package models

import (
	"encoding/csv"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"go-admin/app/admin/apis/pay"
	utils "go-admin/app/admin/models/tools"
	orm "go-admin/common/global"
	"go-admin/logger"
	"go-admin/pkg/jwtauth"
	"go-admin/tools"
	"go-admin/tools/app"
	"go-admin/tools/config"
	"log"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"
)

type MemberType int

const (
	Unknown                         MemberType = iota
	FirstInvite                                // 1-首次邀请
	OpenAnnualGold                             // 2-开通年费黄金
	OpenQuarterGold                            // 3-开通季度黄金
	OpenHalfYearGold                           // 4-开通半年黄金
	OpenAnnualPlatinum                         // 5-开通年费白金
	OpenAnnualBlack                            // 6-开通年费黑金
	RenewAnnualGoldIntervene                   // 7-续费年费黄金（干预）
	RenewAnnualPlatinumIntervene               // 8-续费年费白金（干预）
	RenewAnnualBlackIntervene                  // 9-续费年费黑金（干预）
	RenewAnnualGoldAuto                        // 10-续费年费黄金（自动）
	RenewQuarterGoldAuto                       // 11-续费季度黄金（自动）
	RenewHalfYearGoldAuto                      // 12-续费半年黄金（自动）
	RenewAnnualPlatinumAuto                    // 13-续费年费白金（自动）
	RenewAnnualBlackAuto                       // 14-续费年费黑金（自动）
	UpgradeGoldToPlatinumIntervene             // 15-黄金→白金（干预）
	UpgradeGoldToBlackIntervene                // 16-黄金→黑金（干预）
	UpgradePlatinumToBlackIntervene            // 17-白金→黑金（干预）
	UpgradeGoldToPlatinumAuto                  // 18-黄金→白金（自动）
	UpgradeGoldToBlackAuto                     // 19-黄金→黑金（自动）
	UpgradePlatinumToBlackAuto                 // 20-白金→黑金（自动）
	OpenAnnualPrivilege                        // 21 开通年费尊享会员
	RenewAnnualPrivilegeAuto                   // 22 续费年费尊享会员(自动）
)

const (
	MemberLevelConsumer  = 10 // 普通用户:有开过零售单，留了手机号，但是小程序端未登陆过的，仍然是普通用户
	MemberLevelUser      = 1  // 普通会员:仅进入了小程序且授权过手机号的为会员用户，未开通租卡会员的为“普通会员”
	MemberLevelGold      = 2  // 黄金会员
	MemberLevelPeriod    = 3  // 短期会员
	MemberLevelPlatinum  = 4  // 白金会员
	MemberLevelBlackGold = 5  // 黑金会员
	MemberLevelPrivilege = 6  // 尊享会员
	MemberLevelTest      = 99 // 测试用户
)

const (
	UserTypeConsumer      = 1 // 普通用户
	UserTypeShopAssistant = 2 // 店员
)

const ( // 尊享会员延保状态
	ExtendExpire      = 1 // 已过期
	ExtendWaitActive  = 2 // 待激活
	ExtendEffectivity = 3 // 已激活
)

const ( // 短信记录类型
	SmsTypeRenewCoupon = 1 // 续费优惠提醒
	SmsTypeRenewRemind = 2 // 续费提醒
	SmsTypeReturnCard  = 3 // 还卡提醒
)

// gen:qs
//
//go:generate goqueryset -in user.go
type UserInfo struct {
	Model

	Uid                   uint32      `json:"uid" gorm:"column:uid;unique_index"`               //
	MemberLevel           uint32      `json:"member_level"`                                     // 当前会员等级:10-普通用户 1-普通会员 2-黄金会员 4-白金会员 5-黑金会员
	MemberGenre           uint32      `json:"member_genre"`                                     // 会员类型 200-黄金年费 201-黄金季度 202-黄金半年
	MemberExpire          *time.Time  `json:"member_expire"`                                    // 会员到期时间
	OpenMemberTime        *time.Time  `json:"open_member_time"`                                 // 开通会员时间
	Bond                  uint32      `json:"bond"`                                             // 保证金
	WxName                string      `json:"wxName"`                                           // 昵称
	WxAvatar              string      `json:"wxAvatar"`                                         // 头像
	WxOpenID              string      `json:"wxOpenID"`                                         // 微信openid
	AppOpenID             string      `json:"appOpenID"`                                        //
	WxUnionID             string      `json:"wxUnionID"`                                        // 微信unionId
	Tel                   string      `json:"tel"`                                              // 电话
	Gender                uint8       `json:"gender"`                                           // 性别
	City                  string      `json:"city"`                                             // 城市
	Province              string      `json:"province"`                                         // 省
	Country               string      `json:"country"`                                          // 市
	Deposit               uint32      `json:"deposit"`                                          // 押金
	UserType              uint8       `json:"user_type"`                                        // 用户类型 1-普通用户 2-店员
	XcxRoleId             uint32      `json:"xcx_role_id"`                                      // 角色id
	OpenMemberChannel     string      `json:"open_member_channel" `                             // 开通会员渠道: -门店推广 -用户邀请 -兑换码
	StoreId               uint64      `json:"store_id"`                                         // 门店id
	InviteCodeUrl         string      `json:"invite_code_url"`                                  // 分享二维码
	MemberOpenTime        *time.Time  `json:"member_open_time" gorm:"-"`                        //
	LastLoginAt           *time.Time  `json:"last_login_at"`                                    // 最近登录时间
	IP                    string      `json:"-" gorm:"type:varchar(60)"`                        // ip
	InBlack               bool        `json:"in_black"`                                         // 是否在黑名单
	CooperativeBusinessId uint32      `json:"cooperative_business_id" gorm:"index"`             // 合作商id
	CooperativeName       string      `json:"cooperative_name"`                                 // 合作商名称
	Version               uint32      `json:"-"`                                                //
	MemberStatus          uint8       `json:"member_status" gorm:"-"`                           //
	InviteTime            *time.Time  `json:"invite_time"`                                      //
	OpenMemberLevel       uint32      `json:"open_member_level"`                                // 开通会员级别：10-普通用户 1-普通会员 2-黄金会员 4-白金会员 5-黑金会员
	ShopAssistantName     string      `json:"shop_assistant_name"`                              // 店员名称
	Mark                  int8        `json:"mark"`                                             // 标记
	FirstRetailOrder      *time.Time  `json:"first_retail_order"`                               // 首次零售开单时间
	Store                 *Store      `json:"store" gorm:"-"`                                   //
	OrderCards            []OrderCard `json:"order_cards" gorm:"foreignKey:uid;references:uid"` //
	ForfeitPenalty        int         `json:"forfeit_penalty" gorm:"-"`                         // 滞纳金
	MemberDiscountFlag    int         `json:"member_discount_flag" gorm:"-"`                    // 会员优惠标志：0-不享受会员优惠，1-可享受会员优惠
	//RenewalTime           *time.Time  `json:"renewal_time"`                                     //
	//RenewalMemberLevel    uint32      `json:"renewal_member_level"`                             //
	//MemberLevelString     string      `json:"member_level_string" gorm:"-"`                     // 会员类型
}

func (m *UserInfo) TableName() string {
	return "user"
}

const (
	UNMARK = iota
	MARK
)

const (
	OpenMemberChannelStorePromotion = "store_promotion" // 门店推荐
	OpenMemberChannelUserInvite     = "user_invite"
	OpenMemberChannelRedeemCode     = "redeem_code"
)

const DateTimeFormat = "2006-01-02"
const TimeFormat = "2006-01-02 15-04-05"
const ExcelTimeFormat = "2006-01-02 15:04:05"
const QueryTimeFormat = "2006-01-02T15:04:05+08:00"
const StoreDateTimeFormat = "2006.01.02"

const (
// ExportUrl = "https://admin.deovo.com/load/export/"
// ExportUrl = "https://dev.admin.deovo.com/load/export/" // dev环境
// ExportUrl = "/Users/max/Documents/" // 本地环境
)

type UserInvite struct {
	Model

	FromUid        uint32    `json:"from_uid"`         // 邀请用户id
	UserType       uint8     `json:"user_type"`        // 用户类型
	StoreId        uint64    `json:"store_id"`         // 门店id
	MemberOpenTime time.Time `json:"member_open_time"` // 开通会员
	MemberType     uint8     `json:"member_type"`      // 被邀请用户 1-普通用户 2-会员
	MemberStatus   uint8     `json:"member_status"`    // 被邀请用户 1-未开通  2-已开通 3-已取消会员
	ToUid          uint32    `json:"to_uid"`           // 被邀请用户
	StoreType      uint32    `json:"store_type"`       // 门店类型
	Action         uint32    `json:"action"`           // 2-激活邀请
	SpendType      uint32    `json:"spend_type"`       // 1-开通会员 2-续费 3-升级
	MemberLevel    uint32    `json:"member_level"`     // 会员等级
}

func (m *UserInvite) TableName() string {
	return "user_invite"
}

const (
	DepositRefundStatusUnconfirmed = 1 // 待确认
	DepositRefundStatusConfirmed   = 2 // 已确认
	DepositRefundStatusRefunded    = 3 // 已退款
	DepositRefundStatusRefused     = 4 // 已拒绝
)

// gen:qs
type DepositRefundRecord struct {
	Model

	Uid         uint32    `json:"uid"`
	Status      uint32    `json:"status"` //  unconfirmed confirmed refunded
	Amount      uint32    `json:"amount"`
	Operator    uint32    `json:"operator"` // 操作者
	ConfirmTime time.Time `json:"confirm_time"`
	User        User      `json:"user" gorm:"-"`
}

const (
	//FundTypeMemberGold             = "member_gold"                // 黄金会员
	//FundTypeMemberPlatinum         = "member_platinum"            // 白金会员
	//FundTypeMemberBlackGold        = "member_black_gold"          // 黑金会员
	//FundTypeMemberGoldDeposit      = "member_gold_deposit"        // 黄金会员押金
	//FundTypeMemberPlatinumDeposit  = "member_platinum_deposit"    // 白金会员押金
	//FundTypeMemberBlackGoldDeposit = "member_black_gold_platinum" // 黑金会员押金
	//FundTypeExpressFee             = "express_fee"                // 邮费
	//FundTypeUpgradeMember          = "upgrade_member"             // 升级会员
	//FundTypeMemberExpireDelay      = "member_expire_delay"        // 滞纳金

	FundTypeMemberFee         = "member_fee"          // 会员费
	FundTypeMemberDeposit     = "member_deposit"      // 押金
	FundTypeExpressFee        = "express_fee"         // 邮费
	FundTypeUpgradeMember     = "upgrade_member"      // 升级会员
	FundTypeMemberExpireDelay = "member_expire_delay" // 滞纳金
	FundTypeDepositRefund     = "deposit_refund"      // 退押金
	FundTypeExpressFeeRefund  = "express_fee_refund"  // 退邮费
	FundTypeRecycleCard       = "recycle_card"        // 回收卡带
)

// gen:qs
type FundRecord struct {
	Model
	Uid           uint32 `json:"uid"  gorm:"index"`            //
	FundType      string `json:"fund_type"  gorm:"index"`      // -member_gold   -member_platinum  -member_black_gold
	Amount        int64  `json:"amount"`                       //
	TransactionId string `json:"transaction_id"  gorm:"index"` // 支付单号
	OutTradeNo    string `json:"out_trade_no" gorm:"index"`    //
	RefundId      string `json:"refund_id"  gorm:"index"`      //
	PaymentNo     string `json:"payment_no"  gorm:"index"`     // 付款单号
	Status        uint32 `json:"status"`                       // 1-待支付 2-已支付 3-已退款
	Remark        string `json:"remark"`                       // 备注

	// fund_record
}

type XcxRole struct {
	Model
	RoleName string `json:"role_name" gorm:"size:255;"` // 角色名称
	RoleKey  string `json:"role_key" gorm:"size:255;"`  // 角色代码
	RoleSort int    `json:"role_sort" gorm:""`          // 角色排序
	Status   string `json:"status" gorm:"size:255;"`    // 状态:1-停用 2-正常
	Flag     string `json:"flag" gorm:"size:255;"`      //
	CreateBy string `json:"create_by" gorm:"size:255;"` //
	UpdateBy string `json:"update_by" gorm:"size:255;"` //
	Remark   string `json:"remark" gorm:"size:255;"`    // 备注

	Params  string `json:"params" gorm:"-"`
	MenuIds []int  `json:"menuIds" gorm:"-"`
	DeptIds []int  `json:"deptIds" gorm:"-"`
	// xcx_role
}

const (
	OperationTypeRentCardRevert             = "rent_card_revert"
	OperationTypeRentCardDeliver            = "rent_card_deliver"
	OperationTypeMallOrderRefundSendReceive = "mall_goods_order_refund_receive" // 退货入库
)

// gen:qs
type OperationLog struct {
	Model
	Uid                   uint32 `json:"uid" gorm:"index"` // 店员id
	SysUid                uint32 `json:"sys_uid" gorm:"index"`
	Description           string `json:"description"`                          // 描述
	OperationType         string `json:"operation_type" gorm:"index"`          // 操作类型
	CorrelationId         uint32 `json:"correlation_id" gorm:"index"`          // 关联id
	CorrelationName       string `json:"correlation_name" gorm:"index"`        // 关联name
	StoreId               uint32 `json:"store_id" gorm:"index"`                // 门店id
	StoreName             string `json:"store_name"`                           // 门店名称
	CooperativeName       string `json:"cooperative_name"`                     // 合作商名称
	CooperativeBusinessId uint32 `json:"cooperative_business_id" gorm:"index"` // 合作商id
	SerialNumber          string `json:"serial_number" gorm:"index"`           // 卡编号
	Detail                string `json:"detail"`                               // 详情
	Remark                string `json:"remark"`                               // 备注
}

type U struct {
	UserInfo
	MemberExpireDays uint32  `json:"member_expire_days"` // 会员过期天数
	OrderCount       int     `json:"order_count"`        // 消费次数
	OrderAmount      float64 `json:"order_amount"`       // 消费金额
	Vm               uint32  `json:"vm"`                 // 用户积分
}

type NewUserListReq struct {
	PageIndex       int    `json:"pageIndex"`         // 页码
	PageSize        int    `json:"pageSize"`          // 页面条数
	Uid             int    `json:"uid"`               // 用户id
	Tel             string `json:"tel"`               // 手机号
	StoreId         int    `json:"store_id"`          // 门店id
	UserType        int    `json:"user_type"`         // 用户类型 用户类型 1-普通用户 2-店员
	OpenMemberLevel []int  `json:"open_member_level"` // 首次开通租卡会员等级：2-黄金会员 4-白金会员 5-黑金会员
	MemberLevel     []int  `json:"member_level"`      // 当前会员等级:10-普通用户 1-普通会员 2-黄金会员 4-白金会员 5-黑金会员
	CreateStartTime string `json:"create_startTime"`  // 注册小程序-开始时间
	CreateEndTime   string `json:"create_endTime"`    // 注册小程序-结束时间
	OrderStartTime  string `json:"order_startTime"`   // 首次零售开单-开始时间
	OrderEndTime    string `json:"order_endTime"`     // 首次零售开单-结束时间
	OpenStartTime   string `json:"open_startTime"`    // 首次开通租卡会员-开始时间
	OpenEndTime     string `json:"open_endTime"`      // 首次开通租卡会员-结束时间
	Filter          bool   `json:"filter"`            // 是否过滤无滞纳金已标记用户
	SortField       string `json:"sort_field"`        // 排序字段：滞纳金传"forfeit_penalty"
	SortType        string `json:"sort_type"`         // 排序类型：desc 降序、asc 升序
	IsExport        uint32 `json:"is_export"`         // 1-导出
	IsOrderQuery    uint32 `json:"is_order_query"`    // 1-新建零售订单时查询，不限制门店
}

type NewUserListResp struct {
	List      []U    `json:"list"`       // 用户数据
	Total     int    `json:"total"`      // 总条数
	PageIndex int    `json:"pageIndex"`  // 页码
	PageSize  int    `json:"pageSize"`   // 每页展示条数
	ExportUrl string `json:"export_url"` // 导出excel地址
}

func GetNewUserList(req *NewUserListReq, c *gin.Context) (*NewUserListResp, error) {
	resp := &NewUserListResp{
		PageIndex: req.PageIndex,
		PageSize:  req.PageSize,
	}
	req.PageIndex -= 1
	if req.PageIndex < 0 {
		req.PageIndex = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}

	if req.SortField == "forfeit_penalty" {
		return GetUserListByForfeitPenalty(req)
	}

	users := make([]U, 0)
	if req.SortField == "" {
		req.SortField = "id"
	}
	if req.SortType == "" {
		req.SortType = "DESC"
	}

	qs := orm.Eloquent.Model(&UserInfo{}).Debug()

	if req.IsOrderQuery != 1 { // 不是新建零售订单，需要校验门店权限
		// 非管理员才判断所属门店
		if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
			sysUser, err := GetSysUserByCtx(c)
			if err != nil {
				return nil, err
			}

			var storeList []uint32
			// 返回sysUser未过期的门店id列表
			storeList = GetValidStoreIDs(sysUser.StoreData)
			if req.StoreId != 0 {
				if !Contains(storeList, uint32(req.StoreId)) {
					return nil, errors.New("您没有该门店权限")
				}
			} else {
				if len(storeList) > 0 {
					if len(storeList) == 1 {
						qs = qs.Where("store_id = ?", storeList[0])
					} else {
						qs = qs.Where("store_id IN (?)", storeList)
					}
				} else {
					return nil, errors.New("用户未绑定门店")
				}
			}
		}
	}

	if req.Tel != "" {
		qs = qs.Where("user.tel", req.Tel)
	}
	if req.Uid != 0 {
		qs = qs.Where("user.uid", req.Uid)
	}
	if len(req.OpenMemberLevel) != 0 {
		qs = qs.Where("user.open_member_level in (?)", req.OpenMemberLevel)
	}
	if len(req.MemberLevel) != 0 {
		qs = qs.Where("user.member_level in (?)", req.MemberLevel)
	}
	if req.StoreId != 0 {
		qs = qs.Where("user.store_id", req.StoreId)
	}
	if req.UserType != 0 {
		qs = qs.Where("user.user_type", req.UserType)
	}

	if req.CreateStartTime != "" {
		parse, err := time.Parse(QueryTimeFormat, req.CreateStartTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("user.created_at > ?", parse)
	}
	if req.CreateEndTime != "" {
		parse, err := time.Parse(QueryTimeFormat, req.CreateEndTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("user.created_at < ?", parse)
	}

	if req.OrderStartTime != "" {
		parse, err := time.Parse(QueryTimeFormat, req.OrderStartTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("user.first_retail_order > ?", parse)
	}
	if req.OrderEndTime != "" {
		parse, err := time.Parse(QueryTimeFormat, req.OrderEndTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("user.first_retail_order < ?", parse)
	}

	if req.OpenStartTime != "" {
		parse, err := time.Parse(QueryTimeFormat, req.OpenStartTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("user.open_member_time > ?", parse)
	}
	if req.OpenEndTime != "" {
		parse, err := time.Parse(QueryTimeFormat, req.OpenEndTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("user.open_member_time < ?", parse)
	}

	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return nil, err
	}

	currentTime := time.Now()

	// 子查询，查询消费次数和消费金额
	//subQuery := fmt.Sprintf(`SELECT uid, COUNT(*) as order_count, SUM(amount) as order_amount
	//	FROM fund_record
	//	WHERE fund_type NOT IN ('deposit_refund', 'express_fee_refund', 'member_expire_delay', 'recycle_card')
	//	GROUP BY uid
	//	HAVING COUNT(uid) > 0`)

	subQuery := fmt.Sprintf(`SELECT uid, COUNT(*) as order_count, SUM(total_amount) as order_amount
		FROM erp_order 
		WHERE pay_status = 2
		GROUP BY uid 
		HAVING COUNT(uid) > 0`)

	// 查询用户数据，过期天数，消费次数，消费金额---20240308修改：过期会员等级会自动改成1普通会员，所以这里的范围改成，1，2，3, 4, 5
	qs = qs.Select("user.*, COALESCE(fr.order_count, 0) as order_count, COALESCE(fr.order_amount, 0) as "+
		"order_amount, COALESCE(uv.vm, 0) as vm, CASE WHEN (user.member_level IN (1, 2, 3, 4, 5) AND user.member_expire < ?) "+
		"THEN DATEDIFF(?, user.member_expire) ELSE 0 END AS member_expire_days", currentTime, currentTime).
		Joins(fmt.Sprintf("LEFT JOIN (%s) fr ON user.uid = fr.uid", subQuery)).
		Joins("LEFT JOIN user_vm uv ON user.uid = uv.uid")

	if req.Filter {
		qs = orm.Eloquent.Table("(?) as a", qs)
		qs = qs.Select("a.*").
			Joins("inner join order_card as oc on a.uid=oc.uid").
			Where("pay_status = ? AND card_status IN (?)", HavePaid, []int{1, 2, 3}).
			Group("oc.uid").
			Having("count(oc.uid) > 0")

		qs = qs.Where("member_expire_days > 0").Where("mark = ?", UNMARK)

		err = qs.Find(&users).Error
		if err != nil && err != RecordNotFound {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}

		count = int64(len(users))
		users = nil
	}

	if req.IsExport == 1 { // 导出excel
		err = qs.Order(fmt.Sprintf("%s %s", req.SortField, req.SortType)).Find(&users).Error
		if err != nil && err != RecordNotFound {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
	} else {
		err = qs.Order(fmt.Sprintf("%s %s", req.SortField, req.SortType)).Offset(req.PageIndex * req.PageSize).Limit(req.PageSize).Find(&users).Error
		if err != nil && err != RecordNotFound {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
	}
	resp.Total = int(count)

	//查询卡片
	var uids []uint32
	for _, u := range users {
		if u.MemberExpireDays > 0 {
			uids = append(uids, u.Uid)
		}
	}
	//未归还卡带
	cards, err := GetUserExpiredCards(uids)
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return nil, err
	}

	// 查询门店信息
	storeList := make(map[uint32]Store)
	storeList = GetStoreMap()

	for i, u := range users {
		c, ok := cards[u.Uid]
		if ok {
			users[i].OrderCards = c
			//滞纳金 一个卡带一天2块钱
			users[i].ForfeitPenalty = len(c) * 200 * int(users[i].MemberExpireDays)
		}

		// 添加门店信息
		//users[i].Store, _ = setStore(u.StoreId)
		store := storeList[uint32(u.StoreId)]
		users[i].Store = &store

		// 校验时间，如果为01-01-01 08:05，则赋值为空
		validateZeroTime(&users[i].MemberExpire)
		validateZeroTime(&users[i].OpenMemberTime)
		validateZeroTime(&users[i].MemberOpenTime)
		validateZeroTime(&users[i].LastLoginAt)
		validateZeroTime(&users[i].InviteTime)
		validateZeroTime(&users[i].FirstRetailOrder)
	}

	if req.Uid != 0 && len(users) == 1 { // 只有单个查询用户uid时，才判断是否能够享受会员优惠 add:2024-10-25
		memberDiscountFlag := canEnjoyMemberDiscount(req.Uid)
		if memberDiscountFlag {
			users[0].MemberDiscountFlag = 1
		}
	}

	if req.IsExport == 1 {
		exportFile, err := newUserListExport(users, c)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		resp.ExportUrl = exportFile
	} else {
		resp.List = users
	}

	return resp, nil
}

func canEnjoyMemberDiscount(uid int) bool {
	// 查询user表
	userInfo := new(UserInfo)
	err := orm.Eloquent.Table("user").Where("uid = ?", uid).Find(userInfo).Error
	if err != nil {
		logger.Error("查询 user 表时出错:", logger.Field("err", err))
		return false
	}

	// 检查user表的member_level是否在黄金会员、短期会员、白金会员、黑金会员之间
	if userInfo.MemberLevel == MemberLevelGold ||
		userInfo.MemberLevel == MemberLevelPeriod ||
		userInfo.MemberLevel == MemberLevelPlatinum ||
		userInfo.MemberLevel == MemberLevelBlackGold {
		return true
	}

	// 查询privilege_member表
	privilegeInfo := new(PrivilegeMember)
	err = orm.Eloquent.Table("privilege_member").Where("uid = ?", uid).Find(privilegeInfo).Error
	if err != nil {
		logger.Error("查询 privilege_member 表时出错:", logger.Field("err", err))
		return false
	}

	// 检查privilege_member表的member_level是否为6
	if privilegeInfo.MemberLevel == MemberLevelPrivilege {
		return true
	}

	// 如果不满足条件，则返回false
	return false
}

// GetUserListByForfeitPenalty 滞纳金排序
func GetUserListByForfeitPenalty(req *NewUserListReq) (*NewUserListResp, error) {
	resp := &NewUserListResp{
		PageIndex: req.PageIndex + 1,
		PageSize:  req.PageSize,
	}

	allUsers := make([]U, 0)
	qs := orm.Eloquent.Model(&UserInfo{})

	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return nil, err
	}

	subQuery := fmt.Sprintf(`SELECT uid, COUNT(*) as order_count, SUM(total_amount) as order_amount
		FROM erp_order 
		WHERE pay_status = 2
		GROUP BY uid 
		HAVING COUNT(uid) > 0`)

	currentTime := time.Now()
	// 查询用户数据，过期天数，消费次数，消费金额---20240308修改：过期会员等级会自动改成1普通会员，所以这里的范围改成，1，2，3, 4, 5
	qs = qs.Select("user.*, COALESCE(fr.order_count, 0) as order_count, COALESCE(fr.order_amount, 0) as "+
		"order_amount, COALESCE(uv.vm, 0) as vm, CASE WHEN (user.member_level IN (1, 2, 3, 4, 5) AND user.member_expire < ?) "+
		"THEN DATEDIFF(?, user.member_expire) ELSE 0 END AS member_expire_days", currentTime, currentTime).
		Joins(fmt.Sprintf("LEFT JOIN (%s) fr ON user.uid = fr.uid", subQuery)).
		Joins("LEFT JOIN user_vm uv ON user.uid = uv.uid")

	if req.Filter {
		qs = orm.Eloquent.Table("(?) as a", qs)
		qs = qs.Select("a.*").
			Joins("inner join order_card as oc on a.uid=oc.uid").
			Where("pay_status = ? AND card_status IN (?)", HavePaid, []int{1, 2, 3}).
			Group("oc.uid").
			Having("count(oc.uid) > 0")

		qs = qs.Where("member_expire_days > 0").Where("mark = ?", UNMARK)

		err := qs.Find(&allUsers).Error
		if err != nil && err != RecordNotFound {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}

		count = int64(len(allUsers))
		allUsers = nil
	}

	err = qs.Find(&allUsers).Error
	if err != nil && err != RecordNotFound {
		logger.Errorf("err:", logger.Field("err", err))
		return nil, err
	}

	// Fetch expired cards for users with positive MemberExpireDays
	var uids []uint32
	for _, u := range allUsers {
		if u.MemberExpireDays > 0 {
			uids = append(uids, u.Uid)
		}
	}
	cards, err := GetUserExpiredCards(uids)
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return nil, err
	}

	// 查询门店信息
	storeList := make(map[uint32]Store)
	storeList = GetStoreMap()

	// Calculate forfeit penalty and update user data
	for i, u := range allUsers {
		allUsers[i].OrderCards = cards[u.Uid]
		allUsers[i].ForfeitPenalty = calculateForfeitPenalty(allUsers[i])

		store := storeList[uint32(u.StoreId)]
		allUsers[i].Store = &store

		// Validate and adjust zero time values
		validateZeroTime(&allUsers[i].MemberExpire)
		validateZeroTime(&allUsers[i].OpenMemberTime)
		validateZeroTime(&allUsers[i].MemberOpenTime)
		validateZeroTime(&allUsers[i].LastLoginAt)
		validateZeroTime(&allUsers[i].InviteTime)
		validateZeroTime(&allUsers[i].FirstRetailOrder)
	}

	// Sorting by forfeit penalty
	sort.Slice(allUsers, func(i, j int) bool {
		return allUsers[i].ForfeitPenalty < allUsers[j].ForfeitPenalty
	})
	if req.SortType == "DESC" || req.SortType == "desc" {
		reverseUsers(allUsers)
	}

	// Paginate results
	startIndex := req.PageIndex * req.PageSize
	endIndex := startIndex + req.PageSize
	if endIndex > len(allUsers) {
		endIndex = len(allUsers)
	}

	// Slice the users based on pagination
	pagedUsers := allUsers[startIndex:endIndex]

	resp.Total = len(allUsers)
	resp.List = pagedUsers

	return resp, nil
}

// Function to calculate forfeit penalty for a user
func calculateForfeitPenalty(user U) int {
	return len(user.OrderCards) * 200 * int(user.MemberExpireDays)
}

// Function to reverse a slice of users
func reverseUsers(users []U) {
	for i := len(users)/2 - 1; i >= 0; i-- {
		opp := len(users) - 1 - i
		users[i], users[opp] = users[opp], users[i]
	}
}

// Function to validate and adjust zero time values
func validateZeroTime(t **time.Time) {
	if *t != nil && (*t).IsZero() {
		*t = nil
	}
}

func setStore(storeId uint64) (*Store, error) {
	storeInfo := new(Store)
	err := orm.Eloquent.Table("store").Where("id=?", storeId).Find(storeInfo).Error
	if err != nil && err != RecordNotFound {
		logger.Error("set store err:", logger.Field("err", err))
		return nil, err
	}
	return storeInfo, nil
}

func GetUserList(page, pageSize, uid, memberLevel, storeId, userType, cooperativeBusinessId int, tel, startTime, endTime, nameKey, sortFiled, sortType string, filter bool) ([]U, uint32, uint32, error) {
	var (
		users     = make([]U, 0)
		totalPage uint32
	)
	fmt.Println("tel:", tel)
	fmt.Println("nameKey:", nameKey)

	page -= 1
	if page < 0 {
		page = 0
	}
	if sortFiled == "" {
		sortFiled = "id"
	}
	if sortType == "" {
		sortType = "DESC"
	}
	user := &UserInfo{}
	qs := orm.Eloquent.Table(user.TableName()).Debug()

	if tel != "" {
		qs = qs.Where("tel", tel)
	}
	if uid != 0 {
		qs = qs.Where("uid", uid)
	}
	if memberLevel != 0 {
		qs = qs.Where("member_level", memberLevel)
	}
	if storeId != 0 {
		qs = qs.Where("store_id", storeId)
	}
	if userType != 0 {
		qs = qs.Where("user_type", userType)
	}
	if cooperativeBusinessId != 0 {
		qs = qs.Where("cooperative_business_id=?", cooperativeBusinessId)
	}
	if startTime != "" {
		parse, err := time.Parse(DateTimeFormat, startTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return users, 0, 0, err
		}
		qs = qs.Where("created_at > ?", parse)
	}
	if endTime != "" {
		parse, err := time.Parse(DateTimeFormat, endTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return users, 0, 0, err
		}
		qs = qs.Where("created_at < ?", parse)
	}
	if nameKey != "" {
		qs = qs.Where("wx_name LIKE ?", "%"+nameKey+"%")
	}

	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return users, 0, 0, err
	}

	currentTime := time.Now()

	//计算过期天数
	qs = qs.Select("*, CASE WHEN (member_level IN (2, 4, 5) AND member_expire < ?) THEN DATEDIFF(?,member_expire) ELSE 0 END AS member_expire_days", currentTime, currentTime)

	if filter {

		qs = orm.Eloquent.Table("(?) as a", qs)
		//qs = qs.Preload("OrderCards", func(db *gorm.DB) *gorm.DB {
		//	return db.Where("pay_status = ? AND card_status IN (?)", 2, []int{1, 2, 3}).
		//		Group("uid").
		//		Having("count(uid) > 0")
		//})

		qs = qs.Select("a.*").
			Joins("inner join order_card as oc on a.uid=oc.uid").
			Where("pay_status = ? AND card_status IN (?)", 2, []int{1, 2, 3}).
			Group("oc.uid").
			Having("count(oc.uid) > 0")

		qs = qs.Where("member_expire_days > 0").Where("mark = ?", UNMARK)
	}

	err = qs.Order(fmt.Sprintf("%s %s", sortFiled, sortType)).Offset(page * pageSize).Limit(pageSize).Find(&users).Error
	if err != nil && err != RecordNotFound {
		logger.Errorf("err:", logger.Field("err", err))
		return users, 0, 0, err
	}

	totalPage = uint32(int(count)/pageSize + 1)

	return users, totalPage, uint32(count), nil
}

// 导出所有用户excel
func newUserListExport(list []U, c *gin.Context) (string, error) {
	file := excelize.NewFile()
	fSheet := "Sheet1"

	url := config.ExportConfig.Url
	fileName := time.Now().Format(TimeFormat) + "所有会员" + ".xlsx"
	fmt.Println("url fileName:", url+fileName)

	// 判断是否有权限
	flag1, _ := checkRoleMenu(c, UserInfoListMenu)

	nEndCount := 0
	title := []interface{}{"用户ID"}

	if flag1 { // 手机号
		title = append(title, "手机号")
		nEndCount += 1
	}

	title = append(title, "所属门店", "消费次数", "消费金额", "注册小程序时间", "首次零售开单时间",
		"首次开通租卡会员等级", "当前会员等级", "首次开通租卡会员时间", "租卡会员到期时间", "保证金", "租卡会员过期天数", "滞纳金",
		"未归还卡带名称", "未归还卡带串码")
	for i, _ := range title {
		cell, _ := excelize.CoordinatesToCellName(1+i, 1)
		err := file.SetCellValue(fSheet, cell, title[i])
		if err != nil {
			logger.Error("file set value err:", logger.Field("err", err))
		}
	}

	var row []interface{}
	nExcelStartRow := 0

	// 查询门店信息
	var storeList []Store
	err := orm.Eloquent.Table("store").Find(&storeList).Error
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return "", err
	}
	storeMap := make(map[uint32]string, 0)
	for i, _ := range storeList {
		storeMap[storeList[i].ID] = storeList[i].Name
	}
	fmt.Println("storeMap is:", storeMap[13])

	for i := 0; i < len(list); i++ {
		// 未归还卡带名称和串码
		var cardNames, cardNums []string
		var cardNamesResult, cardNumsResult string
		if list[i].MemberExpireDays > 0 {
			for _, item := range list[i].OrderCards {
				// 未归还卡带名称
				if item.GameCard != nil {
					cardNames = append(cardNames, item.GameCard.Name)
				}
				// 未归还卡带串码
				cardNums = append(cardNums, item.SerialNumber)
			}
			if len(cardNames) != 0 {
				cardNamesResult = strings.Join(cardNames, ",")
			}
			if len(cardNums) != 0 {
				cardNumsResult = strings.Join(cardNums, ",")
			}
		}

		row = []interface{}{
			list[i].Uid, // 用户ID
		}

		if flag1 { // 手机号
			row = append(row, list[i].Tel)
		}

		row = append(row, storeMap[uint32(list[i].StoreId)])                          // 所属门店
		row = append(row, list[i].OrderCount)                                         // 消费次数
		row = append(row, list[i].OrderAmount)                                        // 消费金额
		row = append(row, tools.ConvertTimeToString(list[i].CreatedAt))               // 注册小程序时间
		row = append(row, tools.ConvertTimeToStringByPoint(list[i].FirstRetailOrder)) // 首次零售开单时间
		row = append(row, getMemberLevelChineseDescription(list[i].OpenMemberLevel))  // 首次开通租卡会员等级
		row = append(row, getMemberLevelChineseDescription(list[i].MemberLevel))      // 当前会员等级
		row = append(row, tools.ConvertTimeToStringByPoint(list[i].OpenMemberTime))   // 首次开通租卡会员时间
		row = append(row, tools.ConvertTimeToStringByPoint(list[i].MemberExpire))     // 租卡会员到期时间
		row = append(row, float32(list[i].Deposit)/100)                               // 保证金(数据库存储的是分）
		row = append(row, list[i].MemberExpireDays)                                   // 租卡会员过期天数
		row = append(row, list[i].ForfeitPenalty)                                     // 滞纳金
		row = append(row, cardNamesResult)                                            // 未归还卡带名称
		row = append(row, cardNumsResult)                                             // 未归还卡带串码

		for j, _ := range row {
			cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
			err := file.SetCellValue(fSheet, cell, row[j])
			if err != nil {
				logger.Error("file set value err:", logger.Field("err", err))
			}
		}
		nExcelStartRow++
	}

	// 设置所有单元格的样式: 居中、加边框
	style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
	"border":[{"type":"left","color":"000000","style":1},
	{"type":"top","color":"000000","style":1},
	{"type":"right","color":"000000","style":1},
	{"type":"bottom","color":"000000","style":1}]}`)

	// 设置单元格的样式: 居中、加边框、自动换行
	style1, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center","wrap_text":true},
	"border":[{"type":"left","color":"000000","style":1},
	{"type":"top","color":"000000","style":1},
	{"type":"right","color":"000000","style":1},
	{"type":"bottom","color":"000000","style":1}]}`)

	var endRow string
	switch nEndCount {
	case 1:
		endRow = fmt.Sprintf("P"+"%d", nExcelStartRow+1)
		// 应用样式到整个表格
		file.SetColWidth("Sheet1", "F", "F", 18)
		file.SetColWidth("Sheet1", "G", "G", 18)
		file.SetColWidth("Sheet1", "J", "J", 18)
		file.SetColWidth("Sheet1", "K", "K", 18)
		_ = file.SetCellStyle("Sheet1", "A1", "P1", style1)
	default:
		endRow = fmt.Sprintf("O"+"%d", nExcelStartRow+1)
		// 应用样式到整个表格
		file.SetColWidth("Sheet1", "E", "E", 18)
		file.SetColWidth("Sheet1", "F", "F", 18)
		file.SetColWidth("Sheet1", "I", "I", 18)
		file.SetColWidth("Sheet1", "J", "J", 18)
		_ = file.SetCellStyle("Sheet1", "A1", "O1", style1)
	}

	_ = file.SetCellStyle("Sheet1", "A2", endRow, style)

	fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
	if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
		fmt.Println(err)
	}
	return url + fileName, nil
}

type CommonProblem struct {
	Model

	Question string `json:"question"`
	Answer   string `json:"answer" gorm:"type:text"`
	Sort     uint32 `json:"sort" gorm:"index"`
}

func (*CommonProblem) TableName() string {
	return "common_problem"
}

type GroupSendMessageTemplate struct {
	Model

	Title    string    `json:"title" `
	Message  string    `json:"message"`
	UserType uint32    `json:"user_type" gorm:"index,column:user_type"` // 1-所有用户 2-会员 3-非会员 4-指定用户
	SendTime time.Time `json:"send_time"`
	Tels     string    `json:"tels"`
	Status   uint32    `json:"status"` // 1-待发送 2-已发送
}

func (*GroupSendMessageTemplate) TableName() string {
	return "group_send_message_template"
}

// ExpireMemberSmsSend SmsType：1-会员剩余1个月续费提醒；2-会员剩余7天/4天/0天（且有卡带未归还/游玩中）；3-过期未还卡提醒（最多会发12条，对应天数：1, 2, 3, 4, 5, 6, 7, 14, 21, 28, 60, 90）
type ExpireMemberSmsSend struct {
	Model

	Message  string    `json:"message"`
	SendTime time.Time `json:"send_time"`
	Tel      string    `json:"tel" gorm:"index"`
	Status   uint32    `json:"status"`   // 1-发送成功 2-发送失败
	SmsType  uint32    `json:"sms_type"` // 1-续费优惠；2-续费；3-还卡
}

func GetUserInfoMap(uids []uint32) (map[uint32]UserInfo, error) {
	userInfoMap := make(map[uint32]UserInfo, 0)
	if len(uids) == 0 {
		return userInfoMap, nil
	}
	var userInfos []UserInfo
	err := orm.Eloquent.Table("user").Where("uid in (?)", uids).Find(&userInfos).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return userInfoMap, err
	}

	for i, _ := range userInfos {
		userInfoMap[userInfos[i].Uid] = userInfos[i]
	}
	return userInfoMap, nil
}

func (m *CommonProblem) List() ([]CommonProblem, error) {
	commons := make([]CommonProblem, 0)
	err := orm.Eloquent.Table("common_problem").Order("sort desc").Find(&commons).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return commons, err
	}

	return commons, nil
}

func (m *CommonProblem) Add() error {
	err := orm.Eloquent.Table("common_problem").Create(m).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return err
	}

	return nil
}

func (m *CommonProblem) Modify() error {
	err := orm.Eloquent.Table("common_problem").Save(m).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return err
	}

	return nil
}

func (m *CommonProblem) Del() error {
	err := orm.Eloquent.Table("common_problem").Where("id", m.ID).Delete(m).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return err
	}

	return nil
}

type UserAddress struct {
	Model

	Uid          uint32 `json:"uid" gorm:"index"`
	ReceiverName string `json:"receiver_name"`
	Tel          string `json:"tel" gorm:"type:varchar(20)"`
	Province     string `json:"province" gorm:"type:varchar(100)"`
	City         string `json:"city" gorm:"type:varchar(100)"`
	District     string `json:"district" gorm:"type:varchar(100)"`
	Address      string `json:"address" gorm:"type:varchar(100)"`
	State        uint8  `json:"state"`
	IsDefault    uint8  `json:"is_default"`
}

func (m *UserAddress) TableName() string {
	return `user_address`
}

// gen:qs
//type InviteMemberReport struct {
//	Model
//	Uid                   uint32    `json:"uid" gorm:"index"`
//	StoreId               uint32    `json:"store_id" gorm:"index"`                // 门店id
//	GoldCount             uint32    `json:"gold_count"`                           // 黄金数量
//	PlatinumCount         uint32    `json:"platinum_count"`                       // 白金数量
//	BlackGoldCount        uint32    `json:"black_gold_count"`                     // 黑金数量
//	Date                  string    `json:"date" gorm:"index"`                    // 业绩时间
//	DeductAmount          uint32    `json:"deduct_amount"`                        // 店员提成
//	CooperativeBusinessId uint32    `json:"cooperative_business_id" gorm:"index"` // 合作商id
//	CooperativeName       string    `json:"cooperative_name"`                     // 合作商名称
//	GoldDeduct            uint32    `json:"gold_deduct"`                          // 黄金会员提成
//	PlatinumDeduct        uint32    `json:"platinum_deduct"`                      // 白金会员提成
//	BlackGoldDeduct       uint32    `json:"black_gold_deduct"`                    // 黑金会员提成
//	UserInfo              *UserInfo `json:"user_info" gorm:"-"`                   // 用户
//	Store                 *Store    `json:"store" gorm:"-"`                       // 门店
//	// ReportTime            string `json:"report_time" gorm:"index"`             // 业绩时间
//	// invite_member_report
//}

type InviteMemberReport struct {
	Model
	Uid              uint32 `json:"uid" gorm:"index"`      // 店员uid
	StoreId          uint32 `json:"store_id" gorm:"index"` // 门店id
	GoldCount        uint32 `json:"gold_count"`            // 黄金数量
	GoldCountHalf    uint32 `json:"gold_count_half"`       // 半年黄金数量
	GoldCountQuarter uint32 `json:"gold_count_quarter"`    // 季度黄金数量
	PlatinumCount    uint32 `json:"platinum_count"`        // 白金数量
	BlackGoldCount   uint32 `json:"black_gold_count"`      // 黑金数量
	PrivilegeCount   uint32 `json:"privilege_count"`       // 尊享会员数量
	//ReportTime            string `json:"report_time" gorm:"index"`             // 业绩时间
	Date                              string `json:"date" gorm:"index"`                                       // 业绩时间
	DeductAmount                      uint32 `json:"deduct_amount"`                                           // 店员提成
	CooperativeBusinessId             uint32 `json:"cooperative_business_id" gorm:"index"`                    // 合作商id
	CooperativeName                   string `json:"cooperative_name"`                                        // 合作商名称
	GoldDeduct                        uint32 `json:"gold_deduct"`                                             // 黄金会员提成
	PlatinumDeduct                    uint32 `json:"platinum_deduct"`                                         // 白金会员提成
	BlackGoldDeduct                   uint32 `json:"black_gold_deduct"`                                       // 黑金会员提成
	RenewalGoldCount                  uint32 `json:"renewal_gold_count"`                                      // 续费年度黄金会员数量（自动）
	RenewalGoldCountHalf              uint32 `json:"renewal_gold_count_half"`                                 // 续费半年黄金会员数量（自动）
	RenewalGoldCountQuarter           uint32 `json:"renewal_gold_count_quarter"`                              // 续费季度黄金会员数量（自动）
	RenewalPlatinumCount              uint32 `json:"renewal_platinum_count"`                                  // 续费白金会员数量（自动）
	RenewalBlackGoldCount             uint32 `json:"renewal_black_gold_count"`                                // 续费黑金会员数量（自动）
	RenewalPrivilegeCount             uint32 `json:"renewal_privilege_count"`                                 // 续费尊享会员数量
	UpgradeGoldToPlatinumCount        uint32 `json:"upgrade_gold_to_platinum_count" gorm:"default:0"`         // 升级：黄金->白金数量（自动）
	UpgradeGoldToBlackCount           uint32 `json:"upgrade_gold_to_black_count" gorm:"default:0"`            // 升级：黄金->黑金数量（自动）
	UpgradePlatinumToBlackCount       uint32 `json:"upgrade_platinum_to_black_count" gorm:"default:0"`        // 升级：白金->黑金数量（自动）
	InviteRenewalGoldCount            uint32 `json:"invite_renewal_gold_count"`                               // 续费黄金会员数量（干预）
	InviteRenewalPlatinumCount        uint32 `json:"invite_renewal_platinum_count"`                           // 续费白金会员数量（干预）
	InviteRenewalBlackGoldCount       uint32 `json:"invite_renewal_black_gold_count"`                         // 续费黑金会员数量（干预）
	InviteUpgradeGoldToPlatinumCount  uint32 `json:"invite_upgrade_gold_to_platinum_count" gorm:"default:0"`  // 升级：黄金->白金数量（干预）
	InviteUpgradeGoldToBlackCount     uint32 `json:"invite_upgrade_gold_to_black_count" gorm:"default:0"`     // 升级：黄金->黑金数量（干预）
	InviteUpgradePlatinumToBlackCount uint32 `json:"invite_upgrade_platinum_to_black_count" gorm:"default:0"` // 升级：白金->黑金数量（干预）

	// invite_member_report
	SystemUser *SysUser `json:"system_user" gorm:"-"` // 系统用户
	//User       *UserInfo `json:"user" gorm:"-"`        //
	//Store      *Store    `json:"store" gorm:"-"`       // 门店

}

type UserInviteListReq struct {
	//StoreId uint32 `json:"store_id"` // 门店id
	Uid        uint32 `json:"uid"` // 用户id
	Page       int    `json:"pageIndex"`
	PageSize   int    `json:"pageSize"`
	MemberType int    `json:"memberType"` // 0-全部 1-普通用户 2-会员
	StartTime  string `json:"startTime"`  // 开始时间
	EndTime    string `json:"endTime"`    // 结束时间
}

func (m *UserInfo) InitUserInvite(invite UserInvite) {
	m.MemberOpenTime = &invite.MemberOpenTime
	m.MemberStatus = invite.MemberStatus
	m.InviteTime = &invite.CreatedAt
	m.MemberLevel = invite.MemberLevel
}

func (m *UserInviteListReq) InviteList() ([]UserInfo, int, error) {
	var (
		users     = make([]UserInfo, 0)
		totalPage uint32
		page      = m.Page - 1
		pageSize  = m.PageSize
	)

	if page < 0 {
		page = 0
	}
	if pageSize == 0 {
		pageSize = 10
	}

	//user := &UserInfo{}
	//UserInvite{}
	var userInvites []UserInvite
	qs := orm.Eloquent.Table("user_invite").Where("from_uid", m.Uid)

	if m.MemberType != 0 {
		qs = qs.Where("member_type=?", m.MemberType)
	}

	if m.StartTime != "" {
		parse, err := time.Parse(DateTimeFormat, m.StartTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return users, 0, err
		}
		if m.MemberType == 2 {
			qs = qs.Where("member_open_time > ?", parse)
		} else {
			qs = qs.Where("created_at > ?", parse)
		}
	}
	if m.EndTime != "" {
		parse, err := time.Parse(DateTimeFormat, m.EndTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return users, 0, err
		}
		parse = parse.AddDate(0, 0, 1)
		if m.MemberType == 2 {
			qs = qs.Where("member_open_time < ?", parse)
		} else {
			qs = qs.Where("created_at < ?", parse)
		}
	}

	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return users, 0, err
	}

	err = qs.Order("id DESC").Offset(page * pageSize).Limit(pageSize).Find(&userInvites).Error
	if err != nil && err != RecordNotFound {
		logger.Errorf("err:", logger.Field("err", err))
		return users, 0, err
	}

	totalPage = uint32(int(count)/pageSize + 1)

	uids := make([]uint32, 0)
	userInviteMap := make(map[uint32]UserInvite, 0)
	for i, _ := range userInvites {
		uids = append(uids, userInvites[i].ToUid)
		userInviteMap[userInvites[i].ToUid] = userInvites[i]
	}

	err = orm.Eloquent.Table("user").Debug().Where("uid in (?)", uids).Find(&users).Error
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return users, 0, err
	}
	fmt.Println("totalPage", totalPage)
	userMap := make(map[uint32]UserInfo, 0)
	for i, _ := range users {
		userMap[users[i].Uid] = users[i]
	}

	list := make([]UserInfo, 0, len(users))
	for i, _ := range uids {
		invite, ok1 := userInviteMap[uids[i]]
		if !ok1 {
			continue
		}
		userInfo, ok2 := userMap[uids[i]]
		if !ok2 {
			continue
		}
		userInfo.InitUserInvite(invite)
		list = append(list, userInfo)
	}

	return list, int(count), nil
}

type UserInviteMember struct {
	FromUserInfo UserInfo
	ToUserInfo   UserInfo
	Store        Store
	UserInvite
	UserInviteRecord UserInviteRecord
}

func MemberLevelToString(memberLevel uint32) string {
	switch memberLevel {
	case 2:
		return "黄金会员"
	case 4:
		return "白金会员"
	case 5:
		return "黑金会员"
	}

	return ""
}

func ExportUserMember(storeId uint32, startTime, endTime string) string {
	var userInvites []UserInvite
	qs := orm.Eloquent.Table("invite")

	if storeId != 0 {
		qs = qs.Where("store_id", storeId)
	}
	if startTime != "" {
		parse, err := time.Parse(DateTimeFormat, startTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return ""
		}
		qs = qs.Where("member_open_time > ?", parse)
	}
	if endTime != "" {
		parse, err := time.Parse(DateTimeFormat, endTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return ""
		}
		parse = parse.AddDate(0, 0, 1)
		qs = qs.Where("member_open_time < ?", parse)
	}

	err := qs.Order("id DESC,store_id DESC,from_uid DESC").Find(&userInvites).Error
	if err != nil && err != RecordNotFound {
		logger.Errorf("err:", logger.Field("err", err))
		return ""
	}

	storeIds := make([]uint64, 0)
	fromUids := make([]uint32, 0)
	toUids := make([]uint32, 0)
	for i, _ := range userInvites {
		storeIds = append(storeIds, userInvites[i].StoreId)
		fromUids = append(fromUids, userInvites[i].FromUid)
		toUids = append(toUids, userInvites[i].ToUid)
	}

	var stores []Store
	err = orm.Eloquent.Table("store").Where("id in (?)", storeIds).Find(&stores).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return ""
	}
	storeMap := make(map[uint32]Store)
	for i, _ := range stores {
		storeMap[stores[i].ID] = stores[i]
	}

	fromUids = append(fromUids, toUids...)
	var userInfos []UserInfo
	err = orm.Eloquent.Table("user").Where("uid in (?)", fromUids).Find(&userInfos).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return ""
	}
	userInfoMap := make(map[uint32]UserInfo, 0)
	for i, _ := range userInfos {
		userInfoMap[userInfos[i].Uid] = userInfos[i]
	}

	inviteMembers := make([]UserInviteMember, 0, len(userInvites))
	for i, _ := range userInvites {
		fromUser, _ := userInfoMap[userInvites[i].FromUid]
		toUser, ok2 := userInfoMap[userInvites[i].ToUid]
		if !ok2 {
			continue
		}
		store, ok1 := storeMap[uint32(userInvites[i].StoreId)]
		if !ok1 {
			store = storeMap[uint32(toUser.StoreId)]
		}
		invite := UserInviteMember{
			FromUserInfo: fromUser,
			Store:        store,
			ToUserInfo:   toUser,
			UserInvite:   userInvites[i],
		}
		inviteMembers = append(inviteMembers, invite)
	}

	fileName := "邀请会员"
	if storeId == 0 {
		fileName = "全部门店邀请会员"
	} else {
		if len(stores) > 0 {
			fileName = stores[0].Name
		}
	}
	//url := "http://switch.deovo.com:8000/img/export/"
	//url := "http://39.108.188.218:8000/img/export/"

	//fileName = fileName + time.Now().Format("2006-01-02 15:04:05") + ".csv"
	//f, err := os.OpenFile(fmt.Sprintf("./")+fileName, os.O_CREATE|os.O_TRUNC|os.O_APPEND|os.O_RDWR, 0644)
	f, err := os.OpenFile(fmt.Sprintf("/www/server/images/export/")+fileName, os.O_CREATE|os.O_TRUNC|os.O_APPEND|os.O_RDWR, 0644)
	if err != nil {
		fmt.Println(err)
		return fileName
	}
	defer f.Close()

	w := csv.NewWriter(f)

	//headline := []string{"门店名称", "店员id", "店员昵称","姓名", "会员id", "会员昵称", "注册会员时间", "会员状态"}
	headline := []string{"门店名称", "店员id", "姓名", "会员id", "会员昵称", "会员等级", "会员手机号", "注册会员时间", "会员状态"}
	if err := w.Write(headline); err != nil {
		log.Fatalln("error writing record to csv:", logger.Field("err", err))
	}

	for _, invite := range inviteMembers {
		//fmt.Println("MemberOpenTime",invite.UserInvite.MemberOpenTime)
		//fmt.Println("MemberOpenTime",invite.UserInvite.MemberOpenTime.Format("2006-01-02 15:04:05"))
		record := []string{invite.Store.Name, fmt.Sprintf("%d", invite.FromUserInfo.Uid), invite.FromUserInfo.ShopAssistantName,
			fmt.Sprintf("%d", invite.ToUserInfo.Uid), invite.ToUserInfo.WxName, MemberLevelToString(invite.UserInvite.MemberLevel),
			invite.ToUserInfo.Tel, invite.UserInvite.MemberOpenTime.Format("2006-01-02 15:04:05"),
			GetUserInviteStatus(invite.MemberStatus)}
		if err := w.Write(record); err != nil {
			log.Fatalln("error writing record to csv:", logger.Field("err", err))
		}
	}

	w.Flush()
	if err := w.Error(); err != nil {
		log.Fatal(err)
	}

	return config.ExportConfig.Url + fileName
}

// gen:qs
type UserInviteRecord struct {
	Model

	ToUid             uint32    `json:"to_uid"`                       // 用户ID
	FromUid           uint32    `json:"from_uid"`                     // 邀请人ID
	StoreId           uint64    `json:"store_id"`                     // 门店id            邀请用户门店
	Action            uint32    `json:"action"`                       // 1-未激活 2-激活邀请
	SpendType         uint32    `json:"spend_type"`                   // 1-未开通 2-开通会员 3-续费 4-升级
	MemberLevel       uint32    `json:"member_level"`                 // 会员等级 0-未开通 1-普通 2-黄金 3-短期 4-白金 5-黑金 6-尊享会员
	MemberGenre       uint32    `json:"member_genre"`                 // 会员类型 200-黄金年费 201-黄金季度 202-黄金半年
	First             uint32    `json:"first"`                        // 首次
	Scan              uint32    `json:"scan"`                         // 扫码
	ActionTime        time.Time `json:"action_time"`                  // 激活时间
	RenewHide         uint32    `json:"renew_hide"`                   // 自动续费 1-自动 0-干预
	ShopAssistantName string    `json:"shop_assistant_name" gorm:"-"` // 店员名称
	// user_invite_record
}

type UserInviteRecordReq struct {
	PageNum    int       `json:"pageIndex"`
	PageSize   int       `json:"pageSize"`
	MemberType int       `json:"member_type"` // 1-首次邀请 2-开通黄金 3-开通白金 4-开通黑金 5-续费黄金 6-续费白金 7-续费黑金
	FromUid    uint32    `json:"from_uid"`
	ToUid      uint32    `json:"to_uid"`
	StartTime  time.Time `json:"startTime"` // 开始时间
	EndTime    time.Time `json:"endTime"`   // 结束时间
}

func (m *UserInviteRecordReq) List() ([]UserInviteRecord, int64, error) {
	var records []UserInviteRecord
	err := UpdateUserInviteRecordRenewHide()
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return records, 0, err
	}

	page := m.PageNum - 1
	pageSize := m.PageSize

	if page < 0 {
		page = 0
	}
	if pageSize == 0 {
		pageSize = 10
	}

	qs := orm.Eloquent.Table("user_invite_record").Where("action=2").Where("renew_hide!=1")
	//qs := orm.Eloquent.Table("user_invite_record")

	if m.MemberType != 0 {
		switch m.MemberType {
		case 1: // 首次邀请
			qs = qs.Where("first=1").Where("spend_type=1")
		case 2: // 开通年费黄金
			qs = qs.Where("member_level=2").Where("spend_type=2")
		case 3: // 开通年费白金
			qs = qs.Where("member_level=4").Where("spend_type=2")
		case 4: // 开通年费黑金
			qs = qs.Where("member_level=5").Where("spend_type=2")
		case 5: // 续费年费黄金
			qs = qs.Where("member_level=2").Where("spend_type=3")
		case 6: // 续费年费白金
			qs = qs.Where("member_level=4").Where("spend_type=3")
		case 7: // 续费年费黑金
			qs = qs.Where("member_level=5").Where("spend_type=3")
		}
	}
	if m.FromUid != 0 {
		qs = qs.Where("from_uid=?", m.FromUid)
	}
	if m.ToUid != 0 {
		qs = qs.Where("to_uid=?", m.ToUid)
	}
	if !m.StartTime.IsZero() {
		//qs = qs.Where("created_at > ?", m.StartTime)
		qs = qs.Where("action_time > ?", m.StartTime)
	}
	if !m.EndTime.IsZero() {
		//qs = qs.Where("created_at < ?", m.EndTime)
		qs = qs.Where("action_time < ?", m.EndTime)
	}

	var count int64
	err = qs.Count(&count).Error
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return records, 0, err
	}

	err = qs.Order("action_time DESC").Offset(page * pageSize).Limit(pageSize).Find(&records).Error
	if err != nil && err != RecordNotFound {
		logger.Errorf("err:", logger.Field("err", err))
		return records, 0, err
	}
	return records, count, nil
}

type NewUserInviteRecordReq struct {
	PageNum         int       `json:"pageIndex"`
	PageSize        int       `json:"pageSize"`
	StoreId         uint32    `json:"store_id"`          // 邀请人所属门店id
	InviteUserName  string    `json:"invite_user_name"`  // 邀请人昵称
	FromUid         uint32    `json:"from_uid"`          // 邀请人ID
	ToUid           uint32    `json:"to_uid"`            // 用户ID
	UserTel         string    `json:"user_tel"`          // 用户手机号
	CreateStartTime time.Time `json:"create_start_time"` // 注册小程序时间-开始时间
	CreateEndTime   time.Time `json:"create_end_time"`   // 注册小程序时间-结束时间
	RecordType      []uint32  `json:"record_type"`       // 记录类型 1-首次邀请，2-开通年费黄金，3-开通季度黄金，4-开通半年黄金， 5-开通年费白金，6-开通年费黑金，7-续费年费黄金（干预），8-续费年费白金（干预），9-续费年费黑金（干预），10-续费年费黄金（自动）， 11-续费季度黄金（自动），12-续费半年黄金（自动），13-续费年费白金（自动），14-续费年费黑金（自动），15-黄金→白金（干预）， 16-黄金→黑金（干预），17-白金→黑金（干预），18-黄金→白金（自动），19-黄金→黑金（自动），20-白金→黑金（自动），21-开通尊享会员， 22-续费尊享会员
	RecordStartTime time.Time `json:"record_start_time"` // 记录时间-开始时间
	RecordEndTime   time.Time `json:"record_end_time"`   // 记录时间-结束时间
	MemberLevel     uint32    `json:"member_level"`      // 当前类型：10-普通用户 1-普通会员 2-黄金会员 4-白金会员 5-黑金会员
	IsExport        uint32    `json:"is_export"`         // 1-导出
}

type UserInviteRecordListResp struct {
	List      []UserInviteRecordListData `json:"list"`
	Total     int64                      `json:"total"`      // 总条数
	PageIndex int                        `json:"pageIndex"`  // 页码
	PageSize  int                        `json:"pageSize"`   // 每页展示条数
	ExportUrl string                     `json:"export_url"` // 导出excel地址
}

type UserInviteRecordListData struct {
	StoreId               uint32    `json:"store_id"`               // 邀请人所属门店id
	StoreName             string    `json:"store_name"`             // 邀请人所属门店名称
	InviteUserName        string    `json:"invite_user_name"`       // 邀请人昵称
	InviteUid             uint32    `json:"invite_uid"`             // 邀请人ID
	UserUid               uint32    `json:"user_uid"`               // 用户ID
	UserTel               string    `json:"user_tel"`               // 用户手机号
	CreateTime            time.Time `json:"create_time"`            // 注册小程序时间
	RecordType            uint32    `json:"record_type"`            // 记录类型
	RecordTime            time.Time `json:"record_time"`            // 记录时间
	MemberLevel           uint32    `json:"member_level"`           // 当前租卡会员类型：1-普通 2-黄金 4-白金 5-黑金
	MemberExpire          time.Time `json:"memberExpire"`           // 租卡会员到期时间
	PrivilegeMemberLevel  uint32    `json:"privilege_member_level"` // 当前尊享会员类型：1-普通 6-尊享会员
	PrivilegeMemberExpire time.Time `json:"privilege_memberExpire"` // 尊享会员到期时间
}

func (m *NewUserInviteRecordReq) NewList(c *gin.Context) (*UserInviteRecordListResp, error) {
	resp := new(UserInviteRecordListResp)
	var records []struct {
		UserInviteRecord
		StoreId               uint32
		InviteUserName        string
		UserTel               string
		CreateTime            time.Time
		MemberExpire          time.Time
		UserMemberLevel       uint32
		PrivilegeMemberExpire time.Time
		PrivilegeMemberLevel  uint32
	}
	err := UpdateUserInviteRecordRenewHide()
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return nil, err
	}

	// 查询门店信息
	var storeList []Store
	err = orm.Eloquent.Table("store").Find(&storeList).Error
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return nil, err
	}
	storeMap := make(map[uint32]string, 0)
	for i, _ := range storeList {
		storeMap[storeList[i].ID] = storeList[i].Name
	}
	fmt.Println("storeMap is:", storeMap[13])

	page := m.PageNum - 1
	pageSize := m.PageSize

	if page < 0 {
		page = 0
	}
	if pageSize == 0 {
		pageSize = 10
	}

	qs := orm.Eloquent.Table("user_invite_record").Where("action=2")
	countQuery := orm.Eloquent.Table("user_invite_record").Where("action=2").
		Select("user_invite_record.*, " +
			"COALESCE(SU.nick_name, U.shop_assistant_name) AS InviteUserName, " +
			"B2.tel AS UserTel, B2.created_at AS CreateTime, B2.member_expire AS MemberExpire, B2.member_level AS UserMemberLevel, " +
			"B3.member_expire AS PrivilegeMemberExpire, B3.member_level AS PrivilegeMemberLevel").
		Joins("LEFT JOIN sys_user SU ON user_invite_record.from_uid = SU.uid AND SU.uid != 0").
		Joins("LEFT JOIN user U ON user_invite_record.from_uid = U.uid AND SU.uid IS NULL"). // 仅在 sys_user 为空时使用 user
		Joins("LEFT JOIN user B2 ON user_invite_record.to_uid = B2.uid").
		Joins("LEFT JOIN privilege_member B3 ON user_invite_record.to_uid = B3.uid").
		Group("user_invite_record.id").
		Order("MAX(user_invite_record.action_time) DESC")

	// 非管理员才判断所属门店
	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		sysUser, err := GetSysUserByCtx(c)
		if err != nil {
			return nil, err
		}

		// 返回sysUser未过期的门店id列表
		validStoreList := GetValidStoreIDs(sysUser.StoreData)
		if m.StoreId != 0 {
			if !Contains(validStoreList, m.StoreId) {
				return nil, errors.New("您没有该门店权限")
			}
		} else {
			if len(validStoreList) > 0 {
				if len(validStoreList) == 1 {
					qs = qs.Where("user_invite_record.store_id = ?", validStoreList[0])
					countQuery = countQuery.Where("user_invite_record.store_id = ?", validStoreList[0])
				} else {
					qs = qs.Where("user_invite_record.store_id IN (?)", validStoreList)
					countQuery = countQuery.Where("user_invite_record.store_id IN (?)", validStoreList)
				}
			} else {
				return nil, errors.New("用户未绑定门店")
			}
		}
	}

	if m.StoreId != 0 {
		qs = qs.Where("user_invite_record.store_id=?", m.StoreId)
		countQuery = countQuery.Where("user_invite_record.store_id=?", m.StoreId)
	}
	if m.InviteUserName != "" {
		qs = qs.Where("B1.shop_assistant_name=?", m.InviteUserName)
		countQuery = countQuery.Where("B1.shop_assistant_name=?", m.InviteUserName)
	}
	if m.FromUid != 0 {
		qs = qs.Where("user_invite_record.from_uid=?", m.FromUid)
		countQuery = countQuery.Where("user_invite_record.from_uid=?", m.FromUid)
	}
	if m.ToUid != 0 {
		qs = qs.Where("user_invite_record.to_uid=?", m.ToUid)
		countQuery = countQuery.Where("user_invite_record.to_uid=?", m.ToUid)
	}
	if m.UserTel != "" {
		qs = qs.Where("B2.tel=?", m.UserTel)
		countQuery = countQuery.Where("B2.tel=?", m.UserTel)
	}
	if !m.CreateStartTime.IsZero() {
		qs = qs.Where("B2.created_at > ?", m.CreateStartTime)
		countQuery = countQuery.Where("B2.created_at > ?", m.CreateStartTime)
	}
	if !m.CreateEndTime.IsZero() {
		qs = qs.Where("B2.created_at < ?", m.CreateEndTime)
		countQuery = countQuery.Where("B2.created_at < ?", m.CreateEndTime)
	}

	if len(m.RecordType) != 0 {
		var recordTypeConditions []string
		for _, t := range m.RecordType {
			switch t {
			case 1: // 首次邀请
				recordTypeConditions = append(recordTypeConditions, "(first=1 AND spend_type=1)")
			case 2: // 开通年费黄金
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=2 AND spend_type=2)")
			case 3: // 开通季度黄金
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=2 AND spend_type=2 AND user_invite_record.member_genre=201)")
			case 4: // 开通半年黄金
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=2 AND spend_type=2 AND user_invite_record.member_genre=202)")
			case 5: // 开通年费白金
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=4 AND spend_type=2)")
			case 6: // 开通年费黑金
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=5 AND spend_type=2)")

			case 7: // 续费年费黄金（干预）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=2 AND spend_type=3 AND renew_hide=0)")
			case 8: // 续费年费白金（干预）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=4 AND spend_type=3 AND renew_hide=0)")
			case 9: // 续费年费黑金（干预）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=5 AND spend_type=3 AND renew_hide=0)")

			case 10: // 续费年费黄金（自动）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=2 AND spend_type=3 AND renew_hide=1)")
			case 11: // 续费季度黄金（自动）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=2 AND spend_type=3 AND renew_hide=1 AND user_invite_record.member_genre=201)")
			case 12: // 续费半年黄金（自动）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=2 AND spend_type=3 AND renew_hide=1 AND user_invite_record.member_genre=202)")
			case 13: // 续费年费白金（自动）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=4 AND spend_type=3 AND renew_hide=1)")
			case 14: // 续费年费黑金（自动）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=5 AND spend_type=3 AND renew_hide=1)")

			case 15: // 黄金→白金（干预）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=4 AND spend_type=4 AND renew_hide=0)")
			case 16: // 黄金→黑金（干预）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=5 AND spend_type=4 AND renew_hide=0 AND user_invite_record.member_genre in (200,201,202))")
			case 17: // 白金→黑金（干预）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=5 AND spend_type=4 AND renew_hide=0 AND user_invite_record.member_genre not in (200,201,202))")

			case 18: // 黄金→白金（自动）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=4 AND spend_type=4 AND renew_hide=1)")
			case 19: // 黄金→黑金（自动）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=5 AND spend_type=4 AND renew_hide=1 AND user_invite_record.member_genre in (200,201,202))")
			case 20: // 白金→黑金（自动）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=5 AND spend_type=4 AND renew_hide=1 AND user_invite_record.member_genre not in (200,201,202))")

			case 21: // 开通年费尊享会员
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=6 AND spend_type=2)")
			case 22: // 续费年费尊享会员（自动）
				recordTypeConditions = append(recordTypeConditions, "(user_invite_record.member_level=6 AND spend_type=3 AND renew_hide=1)")
			}
		}

		// 拼接多选条件
		if len(recordTypeConditions) > 0 {
			recordTypeQuery := strings.Join(recordTypeConditions, " OR ")
			qs = qs.Where(recordTypeQuery)
			countQuery = countQuery.Where(recordTypeQuery)
		}
	}

	if !m.RecordStartTime.IsZero() {
		qs = qs.Where("user_invite_record.action_time > ?", m.RecordStartTime)
		countQuery = countQuery.Where("user_invite_record.action_time > ?", m.RecordStartTime)
	}
	if !m.RecordEndTime.IsZero() {
		qs = qs.Where("user_invite_record.action_time < ?", m.RecordEndTime)
		countQuery = countQuery.Where("user_invite_record.action_time < ?", m.RecordEndTime)
	}
	if m.MemberLevel != 0 {
		qs = qs.Where("B2.member_level = ?", m.MemberLevel)
		countQuery = countQuery.Where("B2.member_level = ?", m.MemberLevel)
	}

	var count int64
	err = countQuery.Count(&count).Error
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return nil, err
	}

	if m.IsExport == 1 { // 导出excel
		err = qs.Select("user_invite_record.*, " +
			"COALESCE(SU.nick_name, U.shop_assistant_name) AS InviteUserName, " +
			"B2.tel AS UserTel, B2.created_at AS CreateTime, B2.member_expire AS MemberExpire, B2.member_level AS UserMemberLevel, " +
			"B3.member_expire AS PrivilegeMemberExpire, B3.member_level AS PrivilegeMemberLevel").
			Joins("LEFT JOIN sys_user SU ON user_invite_record.from_uid = SU.uid AND SU.uid != 0").
			Joins("LEFT JOIN user U ON user_invite_record.from_uid = U.uid AND SU.uid IS NULL"). // 仅在 sys_user 为空时使用 user
			Joins("LEFT JOIN user B2 ON user_invite_record.to_uid = B2.uid").
			Joins("LEFT JOIN privilege_member B3 ON user_invite_record.to_uid = B3.uid").
			Group("user_invite_record.id").
			Order("MAX(user_invite_record.action_time) DESC").
			Find(&records).Error
		if err != nil && err != RecordNotFound {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
	} else {
		err = qs.Select("user_invite_record.*, " +
			"COALESCE(SU.nick_name, U.shop_assistant_name) AS InviteUserName, " +
			"B2.tel AS UserTel, B2.created_at AS CreateTime, B2.member_expire AS MemberExpire, B2.member_level AS UserMemberLevel, " +
			"B3.member_expire AS PrivilegeMemberExpire, B3.member_level AS PrivilegeMemberLevel").
			Joins("LEFT JOIN sys_user SU ON user_invite_record.from_uid = SU.uid AND SU.uid != 0").
			Joins("LEFT JOIN user U ON user_invite_record.from_uid = U.uid AND SU.uid IS NULL"). // 仅在 sys_user 为空时使用 user
			Joins("LEFT JOIN user B2 ON user_invite_record.to_uid = B2.uid").
			Joins("LEFT JOIN privilege_member B3 ON user_invite_record.to_uid = B3.uid").
			Group("user_invite_record.id").
			Order("MAX(user_invite_record.action_time) DESC").
			Offset(page * pageSize).
			Limit(pageSize).
			Find(&records).Error
		if err != nil && err != RecordNotFound {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
	}

	var listData []UserInviteRecordListData
	for _, item := range records {
		data := UserInviteRecordListData{
			StoreId:               item.StoreId,
			StoreName:             storeMap[item.StoreId],
			InviteUserName:        item.InviteUserName,
			InviteUid:             item.FromUid,
			UserUid:               item.ToUid,
			UserTel:               item.UserTel,
			CreateTime:            item.CreateTime,
			RecordType:            uint32(CalculateMemberType(item.SpendType, item.RenewHide, item.MemberGenre, item.MemberLevel)),
			RecordTime:            item.ActionTime,
			MemberLevel:           item.UserMemberLevel,
			MemberExpire:          item.MemberExpire,
			PrivilegeMemberLevel:  item.PrivilegeMemberLevel,
			PrivilegeMemberExpire: item.PrivilegeMemberExpire,
		}

		if item.FromUid == 0 {
			data.InviteUserName = ""
		}

		listData = append(listData, data)
	}

	if m.IsExport == 1 {
		fileName, err := userInviteRecordExport(listData, c)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		resp.ExportUrl = fileName
	} else {
		resp.List = listData
		resp.PageIndex = m.PageNum
		resp.PageSize = m.PageSize
		resp.Total = count
	}

	return resp, nil
}

// getMemberTypeChineseDescription 根据整数参数返回对应中文描述
func getMemberTypeChineseDescription(memberType MemberType) string {
	switch memberType {
	case FirstInvite:
		return "首次邀请"
	case OpenAnnualGold:
		return "开通年费黄金"
	case OpenQuarterGold:
		return "开通季度黄金"
	case OpenHalfYearGold:
		return "开通半年黄金"
	case OpenAnnualPlatinum:
		return "开通年费白金"
	case OpenAnnualBlack:
		return "开通年费黑金"
	case RenewAnnualGoldIntervene:
		return "续费年费黄金（干预）"
	case RenewAnnualPlatinumIntervene:
		return "续费年费白金（干预）"
	case RenewAnnualBlackIntervene:
		return "续费年费黑金（干预）"
	case RenewAnnualGoldAuto:
		return "续费年费黄金（自动）"
	case RenewQuarterGoldAuto:
		return "续费季度黄金（自动）"
	case RenewHalfYearGoldAuto:
		return "续费半年黄金（自动）"
	case RenewAnnualPlatinumAuto:
		return "续费年费白金（自动）"
	case RenewAnnualBlackAuto:
		return "续费年费黑金（自动）"
	case UpgradeGoldToPlatinumIntervene:
		return "黄金→白金（干预）"
	case UpgradeGoldToBlackIntervene:
		return "黄金→黑金（干预）"
	case UpgradePlatinumToBlackIntervene:
		return "白金→黑金（干预）"
	case UpgradeGoldToPlatinumAuto:
		return "黄金→白金（自动）"
	case UpgradeGoldToBlackAuto:
		return "黄金→黑金（自动）"
	case UpgradePlatinumToBlackAuto:
		return "白金→黑金（自动）"
	case OpenAnnualPrivilege:
		return "开通尊享会员"
	case RenewAnnualPrivilegeAuto:
		return "续费尊享会员"
	default:
		return ""
	}
}

// getMemberLevelChineseDescription 根据整数参数返回对应中文描述
func getMemberLevelChineseDescription(memberLevel uint32) string {
	switch memberLevel {
	case 1:
		return "普通会员"
	case 2, 3:
		return "黄金会员"
	case 4:
		return "白金会员"
	case 5:
		return "黑金会员"
	case 6:
		return "尊享会员"
	}

	return ""
}

// 导出会员邀请记录excel
func userInviteRecordExport(list []UserInviteRecordListData, c *gin.Context) (string, error) {
	file := excelize.NewFile()
	fSheet := "Sheet1"

	url := config.ExportConfig.Url
	fileName := time.Now().Format(TimeFormat) + "会员邀请记录" + ".xlsx"
	fmt.Println("url fileName:", url+fileName)

	// 判断是否有权限
	flag1, _ := checkRoleMenu(c, InviteRecordListMenu)

	nEndCount := 0
	title := []interface{}{"邀请人所属门店", "邀请人昵称", "邀请人ID", "用户ID"}
	if flag1 { // 手机号
		title = append(title, "手机号")
		nEndCount += 1
	}
	title = append(title, "注册小程序时间", "记录类型", "记录时间", "当前类型", "租卡会员到期时间")

	for i, _ := range title {
		cell, _ := excelize.CoordinatesToCellName(1+i, 1)
		err := file.SetCellValue(fSheet, cell, title[i])
		if err != nil {
			logger.Error("file set value err:", logger.Field("err", err))
		}
	}

	var row []interface{}
	nExcelStartRow := 0

	for i := 0; i < len(list); i++ {
		row = []interface{}{
			list[i].StoreName,      // 邀请人所属门店
			list[i].InviteUserName, // 邀请人昵称
			list[i].InviteUid,      // 邀请人ID
			list[i].UserUid,        // 用户ID
		}

		// 控制是否导出
		if flag1 { // 手机号
			row = append(row, list[i].UserTel)
		}

		row = append(row, tools.ConvertTimeToString(list[i].CreateTime))                   // 注册小程序时间
		row = append(row, getMemberTypeChineseDescription(MemberType(list[i].RecordType))) // 记录类型
		row = append(row, tools.ConvertTimeToString(list[i].RecordTime))                   // 记录时间
		row = append(row, getMemberLevelChineseDescription(list[i].MemberLevel))           // 当前类型
		row = append(row, tools.ConvertTimeToString(list[i].MemberExpire))                 // 租卡会员到期时间

		for j, _ := range row {
			cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
			err := file.SetCellValue(fSheet, cell, row[j])
			if err != nil {
				logger.Error("file set value err:", logger.Field("err", err))
			}
		}
		nExcelStartRow++
	}

	// 设置所有单元格的样式: 居中、加边框
	style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
	"border":[{"type":"left","color":"000000","style":1},
	{"type":"top","color":"000000","style":1},
	{"type":"right","color":"000000","style":1},
	{"type":"bottom","color":"000000","style":1}]}`)

	// 设置单元格的样式: 居中、加边框、自动换行
	style1, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center","wrap_text":true},
	"border":[{"type":"left","color":"000000","style":1},
	{"type":"top","color":"000000","style":1},
	{"type":"right","color":"000000","style":1},
	{"type":"bottom","color":"000000","style":1}]}`)

	var endRow string
	switch nEndCount {
	case 1:
		endRow = fmt.Sprintf("J"+"%d", nExcelStartRow+1)
		// 设置单元格大小
		file.SetColWidth("Sheet1", "A", "A", 30)
		file.SetColWidth("Sheet1", "B", "B", 12)
		file.SetColWidth("Sheet1", "E", "E", 15)
		file.SetColWidth("Sheet1", "F", "F", 20)
		file.SetColWidth("Sheet1", "G", "G", 20)
		file.SetColWidth("Sheet1", "H", "H", 20)
		file.SetColWidth("Sheet1", "J", "J", 20)
		// 应用样式到整个表格
		_ = file.SetCellStyle("Sheet1", "A1", "J1", style1)
	default:
		endRow = fmt.Sprintf("I"+"%d", nExcelStartRow+1)
		// 设置单元格大小
		file.SetColWidth("Sheet1", "A", "A", 30)
		file.SetColWidth("Sheet1", "B", "B", 12)
		file.SetColWidth("Sheet1", "D", "D", 15)
		file.SetColWidth("Sheet1", "E", "E", 20)
		file.SetColWidth("Sheet1", "F", "F", 20)
		file.SetColWidth("Sheet1", "G", "G", 20)
		file.SetColWidth("Sheet1", "I", "I", 20)
		// 应用样式到整个表格
		_ = file.SetCellStyle("Sheet1", "A1", "I1", style1)
	}

	_ = file.SetCellStyle("Sheet1", "A2", endRow, style)

	fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
	if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
		fmt.Println(err)
	}
	return url + fileName, nil
}

// CalculateMemberType   匹配记录类型
func CalculateMemberType(spendType, renewHide, memberGenre, memberLevel uint32) MemberType {
	switch {
	case spendType == 1:
		return FirstInvite
	case spendType == 2 && memberLevel == 2 && memberGenre == 201:
		return OpenQuarterGold
	case spendType == 2 && memberLevel == 2 && memberGenre == 202:
		return OpenHalfYearGold
	case spendType == 3 && renewHide == 1 && memberLevel == 2 && memberGenre == 201:
		return RenewQuarterGoldAuto
	case spendType == 3 && renewHide == 1 && memberLevel == 2 && memberGenre == 202:
		return RenewHalfYearGoldAuto
	case spendType == 2:
		switch memberLevel {
		case 2:
			return OpenAnnualGold
		case 4:
			return OpenAnnualPlatinum
		case 5:
			return OpenAnnualBlack
		case 6:
			return OpenAnnualPrivilege
		}
	case spendType == 3 && renewHide == 0:
		switch memberLevel {
		case 2:
			return RenewAnnualGoldIntervene
		case 4:
			return RenewAnnualPlatinumIntervene
		case 5:
			return RenewAnnualBlackIntervene
		}
	case spendType == 3 && renewHide == 1:
		switch memberLevel {
		case 2:
			return RenewAnnualGoldAuto
		case 4:
			return RenewAnnualPlatinumAuto
		case 5:
			return RenewAnnualBlackAuto
		case 6:
			return RenewAnnualPrivilegeAuto
		}
	case spendType == 4 && renewHide == 0:
		switch memberLevel {
		case 4:
			return UpgradeGoldToPlatinumIntervene
		case 5:
			if memberGenre == 200 || memberGenre == 201 || memberGenre == 202 {
				return UpgradeGoldToBlackIntervene
			}
			return UpgradePlatinumToBlackIntervene
		}
	case spendType == 4 && renewHide == 1:
		switch memberLevel {
		case 4:
			return UpgradeGoldToPlatinumAuto
		case 5:
			if memberGenre == 200 {
				return UpgradeGoldToBlackAuto
			}
			return UpgradePlatinumToBlackAuto
		}
	}
	return Unknown
}

// UpdateUserInviteRecordRenewHide 更新用户邀请记录：如果不是店员干预的续费用户，则更新为1-自动续费
func UpdateUserInviteRecordRenewHide() error {
	err := orm.Eloquent.Exec("UPDATE user_invite_record SET renew_hide=1 WHERE spend_type=3 AND scan=0 AND renew_hide!=1;").Error
	if err != nil {
		logger.Errorf("update renew_hide err:", logger.Field("err", err))
		return err
	}

	return nil
}

//func ExportUserMemberList(storeId, memberType uint32, startTime, endTime string) string {
//	var userInvites []UserInvite
//	qs := orm.Eloquent.Table("user_11invite").Where("from_uid > 0")
//	if memberType == 1 {
//		qs = qs.Where("member_type=？", 1)
//	} else if memberType == 2 {
//		qs = qs.Where("member_type in (?)", []uint32{2, 4, 5})
//	} else if memberType == 3 {
//		qs = qs.Where("member_type=？", 3)
//	}
//
//	if storeId != 0 {
//		qs = qs.Where("store_id", storeId)
//	}
//	if startTime != "" {
//		parse, err := time.Parse(DateTimeFormat, startTime)
//		if err != nil {
//			logger.Errorf("err:",logger.Field("err",err))
//			return ""
//		}
//		qs = qs.Where("member_open_time > ?", parse)
//	}
//	if endTime != "" {
//		parse, err := time.Parse(DateTimeFormat, endTime)
//		if err != nil {
//			logger.Errorf("err:",logger.Field("err",err))
//			return ""
//		}
//		parse = parse.AddDate(0, 0, 1)
//		qs = qs.Where("member_open_time < ?", parse)
//	}
//
//	err := qs.Order("id DESC,store_id DESC,from_uid DESC").Find(&userInvites).Error
//	if err != nil && err != RecordNotFound {
//		logger.Errorf("err:",logger.Field("err",err))
//		return ""
//	}
//
//	storeIds := make([]uint64, 0)
//	fromUids := make([]uint32, 0)
//	toUids := make([]uint32, 0)
//	for i, _ := range userInvites {
//		storeIds = append(storeIds, userInvites[i].StoreId)
//		fromUids = append(fromUids, userInvites[i].FromUid)
//		toUids = append(toUids, userInvites[i].ToUid)
//	}
//
//	var stores []Store
//	err = orm.Eloquent.Table("store").Where("id in (?)", storeIds).Find(&stores).Error
//	if err != nil {
//		logger.Error("err:",logger.Field("err",err))
//		return ""
//	}
//	storeMap := make(map[uint32]Store)
//	for i, _ := range stores {
//		storeMap[stores[i].ID] = stores[i]
//	}
//
//	fromUids = append(fromUids, toUids...)
//	var userInfos []UserInfo
//	err = orm.Eloquent.Table("user").Where("uid in (?)", fromUids).Find(&userInfos).Error
//	if err != nil {
//		logger.Error("err:",logger.Field("err",err))
//		return ""
//	}
//	userInfoMap := make(map[uint32]UserInfo, 0)
//	for i, _ := range userInfos {
//		userInfoMap[userInfos[i].Uid] = userInfos[i]
//	}
//
//	inviteMembers := make([]UserInviteMember, 0, len(userInvites))
//	for i, _ := range userInvites {
//		fromUser, _ := userInfoMap[userInvites[i].FromUid]
//		toUser, ok2 := userInfoMap[userInvites[i].ToUid]
//		if !ok2 {
//			continue
//		}
//		store, ok1 := storeMap[uint32(userInvites[i].StoreId)]
//		if !ok1 {
//			store = storeMap[uint32(toUser.StoreId)]
//		}
//		invite := UserInviteMember{
//			FromUserInfo: fromUser,
//			Store:        store,
//			ToUserInfo:   toUser,
//			UserInvite:   userInvites[i],
//		}
//		inviteMembers = append(inviteMembers, invite)
//	}
//
//	fileName := "邀请会员"
//	if storeId == 0 {
//		fileName = "全部门店邀请会员"
//	} else {
//		if len(stores) > 0 {
//			fileName = stores[0].Name
//		}
//	}
//	//url := "http://switch.deovo.com:8000/img/export/"
//	url := "http://39.108.188.218:8000/img/export/"
//
//	fileName = fileName + time.Now().Format("2006-01-02 15:04:05") + ".csv"
//	//f, err := os.OpenFile(fmt.Sprintf("./")+fileName, os.O_CREATE|os.O_TRUNC|os.O_APPEND|os.O_RDWR, 0644)
//	f, err := os.OpenFile(fmt.Sprintf("/www/server/images/export/")+fileName, os.O_CREATE|os.O_TRUNC|os.O_APPEND|os.O_RDWR, 0644)
//	if err != nil {
//		fmt.Println(err)
//		return fileName
//	}
//	defer f.Close()
//
//	w := csv.NewWriter(f)
//
//	//headline := []string{"门店名称", "店员id", "店员昵称","姓名", "会员id", "会员昵称", "注册会员时间", "会员状态"}
//	headline := []string{"门店名称", "店员id", "姓名", "会员id", "会员昵称", "会员等级", "注册会员时间", "会员状态"}
//	if err := w.Write(headline); err != nil {
//		log.Fatalln("error writing record to csv:",logger.Field("err",err))
//	}
//
//	for _, invite := range inviteMembers {
//		//fmt.Println("MemberOpenTime",invite.UserInvite.MemberOpenTime)
//		//fmt.Println("MemberOpenTime",invite.UserInvite.MemberOpenTime.Format("2006-01-02 15:04:05"))
//		record := []string{invite.Store.Name, fmt.Sprintf("%d", invite.FromUserInfo.Uid), invite.FromUserInfo.ShopAssistantName,
//			fmt.Sprintf("%d", invite.ToUserInfo.Uid), invite.ToUserInfo.WxName, MemberLevelToString(invite.UserInvite.MemberLevel), invite.UserInvite.MemberOpenTime.Format("2006-01-02 15:04:05"),
//			GetUserInviteStatus(invite.MemberStatus)}
//		if err := w.Write(record); err != nil {
//			log.Fatalln("error writing record to csv:",logger.Field("err",err))
//		}
//	}
//
//	w.Flush()
//	if err := w.Error(); err != nil {
//		log.Fatal(err)
//	}
//
//	return url + fileName
//}
// 导出用户

func ExportUserMemberList(storeId, memberType, cooperativeId uint32, startTime, endTime, renewalStartTime, renewalEndTime string) string {
	var userInfos []UserInfo
	qs := orm.Eloquent.Table("user")
	if memberType == 1 {
		qs = qs.Where("member_level=?", 1)
	} else if memberType == 2 {
		qs = qs.Where("member_level in (?)", []uint32{2, 4, 5})
	} else if memberType == 3 {
		qs = qs.Where("member_level=?", 3)
	}

	if storeId != 0 {
		qs = qs.Where("store_id=?", storeId)
	}
	if startTime != "" {
		parse, err := time.Parse(DateTimeFormat, startTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return ""
		}
		//qs = qs.Where("created_at > ?", parse)
		qs = qs.Where("open_member_time > ?", parse)
	}
	if endTime != "" {
		parse, err := time.Parse(DateTimeFormat, endTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return ""
		}
		parse = parse.AddDate(0, 0, 1)
		//qs = qs.Where("created_at < ?", parse)
		qs = qs.Where("open_member_time < ?", parse)
	}
	if cooperativeId != 0 {
		qs = qs.Where("cooperative_business_id=?", cooperativeId)
	}
	//err := qs.Order("id DESC,store_id DESC,from_uid DESC").Find(&userInvites).Error
	err := qs.Order("id DESC,store_id DESC,uid DESC").Find(&userInfos).Error
	//err := qs.Order("id DESC").Find(&userInfos).Error
	if err != nil && err != RecordNotFound {
		logger.Errorf("err:", logger.Field("err", err))
		return ""
	}

	storeIds := make([]uint32, 0)
	fromUids := make([]uint32, 0)
	toUids := make([]uint32, 0)
	for i, _ := range userInfos {
		storeIds = append(storeIds, uint32(userInfos[i].StoreId))
		//fromUids = append(fromUids, userInvites[i].FromUid)
		toUids = append(toUids, userInfos[i].Uid)
	}

	//var stores []Store
	//err = orm.Eloquent.Table("store").Where("id in (?)", storeIds).Find(&stores).Error
	//if err != nil {
	//	logger.Error("err:",logger.Field("err",err))
	//	return ""
	//}
	//storeMap := make(map[uint32]Store)
	//for i, _ := range stores {
	//	storeMap[stores[i].ID] = stores[i]
	//}

	//fromUids = append(fromUids, toUids...)
	var userInvites []UserInvite
	inviteQs := orm.Eloquent.Table("user_invite").Where("to_uid in (?)", toUids)
	if memberType == 1 {

	}
	if memberType == 2 {
		inviteQs = inviteQs.Where("action=2").Where("spend_type=2")
	}
	err = inviteQs.Find(&userInvites).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return ""
	}

	userInviteMap := make(map[uint32]UserInvite, 0)
	for i, _ := range userInvites {
		userInviteMap[userInvites[i].ToUid] = userInvites[i]
		fromUids = append(fromUids, userInvites[i].FromUid)
	}

	var fromUserInfos []UserInfo
	err = orm.Eloquent.Table("user").Where("uid in (?)", fromUids).Find(&fromUserInfos).Error
	if err != nil {
		logger.Error("from user infos err:", logger.Field("err", err))
		return ""
	}
	fromUserMap := make(map[uint32]UserInfo, 0)
	for i, _ := range fromUserInfos {
		fromUserMap[fromUserInfos[i].Uid] = fromUserInfos[i]
		//
		storeIds = append(storeIds, uint32(fromUserInfos[i].StoreId))
	}

	storeMap := StoreMapByIds(storeIds)

	isRenewal := false
	var inviteRecords []UserInviteRecord
	//err = orm.Eloquent.Table("user_invite_record").Where("to_uid in (?)", toUids).Where("first!=1").
	//	Where("scan=1").Order("id DESC").Find(&inviteRecords).Error
	qsInviteRecords := orm.Eloquent.Table("user_invite_record").Where("to_uid in (?)", toUids).
		Where("first!=1").Where("action=2")
	if renewalStartTime != "" {
		isRenewal = true
		parse, err := time.Parse(DateTimeFormat, renewalStartTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return ""
		}
		//qs = qs.Where("created_at > ?", parse)
		qsInviteRecords = qsInviteRecords.Where("action_time > ?", parse).Where("spend_type=3")
	}
	if renewalEndTime != "" {
		isRenewal = true
		parse, err := time.Parse(DateTimeFormat, renewalEndTime)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return ""
		}
		parse = parse.AddDate(0, 0, 1)
		//qs = qs.Where("created_at < ?", parse)
		qsInviteRecords = qsInviteRecords.Where("action_time < ?", parse).Where("spend_type=3")
	}
	err = qsInviteRecords.Order("id ASC").Find(&inviteRecords).Error
	if err != nil {
		logger.Error("invite record err:", logger.Field("err", err))
		return ""
	}

	UserInviteRecordListSetAssistantName(inviteRecords)
	inviteRecordMap := make(map[uint32][]UserInviteRecord, 0)
	for i, _ := range inviteRecords {
		fromUser, ok3 := fromUserMap[inviteRecords[i].FromUid]
		if ok3 {
			inviteRecords[i].ShopAssistantName = fromUser.ShopAssistantName
		}
		//inviteRecordMap[inviteRecords[i].ToUid] = inviteRecords[i]
		v, ok := inviteRecordMap[inviteRecords[i].ToUid]
		if ok {
			if len(v) >= 2 {
				continue
			}
		}
		if inviteRecords[i].SpendType == 3 && inviteRecords[i].Scan == 0 {
			inviteRecords[i].ShopAssistantName = "自动续费"
		}
		inviteRecordMap[inviteRecords[i].ToUid] = append(inviteRecordMap[inviteRecords[i].ToUid], inviteRecords[i])
	}

	inviteMembers := make([]UserInviteMember, 0, len(userInvites))
	for i, _ := range userInfos {
		//toUser, ok2 := userInfoMap[userInvites[i].ToUid]
		store, ok1 := storeMap[(userInfos[i].StoreId)]
		userInfoMember := UserInviteMember{
			FromUserInfo: UserInfo{},
			Store:        store,
			ToUserInfo:   userInfos[i],
			UserInvite:   UserInvite{ToUid: userInfos[i].Uid},
		}
		if isRenewal {
			v, ok := inviteRecordMap[userInfos[i].Uid]
			if !ok {
				continue
			}
			if len(v) > 0 {
				userInfoMember.UserInviteRecord = v[len(v)-1]
			}
		}
		userInvite, ok2 := userInviteMap[userInfos[i].Uid]
		if ok2 {
			userInfoMember.UserInvite = userInvite
			if !ok1 {
				store = storeMap[(userInvite.StoreId)]
				userInfoMember.Store = store
			}

			fromUser, ok3 := fromUserMap[userInvite.FromUid]
			if ok3 {
				userInfoMember.FromUserInfo = fromUser
			}
		}
		fromStore, ok4 := storeMap[userInfoMember.FromUserInfo.StoreId]
		if ok4 {
			userInfoMember.FromUserInfo.Store = &fromStore
		}
		inviteMembers = append(inviteMembers, userInfoMember)
	}
	if isRenewal {
		sort.Sort(ExportUserInviteMemberList(inviteMembers))
	}
	//UserInviteRecordListSetAssistantName(inviteRecords)
	//
	//inviteRecordMap := make(map[uint32][]UserInviteRecord, 0)
	//for i, _ := range inviteRecords {
	//	v, ok := inviteRecordMap[inviteRecords[i].ToUid]
	//	if ok {
	//		if len(v) >= 2 {
	//			continue
	//		}
	//	}
	//	if inviteRecords[i].SpendType == 3 && inviteRecords[i].Scan == 0 {
	//		inviteRecords[i].ShopAssistantName = "自动续费"
	//	}
	//
	//	inviteRecordMap[inviteRecords[i].ToUid] = append(inviteRecordMap[inviteRecords[i].ToUid], inviteRecords[i])
	//}

	fileName := "邀请会员"
	if storeId == 0 {
		fileName = "全部门店邀请会员"
	} else {
		store, err := GetStore(storeId)
		if err != nil {
			logger.Error("get store err:", logger.Field("err", err))
			return ""
		}
		fileName = store.Name
	}
	//url := "http://39.108.188.218:8000/img/export/"
	//url := "https://dev.admin.deovo.com/img/export/"
	styleBorder := &excelize.Style{
		Border: []excelize.Border{{
			Type:  "left",
			Color: "000000",
			Style: 1,
		}, {
			Type:  "top",
			Color: "000000",
			Style: 1,
		}, {
			Type:  "right",
			Color: "000000",
			Style: 1,
		}, {
			Type:  "bottom",
			Color: "000000",
			Style: 1,
		}},
	}
	styleFill1 := &excelize.Style{
		Border: []excelize.Border{{
			Type:  "left",
			Color: "000000",
			Style: 1,
		}, {
			Type:  "top",
			Color: "000000",
			Style: 1,
		}, {
			Type:  "right",
			Color: "000000",
			Style: 1,
		}, {
			Type:  "bottom",
			Color: "000000",
			Style: 1,
		}},
		Fill: excelize.Fill{
			Type:    "pattern",
			Pattern: 1,
			Color:   []string{"FFFF00"},
		},
	}
	styleFill2 := &excelize.Style{
		Border: []excelize.Border{{
			Type:  "left",
			Color: "000000",
			Style: 1,
		}, {
			Type:  "top",
			Color: "000000",
			Style: 1,
		}, {
			Type:  "right",
			Color: "000000",
			Style: 1,
		}, {
			Type:  "bottom",
			Color: "000000",
			Style: 1,
		}},
		Fill: excelize.Fill{
			Type:    "pattern",
			Pattern: 1,
			Color:   []string{"FFEFDB"},
		},
	}

	//url := "https://dev.admin.deovo.com/load/export/"

	fileName = time.Now().Format(TimeFormat) + fileName + ".xlsx"
	fSheet := "Sheet1"
	file := excelize.NewFile()
	//streamWriter, err := file.NewStreamWriter("Sheet1")
	//if err != nil {
	//	fmt.Println(err)
	//}
	styleBorderId, err := file.NewStyle(styleBorder)
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
	}
	styleFillId1, err := file.NewStyle(styleFill1)
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
	}
	styleFillId2, err := file.NewStyle(styleFill2)
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
	}
	//headline := []string{"门店名称", "店员id", "店员姓名", "用户注册时间", "最近登录时间", "会员id", "会员昵称", "用户手机号", "会员等级", "注册会员时间", "会员状态"}
	headline := []interface{}{"门店名称", "店员id", "店员姓名", "店员门店", "用户注册时间", "最近登录时间", "用户id", "用户昵称", "用户手机号", "会员等级", "注册会员时间",
		"开通_店员id", "开通_店员名称", "开通_扫码时间", "续费_店员id", "续费_店员名称", "续费_扫码时间"}
	if cooperativeId != 0 {
		headline = []interface{}{"门店名称", "店员id", "店员姓名", "店员门店", "用户注册时间", "最近登录时间", "用户id", "会员等级", "注册会员时间",
			"开通_店员id", "开通_店员名称", "开通_扫码时间", "续费_店员id", "续费_店员名称", "续费_扫码时间"}
	}
	headLength := len(headline)
	for i, _ := range headline {
		cell, _ := excelize.CoordinatesToCellName(1+i, 1)
		err = file.SetCellValue(fSheet, cell, headline[i])
		if err != nil {
			logger.Error("file set value err:", logger.Field("err", err))
		}
		idx := i
		if cooperativeId == 0 {
			if idx+1 > 11 && idx+1 <= 14 {
				err = file.SetCellStyle(fSheet, cell, cell, styleFillId1)
				if err != nil {
					logger.Error("file set value err:", logger.Field("err", err))
				}
			} else if idx+1 > 14 && idx+1 <= 17 {
				err = file.SetCellStyle(fSheet, cell, cell, styleFillId2)
				if err != nil {
					logger.Error("file set value err:", logger.Field("err", err))
				}
			} else {
				err = file.SetCellStyle(fSheet, cell, cell, styleBorderId)
				if err != nil {
					logger.Error("file set value err:", logger.Field("err", err))
				}
			}
		} else {
			if idx+1 > 9 && idx+1 <= 12 {
				err = file.SetCellStyle(fSheet, cell, cell, styleFillId1)
				if err != nil {
					logger.Error("file set value err:", logger.Field("err", err))
				}
			} else if idx+1 > 12 && idx+1 <= 15 {
				err = file.SetCellStyle(fSheet, cell, cell, styleFillId2)
				if err != nil {
					logger.Error("file set value err:", logger.Field("err", err))
				}
			} else {
				err = file.SetCellStyle(fSheet, cell, cell, styleBorderId)
				if err != nil {
					logger.Error("file set value err:", logger.Field("err", err))
				}
			}
		}
	}

	//if err = streamWriter.SetRow(cell, headline); err != nil {
	//	fmt.Println(err)
	//}

	for rowId := 0; rowId < len(inviteMembers); rowId++ {
		invite := inviteMembers[rowId]

		fromStoreName := ""
		if invite.FromUserInfo.Store != nil {
			fromStoreName = invite.FromUserInfo.Store.Name
		}

		record := []interface{}{}
		if cooperativeId != 0 {
			record = []interface{}{invite.Store.Name, fmt.Sprintf("%d", invite.FromUserInfo.Uid),
				invite.FromUserInfo.ShopAssistantName, fromStoreName,
				invite.ToUserInfo.CreatedAt.Format(TimeFormat), invite.ToUserInfo.LastLoginAt.Format(TimeFormat),
				fmt.Sprintf("%d", invite.ToUserInfo.Uid), MemberLevelToString(invite.UserInvite.MemberLevel),
				invite.UserInvite.MemberOpenTime.Format(TimeFormat),
				//GetUserInviteStatus(invite.MemberStatus),
			}
		} else {
			record = []interface{}{invite.Store.Name, fmt.Sprintf("%d", invite.FromUserInfo.Uid),
				invite.FromUserInfo.ShopAssistantName, fromStoreName,
				invite.ToUserInfo.CreatedAt.Format(TimeFormat), invite.ToUserInfo.LastLoginAt.Format(TimeFormat),
				fmt.Sprintf("%d", invite.ToUserInfo.Uid), invite.ToUserInfo.WxName, invite.ToUserInfo.Tel,
				MemberLevelToString(invite.ToUserInfo.MemberLevel),
				invite.ToUserInfo.OpenMemberTime.Format(TimeFormat),
				//GetUserInviteStatus(invite.ToUserInfo.MemberStatus),
			}
			//MemberLevelToString(invite.UserInvite.MemberLevel),
			//invite.UserInvite.MemberOpenTime.Format(TimeFormat),
			//GetUserInviteStatus(invite.MemberStatus)}
		}
		userInviteRecordList, ok := inviteRecordMap[invite.ToUid]
		if ok {
			for i, _ := range userInviteRecordList {
				if i == 0 && userInviteRecordList[i].SpendType != 2 {
					record = append(record, []interface{}{"", "", ""}...)
				}
				record = append(record, []interface{}{userInviteRecordList[i].FromUid, userInviteRecordList[i].ShopAssistantName, userInviteRecordList[i].CreatedAt.Format(TimeFormat)}...)
			}
		}

		if len(record) < headLength {
			record = append(record, make([]interface{}, headLength-len(record))...)
		}
		for i, _ := range record {
			cell, _ := excelize.CoordinatesToCellName(1+i, rowId+2)
			err = file.SetCellValue(fSheet, cell, record[i])
			if err != nil {
				logger.Error("file set value err:", logger.Field("err", err))
			}

			err = file.SetCellStyle(fSheet, cell, cell, styleBorderId)
			if err != nil {
				logger.Error("file set value err:", logger.Field("err", err))
			}
		}
		//if err := streamWriter.SetRow(cell, record); err != nil {
		//	fmt.Println(err)
		//}
	}

	//if err := streamWriter.Flush(); err != nil {
	//	fmt.Println(err)
	//}
	if err := file.SaveAs("/www/server/images/export/" + fileName); err != nil {
		//if err := file.SaveAs("./" + fileName); err != nil {
		fmt.Println(err)
	}

	return config.ExportConfig.Url + fileName
}

type ExportUserInviteMemberList []UserInviteMember

func (s ExportUserInviteMemberList) Len() int {
	//返回传入数据的总数
	return len(s)
}
func (s ExportUserInviteMemberList) Swap(i, j int) {
	//两个对象满足Less()则位置对换
	//表示执行交换数组中下标为i的数据和下标为j的数据
	s[i], s[j] = s[j], s[i]
}
func (s ExportUserInviteMemberList) Less(i, j int) bool {
	//按字段比较大小,此处是降序排序
	//返回数组中下标为i的数据是否小于下标为j的数据
	return s[i].UserInviteRecord.ActionTime.After(s[j].UserInviteRecord.ActionTime)
}

func GetUserInviteStatus(status uint8) string {
	switch status {
	case 1:
		return "未注册"
	case 2:
		return "已注册"
	case 3:
		return "取消会员"
	}
	return ""
}

func IsUserInfoByUid(uid uint32) (bool, error) {
	//userInfo := new(UserInfo)
	var count int64
	err := orm.Eloquent.Debug().Table("user").Where("uid = ?", uid).Count(&count).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return false, err
	}
	if count == 0 {
		return true, errors.New("user not exist")
	}
	return true, nil
}

func GetUserInfoByUid(uid uint32) (UserInfo, error) {
	//userInfo := new(UserInfo)
	var userInfo UserInfo
	err := orm.Eloquent.Debug().Table("user").Where("uid = ?", uid).Find(&userInfo).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return userInfo, err
	}
	return userInfo, nil
}

func GetSysUserInfoByUid(uid uint32) (SysUser, error) {
	//userInfo := new(UserInfo)
	var userInfo SysUser
	err := orm.Eloquent.Debug().Table("sys_user").Where("uid = ?", uid).Find(&userInfo).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return userInfo, err
	}
	return userInfo, nil
}

func countDigits(n uint32) int {
	str := strconv.FormatUint(uint64(n), 10)
	return len(str)
}

func GetSysUserInfoById(id uint32) (SysUser, error) {
	var userInfo SysUser
	if countDigits(id) == 8 { //历史数据为8位的uid
		err := orm.Eloquent.Debug().Table("sys_user").Where("uid = ?", id).Find(&userInfo).Error
		if err != nil {
			logger.Error("err:", logger.Field("err", err))
			return userInfo, err
		}
	} else {
		err := orm.Eloquent.Debug().Table("sys_user").Where("user_id = ?", id).Find(&userInfo).Error
		if err != nil {
			logger.Error("err:", logger.Field("err", err))
			return userInfo, err
		}
	}

	return userInfo, nil
}

type UserDepositRefundRecordListReq struct {
	//StoreId uint32 `json:"store_id"` // 门店id
	Uid            uint32 `json:"uid"` // 用户id
	PageNum        int    `json:"pageIndex"`
	PageSize       int    `json:"pageSize"`
	Status         uint32 `json:"status"`
	AuditTimeStart string `json:"audit_time_start"` // 审核开始时间
	AuditTimeEnd   string `json:"audit_time_end"`   // 审核结束时间
}
type UserDepositRefundRecordListResp struct {
	List      []DepositRefundRecord `json:"list"`
	Total     int                   `json:"total"`     // 总条数
	PageIndex int                   `json:"pageIndex"` // 页码
	PageSize  int                   `json:"pageSize"`  // 每页展示条数
}

func (m *UserDepositRefundRecordListReq) DepositRefundRecordList() (*UserDepositRefundRecordListResp, error) {
	qs := orm.Eloquent.Table("deposit_refund_record")
	if m.Status != 0 {
		qs = qs.Where("status=?", m.Status)
	}
	if m.Uid != 0 {
		qs = qs.Where("uid=?", m.Uid)
	}
	if m.AuditTimeStart != "" {
		parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
		if err != nil {
			logger.Errorf("DepositRefundRecordList err:", err)
			return nil, err
		}
		qs = qs.Where("confirm_time >= ?", parse)
	}
	if m.AuditTimeEnd != "" {
		parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
		if err != nil {
			logger.Errorf("DepositRefundRecordList err:", err)
			return nil, err
		}
		//parse = parse.AddDate(0, 0, 1)
		qs = qs.Where("confirm_time <= ?", parse)
	}
	resp := &UserDepositRefundRecordListResp{
		PageIndex: m.PageNum,
		PageSize:  m.PageSize,
	}

	page := m.PageNum - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}

	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Error("count err:", logger.Field("err", err))
		return resp, err
	}
	resp.Total = int(count)

	var depositRefunds []DepositRefundRecord
	err = qs.Order("status ASC").Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&depositRefunds).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return resp, err
	}

	resp.List = depositRefunds

	return resp, nil
}

type GroupSendMessageCreateTemplateListReq struct {
	Status   uint32 `json:"status"` // 1-待发送 2-已发送
	Title    string `json:"title"`
	PageNum  int    `json:"pageIndex"`
	PageSize int    `json:"pageSize"`
}
type GroupSendMessageCreateTemplateListResp struct {
	List               []GroupSendMessageTemplate `json:"list"`
	SmsRemainingNumber int                        `json:"sms_remaining_number"` // 本月短信剩余数量
	Count              uint32                     `json:"count"`
	PageNum            int                        `json:"pageIndex"`
}

func (m *GroupSendMessageCreateTemplateListReq) List() (*GroupSendMessageCreateTemplateListResp, error) {
	qs := orm.Eloquent.Table("group_send_message_template")
	if m.Status != 0 {
		qs = qs.Where("status=?", m.Status)
	}
	if m.Title != "" {
		qs = qs.Where("title LIKE '%" + m.Title + "%'")
	}

	page := m.PageNum - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}
	resp := &GroupSendMessageCreateTemplateListResp{PageNum: m.PageNum}
	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Error("count err:", logger.Field("err", err))
		return resp, err
	}
	resp.Count = uint32(count)

	var groupSends []GroupSendMessageTemplate
	err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&groupSends).Error
	if err != nil && err != RecordNotFound {
		logger.Error("err:", logger.Field("err", err))
		return resp, err
	}
	resp.List = groupSends

	resp.SmsRemainingNumber = GetSmsNumberRemaining()

	return resp, nil
}

func CreateInviteMemberReport() {
	date := time.Now().AddDate(0, 0, 1)
	if date.Day() != 1 {
		return
	}
	var cooperatives []CooperativeBusiness
	err := orm.Eloquent.Table("cooperative_business").Find(&cooperatives).Error
	if err != nil {
		logger.Error("cooperative err:", logger.Field("err", err))
		return
	}
	for i, _ := range cooperatives {
		cooperatives[i].InviteMemberReport()
	}
}

func (m *CooperativeBusiness) InviteMemberReport() {
	var users []UserInfo
	err := orm.Eloquent.Table("user").Where("cooperative_business_id=?", m.ID).
		Where("user_type=?", UserTypeShopAssistant).Find(&users).Error
	if err != nil {
		logger.Error("cooperative err:", logger.Field("err", err))
		return
	}
	for i, _ := range users {
		m.UserInviteReport(users[i])
	}
}

// UserInviteReport
// 每个月1号统计上个月的数据
func (m *CooperativeBusiness) UserInviteReport(userInfo UserInfo) {
	//end := InDayZero(1)
	//start := end.AddDate(0, -1, 0)
	reportTime := time.Now().AddDate(0, -1, 0).Format("2006-01")
	//var userInvites []UserInvite
	//qs := orm.Eloquent.Table("user_invite").Where("from_uid=?", userInfo.Uid).
	//	Where("member_status=?", 2).Where("user_type=?", 2).
	//	Where("member_open_time>?", start).Where("member_open_time<?", end)
	//qs = qs.Where("action=2").Where("spend_type=2")
	//err := qs.Find(&userInvites).Error
	//if err != nil && err != RecordNotFound {
	//	logger.Error("cooperative err:",logger.Field("err",err))
	//	return
	//}
	//reportTime := start.Format("2006-01")
	//m.SetMemberDeductConfig()
	m.SetAssistantMemberDeductConfig(uint32(userInfo.StoreId))
	if m.CooperativeAssistantMemberDeduct == nil {
		logger.Error("cooperative assistant member deduct is nil")
		return
	}
	exist, err := QueryRecordExist(fmt.Sprintf(
		"SELECT * FROM invite_member_report WHERE cooperative_business_id=%d AND date='%s' AND uid=%d",
		userInfo.CooperativeBusinessId, reportTime, userInfo.Uid))
	if err != nil {
		logger.Error("cooperative member promotion record exist err:", logger.Field("err", err))
		return
	}
	report := &InviteMemberReport{
		Uid:                               userInfo.Uid,
		StoreId:                           uint32(userInfo.StoreId),
		GoldCount:                         0,
		GoldCountHalf:                     0,
		GoldCountQuarter:                  0,
		PlatinumCount:                     0,
		BlackGoldCount:                    0,
		PrivilegeCount:                    0,
		Date:                              reportTime,
		DeductAmount:                      0,
		CooperativeBusinessId:             userInfo.CooperativeBusinessId,
		CooperativeName:                   userInfo.CooperativeName,
		GoldDeduct:                        m.CooperativeAssistantMemberDeduct.GoldDeduct,
		PlatinumDeduct:                    m.CooperativeAssistantMemberDeduct.PlatinumDeduct,
		BlackGoldDeduct:                   m.CooperativeAssistantMemberDeduct.BlackGoldDeduct,
		RenewalGoldCount:                  0,
		RenewalGoldCountHalf:              0,
		RenewalGoldCountQuarter:           0,
		RenewalPlatinumCount:              0,
		RenewalBlackGoldCount:             0,
		RenewalPrivilegeCount:             0,
		UpgradeGoldToPlatinumCount:        0,
		UpgradeGoldToBlackCount:           0,
		UpgradePlatinumToBlackCount:       0,
		InviteRenewalGoldCount:            0,
		InviteRenewalPlatinumCount:        0,
		InviteRenewalBlackGoldCount:       0,
		InviteUpgradeGoldToPlatinumCount:  0,
		InviteUpgradeGoldToBlackCount:     0,
		InviteUpgradePlatinumToBlackCount: 0,
	}

	//for i, _ := range userInvites {
	//	switch userInvites[i].MemberLevel {
	//	case 2:
	//		report.GoldCount += 1
	//	case 4:
	//		report.PlatinumCount += 1
	//	case 5:
	//		report.BlackGoldCount += 1
	//	}
	//}
	//report.DeductAmount += report.GoldCount * m.CooperativeAssistantMemberDeduct.GoldDeduct
	//report.DeductAmount += report.PlatinumCount * m.CooperativeAssistantMemberDeduct.PlatinumDeduct
	//report.DeductAmount += report.BlackGoldCount * m.CooperativeAssistantMemberDeduct.BlackGoldDeduct
	if exist {
		//err = orm.Eloquent.Save(report).Error
		//if err != nil {
		//	logger.Error("invite member report err:",logger.Field("err",err))
		//}
		logger.Error("member report exist ")
		return
	}

	//if len(userInvites) == 0 {
	//	err = orm.Eloquent.Create(report).Error
	//	if err != nil {
	//		logger.Error("Create report err:",logger.Field("err",err))
	//	}
	//	return
	//}

	err = orm.Eloquent.Create(report).Error
	if err != nil {
		logger.Error("Create report err:", logger.Field("err", err))
	}
}

func GetSysUser(suid interface{}) (SysUser, error) {
	fmt.Println("sysUid:", suid)
	var sUser SysUser
	err := orm.Eloquent.Table("sys_user").Where(fmt.Sprintf("user_id=%.0f", suid.(float64))).Find(&sUser).Error
	if err != nil {
		logger.Error("invite member report err:", logger.Field("err", err))
		return sUser, err
	}

	return sUser, nil
}

type AssistantInviteMemberReportReq struct {
	RoleId                []uint32 `json:"roleId"`                  // 角色id
	CooperativeBusinessId uint32   `json:"cooperative_business_id"` // 合作商id
	StoreId               uint32   `json:"store_id"`                // 门店id
	Uid                   uint32   `json:"uid"`                     // 店员小程序id
	InviteName            string   `json:"invite_name"`             // 邀请人昵称
	Date                  string   `json:"date"`                    // 日期
	PageIndex             int      `json:"pageIndex"`               // 页码
	PageSize              int      `json:"pageSize"`                // 每页数量
	IsExport              uint32   `json:"is_export"`               // 1-导出
	SysUser               SysUser  `json:"sys_user"`                //
}

type AssistantInviteMemberReportListResp struct {
	List      []InviteMemberReport `json:"list"`
	Total     int64                `json:"total"`      // 数据总条数
	PageIndex int                  `json:"pageIndex"`  // 页码
	PageSize  int                  `json:"pageSize"`   // 每页展示条数
	ExportUrl string               `json:"export_url"` // 导出excel地址
}

func (m *AssistantInviteMemberReportReq) List(c *gin.Context) (*AssistantInviteMemberReportListResp, error) {
	resp := new(AssistantInviteMemberReportListResp)
	var memberReport []InviteMemberReport
	var users []SysUser
	us := orm.Eloquent.Table("sys_user").Where("uid != 0")
	if len(m.RoleId) != 0 {
		us = us.Where("role_id in (?)", m.RoleId)
	}
	if m.StoreId != 0 {
		us = us.Where("JSON_CONTAINS(store_data, ?)", fmt.Sprintf(`{"storeId":%d}`, m.StoreId))
	}
	err := us.Find(&users).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return nil, err
	}
	if len(users) == 0 {
		return &AssistantInviteMemberReportListResp{}, nil
	}

	ids := make(map[string]uint32, 0)
	sysUserMap := make(map[uint32]*SysUser, 0)
	var uidList []uint32
	for i, _ := range users {
		ids[users[i].NickName] = users[i].Uid
		uidList = append(uidList, users[i].Uid)
		sysUserMap[users[i].Uid] = &users[i]
	}

	qs := orm.Eloquent.Table("invite_member_report")
	if len(uidList) != 0 {
		qs = qs.Where("uid in (?)", uidList)
	}

	if m.SysUser.UserId != 1 {
		qs = qs.Where("cooperative_business_id=?", m.SysUser.CooperativeBusinessId)
	} else {
		qs = qs.Where("cooperative_business_id=?", m.CooperativeBusinessId)
	}
	//if len(ids) > 0 {
	//	qs = qs.Where("uid  NOT IN (?)", ids)
	//}

	if m.InviteName != "" {
		m.Uid = ids[m.InviteName]
		if m.Uid == 0 {
			qs = qs.Where("uid=?", m.Uid)
		}
	}
	if m.Uid != 0 {
		qs = qs.Where("uid=?", m.Uid)
	}
	if m.Date != "" {
		qs = qs.Where("date=?", m.Date)
	}
	//qs := NewInviteMemberReportQuerySet(DB).UidEq(m.Uid)
	var count int64
	err = qs.Count(&count).Error
	if err != nil {
		logger.Error("count err:", logger.Field("err", err))
		return nil, err
	}
	page := m.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}
	//totalPage := int(count)/m.PageSize + 1

	if m.IsExport == 1 { // 导出excel
		err = qs.Order("STR_TO_DATE(date, '%Y-%m-%d') DESC, store_id ASC").Find(&memberReport).Error
		if err != nil && err != RecordNotFound {
			logger.Error("err:", logger.Field("err", err))
			return nil, err
		}
	} else {
		err = qs.Order("STR_TO_DATE(date, '%Y-%m-%d') DESC, store_id ASC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&memberReport).Error
		if err != nil && err != RecordNotFound {
			logger.Error("err:", logger.Field("err", err))
			return nil, err
		}
	}

	for i, item := range memberReport {
		memberReport[i].SystemUser = sysUserMap[item.Uid]

		storeInfo, _ := GetUserEffectiveStore(item.Uid)
		memberReport[i].SystemUser.StoreList = storeInfo
		if len(storeInfo) != 0 {
			memberReport[i].StoreId = uint32(storeInfo[0].StoreID)
		}

		memberReport[i].CooperativeBusinessId = sysUserMap[item.Uid].CooperativeBusinessId
		memberReport[i].CooperativeName = sysUserMap[item.Uid].CooperativeName
	}

	//memberReport = InviteMemberReportListSetUser(memberReport)
	//memberReport = InviteMemberReportListSetStore(memberReport)

	if m.IsExport == 1 {
		fileName, err := inviteMemberReport(memberReport)
		if err != nil {
			logger.Error("err:", logger.Field("err", err))
			return nil, err
		}
		resp.ExportUrl = fileName
	} else {
		resp.List = memberReport
		resp.Total = count
		resp.PageSize = m.PageSize
		resp.PageIndex = m.PageIndex
	}

	return resp, nil
}

// 店员绩效导出excel
func inviteMemberReport(list []InviteMemberReport) (string, error) {
	file := excelize.NewFile()
	fSheet := "Sheet1"

	url := config.ExportConfig.Url
	fileName := time.Now().Format(TimeFormat) + "店员绩效" + ".xlsx"
	fmt.Println("url fileName:", url+fileName)

	title1 := []interface{}{"昵称", "小程序ID", "合作商", "门店", "月份",
		"开通会员数", "开通会员数", "开通会员数", "开通会员数", "开通会员数",
		"续费会员数（干预）", "续费会员数（干预）", "续费会员数（干预）",
		"升级会员数（干预）", "升级会员数（干预）", "升级会员数（干预）",
		"续费会员数（自动）", "续费会员数（自动）", "续费会员数（自动）", "续费会员数（自动）", "续费会员数（自动）",
		"升级会员数（自动）", "升级会员数（自动）", "升级会员数（自动）"}
	title2 := []interface{}{"昵称", "小程序ID", "合作商", "门店", "月份",
		"年费黄金", "半年黄金", "季度黄金", "年费白金", "年费黑金",
		"年费黄金", "年费白金", "年费黑金",
		"黄金->白金", "黄金->黑金", "白金->黑金",
		"年费黄金", "半年黄金", "季度黄金", "年费白金", "年费黑金",
		"黄金->白金", "黄金->黑金", "白金->黑金"}
	for i, _ := range title1 {
		cell, _ := excelize.CoordinatesToCellName(1+i, 1)
		err := file.SetCellValue(fSheet, cell, title1[i])
		if err != nil {
			logger.Error("file set value err:", logger.Field("err", err))
		}
	}

	for i, _ := range title2 {
		cell, _ := excelize.CoordinatesToCellName(1+i, 2)
		err := file.SetCellValue(fSheet, cell, title2[i])
		if err != nil {
			logger.Error("file set value err:", logger.Field("err", err))
		}
	}

	var row []interface{}
	nExcelStartRow := 0

	for i := 0; i < len(list); i++ {
		storeName := ""
		if list[i].SystemUser.StoreList != nil {
			for _, item := range list[i].SystemUser.StoreList {
				if storeName != "" {
					storeName += ","
				}
				storeName += item.StoreName
			}
		}
		shopAssistantName := ""
		if list[i].SystemUser != nil {
			shopAssistantName = list[i].SystemUser.NickName
		}

		row = []interface{}{
			shopAssistantName,        // 昵称
			list[i].Uid,              // 小程序ID
			list[i].CooperativeName,  // 合作商名称
			storeName,                // 门店名称
			list[i].Date,             // 月份
			list[i].GoldCount,        // 开通会员：年费黄金
			list[i].GoldCountHalf,    //开通会员：半年黄金
			list[i].GoldCountQuarter, //开通会员：季度黄金
			list[i].PlatinumCount,    // 开通会员：年费白金
			list[i].BlackGoldCount,   // 开通会员：年费黑金

			list[i].InviteRenewalGoldCount,      // 续费会员（干预）：年费黄金
			list[i].InviteRenewalPlatinumCount,  // 续费会员（干预）：白金
			list[i].InviteRenewalBlackGoldCount, // 续费会员（干预）：黑金

			list[i].InviteUpgradeGoldToPlatinumCount,  // 升级（干预）：黄金->白金数量
			list[i].InviteUpgradeGoldToBlackCount,     // 升级（干预）：黄金->黑金数量
			list[i].InviteUpgradePlatinumToBlackCount, // 升级（干预）：白金->黑金数量

			list[i].RenewalGoldCount,        // 续费会员（自动）：年费黄金
			list[i].RenewalGoldCountHalf,    // 续费会员（自动）：半年黄金
			list[i].RenewalGoldCountQuarter, // 续费会员（自动）：季度黄金
			list[i].RenewalPlatinumCount,    // 续费会员（自动）：白金
			list[i].RenewalBlackGoldCount,   // 续费会员（自动）：黑金

			list[i].UpgradeGoldToPlatinumCount,  // 升级（自动）：黄金->白金数量
			list[i].UpgradeGoldToBlackCount,     // 升级（自动）：黄金->黑金数量
			list[i].UpgradePlatinumToBlackCount, // 升级（自动）：白金->黑金数量
		}

		for j, _ := range row {
			cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+3)
			err := file.SetCellValue(fSheet, cell, row[j])
			if err != nil {
				logger.Error("file set value err:", logger.Field("err", err))
			}
		}
		nExcelStartRow++
	}

	// 设置所有单元格的样式: 居中、加边框
	style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
	"border":[{"type":"left","color":"000000","style":1},
	{"type":"top","color":"000000","style":1},
	{"type":"right","color":"000000","style":1},
	{"type":"bottom","color":"000000","style":1}]}`)

	// 设置单元格的样式: 居中、加边框、自动换行
	style1, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center","wrap_text":true},
	"border":[{"type":"left","color":"000000","style":1},
	{"type":"top","color":"000000","style":1},
	{"type":"right","color":"000000","style":1},
	{"type":"bottom","color":"000000","style":1}]}`)

	endRow := fmt.Sprintf("X%d", nExcelStartRow+2)
	// 合并单元格
	_ = file.MergeCell(fSheet, "A1", "A2")
	_ = file.MergeCell(fSheet, "B1", "B2")
	_ = file.MergeCell(fSheet, "C1", "C2")
	_ = file.MergeCell(fSheet, "D1", "D2")
	_ = file.MergeCell(fSheet, "E1", "E2")
	_ = file.MergeCell(fSheet, "F1", "J1")
	_ = file.MergeCell(fSheet, "K1", "M1")
	_ = file.MergeCell(fSheet, "N1", "P1")
	_ = file.MergeCell(fSheet, "Q1", "U1")
	_ = file.MergeCell(fSheet, "V1", "X1")

	//设置单元格高度
	file.SetRowHeight("Sheet1", 1, 20)
	file.SetRowHeight("Sheet1", 2, 20)
	// 从列 C 到列 K，逐一设置宽度为 20
	for col := 'F'; col <= 'X'; col++ {
		colName := string(col)
		file.SetColWidth("Sheet1", colName, colName, 9)
	}
	// 应用样式到整个表格
	_ = file.SetCellStyle("Sheet1", "A1", "X1", style1)
	_ = file.SetCellStyle("Sheet1", "A2", endRow, style)

	fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
	if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
		fmt.Println(err)
	}
	return url + fileName, nil
}

//func InviteMemberReportListSetUser(list []InviteMemberReport) []InviteMemberReport {
//	ids := make([]uint32, 0, len(list))
//	for i, _ := range list {
//		ids = append(ids, list[i].Uid)
//	}
//	if len(ids) == 0 {
//		return list
//	}
//
//	infoMap, err := GetUserInfoMap(ids)
//	if err != nil {
//		logger.Error("user info map err:", logger.Field("err", err))
//		return list
//	}
//
//	for i, _ := range list {
//		v, ok := infoMap[list[i].Uid]
//		if ok {
//			list[i].User = &v
//		}
//		fmt.Println("UserInfo:", v)
//	}
//
//	return list
//}
//
//func InviteMemberReportListSetStore(list []InviteMemberReport) []InviteMemberReport {
//	ids := make([]uint32, 0, len(list))
//	for i, _ := range list {
//		ids = append(ids, list[i].StoreId)
//	}
//	if len(ids) == 0 {
//		return list
//	}
//	storeMap := GetStoreMapByIds(ids)
//	//infoMap, err := GetUserInfoMap(ids)
//	//if err != nil {
//	//	logger.Error("user info map err:",logger.Field("err",err))
//	//	return list
//	//}
//
//	for i, _ := range list {
//		v, ok := storeMap[uint64(list[i].StoreId)]
//		if ok {
//			list[i].Store = v
//		}
//		fmt.Println("UserInfo:", v)
//	}
//
//	return list
//}

func GetCooperativeBusinessId(c *gin.Context) (uint32, error) {
	data, _ := c.Get(jwtauth.JwtPayloadKey)
	sysUid, ok := data.(jwtauth.MapClaims)["identity"]
	if !ok {
		logger.Error("sys uid err")
		app.Error(c, http.StatusInternalServerError, errors.New("sys uid err"), "查询失败")
		return 0, errors.New("sys uid err")
	}
	sysUser, err := GetSysUser(sysUid)
	if err != nil {
		logger.Error("sys user err:", logger.Field("err", err))
		app.Error(c, http.StatusInternalServerError, err, "查询失败")
		return 0, err
	}
	//req.CooperativeBusinessId = sysUser.CooperativeBusinessId
	return sysUser.CooperativeBusinessId, nil
}

func GetSysUserByCtx(c *gin.Context) (*SysUser, error) {
	//data, _ := c.Get(jwtauth.JwtPayloadKey)
	//sysUid, ok := data.(jwtauth.MapClaims)["identity"]
	//if !ok {
	//	logger.Error("sys uid err")
	//	app.Error(c, http.StatusInternalServerError, errors.New("sys uid err"), "查询失败")
	//	return nil, errors.New("sys uid err")
	//}
	//sysUser, err := GetSysUser(sysUid)
	//if err != nil {
	//	logger.Error("sys user err:",logger.Field("err",err))
	//	app.Error(c, http.StatusInternalServerError, err, "查询失败")
	//	return nil, err
	//}
	//req.CooperativeBusinessId = sysUser.CooperativeBusinessId
	//return &sysUser, nil

	data, _ := c.Get(jwtauth.JwtPayloadKey)
	mapClaims := data.(jwtauth.MapClaims)
	sysUid := float64(0)
	if v, ok := mapClaims["identity"]; ok {
		sysUid = v.(float64)
	}
	//fmt.Println("sysUid:", sysUid)

	//req.SysUid = fmt.Sprintf("%.0f", sysUid)
	var sysUser SysUser
	err := orm.Eloquent.Table("sys_user").Where("user_id=?", uint32(sysUid)).Find(&sysUser).Error
	if err != nil {
		logger.Error("sys user err:", logger.Field("err", err))
		app.Error(c, http.StatusInternalServerError, err, "操作失败")
		return &sysUser, err
	}
	return &sysUser, nil
}

//type CooperativeStockExportReq struct {
//	CooperativeBusinessId uint32 `json:"cooperative_business_id"`
//	StoreId               uint32 `json:"store_id"` // 门店id
//}
//
//func (r *CooperativeStockExportReq) Export() {
//
//}
//OrderType: 1-物流支付 2-取消物流租卡 3-滞纳金 4-收回卡 5-退物流费 6-商城购物 7-购买商品取消订单 8-购买商品订单退货

// gen:qs
type UserOpenMemberRecord struct {
	Model

	Uid          uint32    `json:"uid" gorm:"index"`
	OpenNo       string    `json:"open_no" gorm:"index"`
	OrderId      uint32    `json:"order_id" gorm:"index"`
	OrderType    uint32    `json:"order_type"`
	MemberLevel  uint32    `json:"member_level"`
	MemberExpire time.Time `json:"member_expire"` // 会员到期时间

	Order             *Order             `json:"order"  gorm:"-"`
	ShareCardRetrieve *ShareCardRetrieve `json:"share_card_retrieve"  gorm:"-"`
	GoodsOrder        *GoodsOrder        `json:"goods_order"  gorm:"-"`
	//Attach       string    `json:"attach"`
}

func (o *UserOpenMemberRecord) TableName() string {
	return "user_open_member_record"
}

func (m *UserOpenMemberRecord) Refund(outTradeNo string, amount, accountNum uint32) error {
	configInfo, err := PayConfigInfo()
	if err != nil {
		logger.Error("config info err:", logger.Field("err", err))
		return err
	}
	//configInfo.NotifyUrl = "https://dev.switch.deovo.com:8004/api/v1/wxpay_refund/notice"
	err = orm.Eloquent.Create(m).Error
	//err = m.Insert()
	if err != nil {
		logger.Error("insert user open member record err:", logger.Field("err", err))
		return err
	}

	orderRefund := pay.OrderRefund{
		OutTradeNo:  outTradeNo,
		OutRefundNo: m.OpenNo,
		NotifyUrl:   configInfo.RefundNotifyUrl,
		Amount: pay.OrderRefundAmount{
			Refund:   amount,
			Total:    amount,
			Currency: "CNY",
		},
	}
	if accountNum == 2 { // 迪为帐户
		orderRefund.NotifyUrl = configInfo.DwRefundNotifyUrl
	}
	err = pay.TransactionOrderRefund(orderRefund, accountNum)
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return err
	}

	return nil
}

func (m *UserOpenMemberRecord) MallGoodsOrderRefund(outTradeNo string, accountNum uint32) error {
	if m.GoodsOrder == nil {
		return errors.New("goods order is nil")
	}
	if m.OpenNo == "" {
		m.OpenNo = GetOrderSn()
	}
	m.Uid = m.GoodsOrder.Uid
	m.OrderId = m.GoodsOrder.ID

	err := m.Refund(outTradeNo, m.GoodsOrder.Rm, accountNum)
	if err != nil {
		logger.Error("refund err:", logger.Field("err", err))
		return err
	}

	return nil
}

func GetOrderSn() string {
	var orderSn string
	for {
		//orderSn = utils.GetSerialNo32HEXString()
		orderSn = utils.GenSerialNo()
		var count int64
		err := orm.Eloquent.Table("user_open_member_record").Where("open_no=?", orderSn).Count(&count)
		//count, err := NewUserOpenMemberRecordQuerySet(DB).OpenNoEq(orderSn).Total()
		if err != nil {
			logger.Error("err:", logger.Field("err", err))
		}
		if count == 0 {
			break
		}
	}
	return orderSn
}

func (m *OperationLog) AddLog() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("recover err:", logger.Field("err", err))
		}
	}()
	go func() {
		err := orm.Eloquent.Create(m).Error
		if err != nil {
			logger.Error("create operation log err:")
		}
	}()
}

func SendMessageMemberRenewal() {
	fmt.Println("发送续费短息开始:")
	smsSend := &ExpireMemberSmsSend{
		Status:  1,
		SmsType: SmsTypeRenewCoupon,
	}

	start := TodayZero().AddDate(0, 0, GetActivityRenewalConfig().PopTrap)
	end := start.AddDate(0, 0, 1)

	var users []UserInfo
	err := orm.Eloquent.Table("user").Where("member_level IN (2,4,5)").
		Where("member_expire>?", start).Where("member_expire<?", end).Find(&users).Error
	if err != nil {
		logger.Error("cooperative err:", logger.Field("err", err))
		return
	}

	if len(users) == 0 {
		return
	}

	// 批量查询发送记录
	uids := make([]uint32, 0, len(users))
	for _, u := range users {
		uids = append(uids, u.Uid)
	}
	renewalLogs, _ := GetActionUserRenewalLogMulti(uids, UserRenewalLogSendMessage)
	renewalLogMap := make(map[uint32]UserRenewalLog, len(renewalLogs))
	for _, r := range renewalLogs {
		renewalLogMap[r.Uid] = r
	}

	for _, u := range users {
		if u.Tel == "" {
			continue
		}

		var message string
		userStore, err := GetUserBelongStore(u.Uid, u.StoreId)
		if err != nil {
			message = "【明慧科技】提醒：您的go2ns租卡会员时长仅剩余一个月，现在续费最高立减200元！赶快进入小程序领取优惠吧！~更多续约优惠也可联系咨询哦~"
		} else {
			message = fmt.Sprintf("【明慧科技】提醒：您的go2ns租卡会员时长仅剩余一个月，现在续费最高立减200元！赶快进入小程序领取优惠吧！~更多续约优惠也可联系咨询哦~（%s %s）",
				userStore.Name, userStore.Landline)
		}
		err = GtSendMessage([]string{u.Tel}, message)
		if err != nil {
			smsSend.Status = 2
			logger.Errorf("SmsSend err:", logger.Field("err", err))
		}

		// 写入续费日志
		renewalLog := &UserRenewalLog{
			Uid:          u.Uid,
			Action:       UserRenewalLogSendMessage,
			MemberExpire: *u.MemberExpire,
			Type:         0,
			Serial:       uint32(u.MemberExpire.Unix()),
		}
		v, _ := renewalLogMap[u.Uid]
		renewalLog.RenewalNum = v.RenewalNum + 1

		err = orm.Eloquent.Create(renewalLog).Error
		if err != nil {
			logger.Error("create renewal log err:", logger.Field("err", err))
		}

		// 写入发送记录
		smsSend.SendTime = time.Now()
		smsSend.Tel = u.Tel
		smsSend.Message = message
		err = orm.Eloquent.Create(&smsSend).Error
		if err != nil {
			logger.Error("create expire member sms send err:", logger.Field("err", err))
		}
	}

	fmt.Println("发送续费短息完成...")
}

func SendMessageMemberRenewalOld() {
	fmt.Println("发送续费短息开始:")
	smsSend := &ExpireMemberSmsSend{
		SendTime: time.Now(),
		Tel:      "",
		Status:   1,
		SmsType:  SmsTypeRenewCoupon,
	}

	start := TodayZero().AddDate(0, 0, GetActivityRenewalConfig().PopTrap)
	end := start.AddDate(0, 0, 1)
	var users []UserInfo
	err := orm.Eloquent.Table("user").Where("member_level IN (2,4,5)").
		Where("member_expire>?", start).Where("member_expire<?", end).Find(&users).Error
	if err != nil {
		logger.Error("cooperative err:", logger.Field("err", err))
		return
	}

	tels := make([]string, 0)
	uids := make([]uint32, 0, len(users))
	for i, _ := range users {
		if users[i].Tel != "" {
			tels = append(tels, users[i].Tel)
			fmt.Println("user:", users[i].Uid, users[i].Tel)
			uids = append(uids, users[i].Uid)
		}
	}
	if len(tels) > 0 {
		message := "【明慧科技】提醒：您的go2ns租卡会员时长仅剩余一个月，现在续费最高立减200元！赶快进入小程序领取优惠吧！~更多续约优惠也可联系咨询哦~"
		err = GtSendMessage(tels, message)
		if err != nil {
			logger.Errorf("SmsSend err:", logger.Field("err", err))
			return
		}
		//fmt.Println("tels:", tels)
		//fmt.Printf("uids:", uids)
		renewalLogs, err := GetActionUserRenewalLogMulti(uids, UserRenewalLogSendMessage)
		if err != nil {
			logger.Error("renewalLogs err:", logger.Field("err", err))
		}
		renewalLogMap := make(map[uint32]UserRenewalLog, 0)
		for i, _ := range renewalLogs {
			renewalLogMap[renewalLogs[i].Uid] = renewalLogs[i]
		}

		for i, _ := range users {
			renewalLog := &UserRenewalLog{
				Uid:          users[i].Uid,
				Action:       UserRenewalLogSendMessage,
				MemberExpire: *users[i].MemberExpire,
				Type:         0,
				Serial:       uint32(users[i].MemberExpire.Unix()),
			}

			v, _ := renewalLogMap[users[i].Uid]
			renewalLog.RenewalNum = v.RenewalNum + 1

			err = orm.Eloquent.Create(renewalLog).Error
			if err != nil {
				logger.Error("create renewal log err:", logger.Field("err", err))
			}

			// 存记录
			smsSend.Tel = users[i].Tel
			smsSend.Message = message
			err = orm.Eloquent.Create(&smsSend).Error
			if err != nil {
				logger.Error("create expire member sms send err:", logger.Field("err", err))
			}
		}
	}
	fmt.Println("发送续费短息完成...")
}

//func PayConfigInfo() (*PayConfig, error) {
//	payConfig := new(PayConfig)
//	var configAllocation Config
//	err := NewConfigQuerySet(DB).NameEq(ConfigNamePay).One(&configAllocation)
//	if err != nil {
//		logger.Error("err:",logger.Field("err",err))
//		return payConfig, err
//	}
//
//	err = json.Unmarshal([]byte(configAllocation.Value), payConfig)
//	if err != nil {
//		logger.Error("err:",logger.Field("err",err))
//		return payConfig, err
//	}
//
//	return payConfig, nil
//}

//type PayConfig struct {
//	MemberFee       uint32 `json:"member_fee"`
//	DepositFee      uint32 `json:"deposit_fee"`
//	NotifyUrl       string `json:"notify_url"`
//	RefundNotifyUrl string `json:"refund_notify_url"`
//}

type MemberStatisticDaily struct {
	Model

	MemberLevel  uint32    `json:"member_level"`
	Date         string    `json:"date"`
	DateTime     time.Time `json:"date_time"`
	Increase     int64     `json:"increase"`
	Expire       int64     `json:"expire"`
	Net          int64     `json:"net"`
	Accumulative int64     `json:"accumulative"`
	// member_statistic_daily
}

func IndexMemberStatistic() {
	fmt.Println("会员数据统计开始")
	levels := []uint32{2, 4, 5}
	today := TodayZero()
	//today, _ = time.Parse(TimeFormat, "2022-08-09 00:00:00")
	for i, _ := range levels {
		IndexMemberLevelStatistic(levels[i], today)
	}
	fmt.Println("会员数据统计完成...")
}

func IndexMemberLevelStatistic(level uint32, date time.Time) {
	var (
		increase, expire, net, accumulative, origination int64
	)
	startDate := date.AddDate(0, 0, -1)
	endDate := date
	err := orm.Eloquent.Table("user").Where("member_level=?", level).
		Where("open_member_time>?", startDate).
		Where("open_member_time<?", endDate).Count(&increase).Error
	if err != nil {
		logger.Error("increase err:", logger.Field("err", err))
	}
	err = orm.Eloquent.Table("user").Where("member_level=?", level).
		Where("member_expire>?", startDate).
		Where("member_expire<?", endDate).Count(&expire).Error
	if err != nil {
		logger.Error("increase err:%#v", logger.Field("err", err))
	}
	//// TODO
	//var statisticDaily MemberStatisticDaily
	//err = orm.Eloquent.Table("member_statistic_daily").Where("member_level=?", level).
	//	//Where("open_member_time>?", time.Time{}).
	//	Where("date=?", startDate.AddDate(0, 0, -1).Format(DateFormat)).
	//	Find(&statisticDaily).Error
	//if err != nil {
	//	logger.Error("increase err:",logger.Field("err",err))
	//}
	//fmt.Println("increase:", increase)
	//fmt.Println("expire:", expire)
	memberRecordType := 0
	if level == 2 {
		memberRecordType = 4
	} else if level == 4 {
		memberRecordType = 5
	} else if level == 5 {
		memberRecordType = 6
	}
	if memberRecordType != 0 {
		err = orm.Eloquent.Table("user_member_record").Where("type=?", memberRecordType).
			Where("created_at>?", startDate).Where("created_at<?", endDate).Count(&origination).Error
		if err != nil {
			logger.Error("origination err:", logger.Field("err", err))
		}
	}
	increase += origination

	net = increase - expire
	//accumulative = statisticDaily.Accumulative + increase

	err = orm.Eloquent.Table("user").Where("member_level=?", level).
		Where("member_expire>?", time.Now()).Count(&accumulative).Error
	if err != nil {
		logger.Error("increase err:%#v", logger.Field("err", err))
	}

	fmt.Println("net:", net)
	daily := &MemberStatisticDaily{
		MemberLevel:  level,
		Date:         startDate.Format(DateFormat),
		DateTime:     startDate,
		Increase:     increase,
		Expire:       expire,
		Net:          net,
		Accumulative: accumulative,
	}

	err = orm.Eloquent.Create(&daily).Error
	if err != nil {
		logger.Error("create member statistic daily err:", logger.Field("err", err))
	}

}

type MemberStatisticDailyListReq struct {
	MemberLevel uint32 `json:"member_level"`
	//StartDate   string `json:"start_date"`
	//EndDate     string `json:"end_date"`
	StartDate time.Time `json:"start_date"`
	EndDate   time.Time `json:"end_date"`
	Days      uint32    `json:"days"`
	IsExport  uint32    `json:"is_export"` // 1-导出
	PageNum   int       `json:"pageIndex"`
	PageSize  int       `json:"pageSize"`
}

type MemberStatisticDailyListRsp struct {
	Count     int64                  `json:"count"`
	List      []MemberStatisticDaily `json:"list"`
	PageIndex int                    `json:"pageIndex"`
	Url       string                 `json:"url"`
}

func (m *MemberStatisticDailyListReq) List() (*MemberStatisticDailyListRsp, error) {
	rsp := &MemberStatisticDailyListRsp{
		PageIndex: m.PageNum,
	}
	m.PageNum = m.PageNum - 1
	if m.PageNum < 0 {
		m.PageNum = 0
	}
	if m.Days > 0 {
		m.PageSize = int(m.Days)
	}

	qs := orm.Eloquent.Table("member_statistic_daily")
	//if m.StartDate != "" {
	//	start, _ := time.Parse(DateTimeFormat, m.StartDate)
	//	qs = qs.Where("date_time>=?", start)
	//}
	//if m.EndDate != "" {
	//	end, _ := time.Parse(DateTimeFormat, m.EndDate)
	//	qs = qs.Where("date_time<=?", end)
	//}
	if !m.StartDate.IsZero() {
		qs = qs.Where("date_time>=?", m.StartDate)
	}
	if !m.EndDate.IsZero() {
		qs = qs.Where("date_time<=?", m.EndDate)
	}
	if m.Days > 0 {
		//end := TodayZero()
		//start := end.AddDate(0, 0, int(m.Days)*(-1))
		qs = qs.Where("date_time>=?", m.StartDate)
		qs = qs.Where("date_time<=?", m.EndDate)
	}
	if m.MemberLevel != 0 {
		qs = qs.Where("member_level=?", m.MemberLevel)
	}
	var dailys []MemberStatisticDaily
	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Error("count err:", logger.Field("err", err))
		return rsp, err
	}
	rsp.Count = count
	//err = qs.Order("id DESC").Offset(m.PageNum * m.PageSize).Limit(m.PageSize).Find(&dailys).Error
	if m.IsExport == 1 {
		err = qs.Order("date_time DESC").Find(&dailys).Error
		if err != nil && err != RecordNotFound {
			logger.Error("dailys err:", logger.Field("err", err))
			return rsp, err
		}
		listExport, err := MemberStatisticDailyListExport(dailys)
		if err != nil {
			logger.Error("list export err:", logger.Field("err", err))
		}
		rsp.Url = listExport
	} else {
		err = qs.Order("date_time DESC").Offset(m.PageNum * m.PageSize).Limit(m.PageSize).Find(&dailys).Error
		if err != nil && err != RecordNotFound {
			logger.Error("dailys err:", logger.Field("err", err))
			return rsp, err
		}
		rsp.List = dailys
	}

	return rsp, nil
}

func MemberStatisticDailyListExport(dailys []MemberStatisticDaily) (string, error) {
	file := excelize.NewFile()
	streamWriter, err := file.NewStreamWriter("Sheet1")
	if err != nil {
		fmt.Println(err)
	}

	//url := "http://39.108.188.218:8000/img/export/"

	fileName := "会员统计" + time.Now().Format("2006-01-02 15:04:05") + ".xlsx"

	title := []interface{}{"时间", "新增会员数", "会员过期数", "净增会员数", "累计会员数"}
	cell, _ := excelize.CoordinatesToCellName(1, 1)
	if err = streamWriter.SetRow(cell, title); err != nil {
		fmt.Println(err)
	}
	var row []interface{}
	for rowId := 0; rowId < len(dailys); rowId++ {
		row = []interface{}{dailys[rowId].Date, dailys[rowId].Increase, dailys[rowId].Expire, dailys[rowId].Net, dailys[rowId].Accumulative}
		cell, _ := excelize.CoordinatesToCellName(1, rowId+2)
		if err := streamWriter.SetRow(cell, row); err != nil {
			fmt.Println(err)
		}
	}
	if err := streamWriter.Flush(); err != nil {
		fmt.Println(err)
	}
	if err := file.SaveAs("/www/server/images/export/" + fileName); err != nil {
		fmt.Println(err)
	}
	return config.ExportConfig.Url + fileName, nil
}

func UserInviteRecordListSetAssistantName(records []UserInviteRecord) {
	uids := make([]uint32, 0, len(records))
	for i, _ := range records {
		if records[i].ShopAssistantName == "" {
			uids = append(uids, records[i].FromUid)
		}
	}

	infoMap, err := GetUserInfoMap(uids)
	if err != nil {
		logger.Error("info map err:", logger.Field("err", err))
	}

	for i, _ := range records {
		v, ok := infoMap[records[i].FromUid]
		if ok && records[i].ShopAssistantName == "" {
			records[i].ShopAssistantName = v.ShopAssistantName
		}
	}
}

type ExpireMemberSmsSendListReq struct {
	Status    uint32    `json:"status"`     // 1-待发送 2-已发送
	Tel       string    `json:"tel"`        // 用户手机号
	SmsType   uint32    `json:"sms_type"`   // 1-续费优惠；2-续费；3-还卡
	StartTime time.Time `json:"start_time"` // 开始时间
	EndTime   time.Time `json:"end_time"`   // 结束时间
	PageIndex int       `json:"pageIndex"`
	PageSize  int       `json:"pageSize"`
}
type ExpireMemberSmsSendListResp struct {
	List      []ExpireMemberSmsSend `json:"list"`
	Total     int                   `json:"total"`     // 总条数
	PageIndex int                   `json:"pageIndex"` // 页码
	PageSize  int                   `json:"pageSize"`  // 每页展示条数
}

func (m *ExpireMemberSmsSendListReq) List() (*ExpireMemberSmsSendListResp, error) {
	resp := &ExpireMemberSmsSendListResp{
		PageIndex: m.PageIndex,
		PageSize:  m.PageSize,
	}
	qs := orm.Eloquent.Table("expire_member_sms_send")
	if m.Status != 0 {
		qs = qs.Where("status=?", m.Status)
	}
	if m.Tel != "" {
		qs = qs.Where("tel LIKE '%" + m.Tel + "%'")
	}
	if m.SmsType != 0 {
		qs = qs.Where("sms_type = ?", m.SmsType)
	}
	if !m.StartTime.IsZero() {
		qs = qs.Where("send_time > ?", m.StartTime)
	}
	if !m.EndTime.IsZero() {
		parse := m.EndTime.AddDate(0, 0, 1)
		qs = qs.Where("send_time < ?", parse)
	}
	page := m.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}

	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Error("count err:", logger.Field("err", err))
		return resp, err
	}
	resp.Total = int(count)

	var smsSends []ExpireMemberSmsSend
	err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&smsSends).Error
	if err != nil && err != RecordNotFound {
		logger.Error("err:", logger.Field("err", err))
		return resp, err
	}
	resp.List = smsSends

	return resp, nil
}

//func (m *MemberStatisticDailyListReq) Export() (string, error) {
//	qs := orm.Eloquent.Table("member_statistic_daily")
//	if !m.StartDate.IsZero() {
//		qs = qs.Where("date_time>=?", m.StartDate)
//	}
//	if !m.EndDate.IsZero() {
//		qs = qs.Where("date_time<=?", m.EndDate)
//	}
//	if m.Days > 0 {
//		qs = qs.Where("date_time>=?", m.StartDate)
//		qs = qs.Where("date_time<=?", m.EndDate)
//	}
//	if m.MemberLevel != 0 {
//		qs = qs.Where("member_level=?", m.MemberLevel)
//	}
//	var dailys []MemberStatisticDaily
//	err := qs.Order("date_time DESC").Find(&dailys).Error
//	if err != nil && err != RecordNotFound {
//		logger.Error("dailys err:",logger.Field("err",err))
//		return "", err
//	}
//
//	file := excelize.NewFile()
//	streamWriter, err := file.NewStreamWriter("Sheet1")
//	if err != nil {
//		fmt.Println(err)
//	}
//
//	url := "http://39.108.188.218:8000/img/export/"
//	fileName := "/www/server/images/export/" + "会员统计" + time.Now().Format("2006-01-02 15:04:05") + ".xlsx"
//
//	title := []interface{}{"时间", "新增会员数", "会员过期数", "净增会员数", "累计会员数"}
//	cell, _ := excelize.CoordinatesToCellName(1, 1)
//	if err = streamWriter.SetRow(cell, title); err != nil {
//		fmt.Println(err)
//	}
//	var row []interface{}
//	for rowId := 0; rowId < len(dailys); rowId++ {
//		row = []interface{}{dailys[rowId].Date, dailys[rowId].Increase, dailys[rowId].Expire, dailys[rowId].Net, dailys[rowId].Accumulative}
//		cell, _ := excelize.CoordinatesToCellName(1, rowId+2)
//		if err := streamWriter.SetRow(cell, row); err != nil {
//			fmt.Println(err)
//		}
//	}
//	if err := streamWriter.Flush(); err != nil {
//		fmt.Println(err)
//	}
//	if err := file.SaveAs(fileName); err != nil {
//		fmt.Println(err)
//	}
//	return url + fileName, nil
//}

func MarkUser(uid []uint32, mark int8) error {
	return orm.Eloquent.Table("user").
		Where("uid in (?)", uid).
		Update("mark", mark).Error
}

// CheckPhoneExt 检测手机尾号是否一致
func (m *UserInfo) CheckPhoneExt(ext string, length int) bool {
	if ext == "" || m.Tel == "" {
		return false
	}

	total := len(m.Tel)
	if total >= length {
		sub := m.Tel[total-4:]
		return sub == ext
	} else {
		return false
	}
}

type TelListReq struct {
	PhoneNum  string `json:"phone_num" binding:"required"`
	PageIndex int    `json:"pageIndex"` // 页码
	PageSize  int    `json:"pageSize"`  // 页面条数
}

type TelListResp struct {
	List      []UserInfo `json:"list"`
	Total     int        `json:"total"`     // 总条数
	PageIndex int        `json:"pageIndex"` // 页码
	PageSize  int        `json:"pageSize"`  // 每页展示条数
}

func (m *TelListReq) GetTelList() (*TelListResp, error) {
	resp := &TelListResp{
		PageIndex: m.PageIndex,
		PageSize:  m.PageSize,
	}
	page := m.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}

	var count int64
	qs := orm.Eloquent.Table("user").Where("tel like ?", "%"+m.PhoneNum+"%")
	qs = qs.Where("member_level in (?)",
		[]uint32{MemberLevelUser, MemberLevelGold, MemberLevelPeriod, MemberLevelPlatinum, MemberLevelBlackGold})
	err := qs.Count(&count).Error
	if err != nil {
		logger.Error("count err:", logger.Field("err", err))
		return nil, err
	}

	var userInfo []UserInfo
	err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&userInfo).Error
	if err != nil {
		logger.Error("find err:", logger.Field("err", err))
		return nil, err
	}

	resp.List = userInfo

	//跟之前保持一致
	resp.Total = int(count)
	resp.PageIndex = page + 1
	resp.PageSize = m.PageSize

	return resp, nil
}

// UpdateExpireMemberLevel 更新过期用户的当前会员等级
func UpdateExpireMemberLevel() {
	var users []UserInfo
	err := orm.Eloquent.Table("user").Where("member_expire < ?", time.Now()).
		Where("member_level in (?)", []uint32{2, 3, 4, 5}).Find(&users).Error
	if err != nil {
		logger.Error(err.Error())
		return
	}

	if len(users) == 0 {
		logger.Info("UpdateExpireMemberLevel users is null")
		return
	}

	for i, _ := range users {
		if err = orm.Eloquent.Model(&UserInfo{}).Where("id = ?", users[i].ID).Updates(map[string]interface{}{
			"member_level": MemberLevelUser,
			"updated_at":   time.Now(),
		}).Error; err != nil {
			logger.Errorf("UpdateExpireMemberLevel err,", err.Error())
			continue
		}
	}
}

// UpdateExpirePrivilegeMemberLevel 更新过期尊享会员等级
func UpdateExpirePrivilegeMemberLevel() {
	var users []PrivilegeMember
	err := orm.Eloquent.Table("privilege_member").Where("member_expire < ?", time.Now()).
		Where("member_level = ?", MemberLevelPrivilege).Find(&users).Error
	if err != nil {
		logger.Error(err.Error())
		return
	}

	if len(users) == 0 {
		logger.Info("UpdateExpirePrivilegeMemberLevel users is null")
		return
	}

	for i, _ := range users {
		if err = orm.Eloquent.Model(&PrivilegeMember{}).Where("id = ?", users[i].ID).Updates(map[string]interface{}{
			"member_level": MemberLevelUser,
			"updated_at":   time.Now(),
		}).Error; err != nil {
			logger.Errorf("UpdateExpirePrivilegeMemberLevel err,", err.Error())
			continue
		}
	}
}

// UpdateExpireUserVm 扣减用户过期积分
func UpdateExpireUserVm() {
	var userVmRecords []UserVmRecord

	// 查找需要处理的用户积分记录
	err := orm.Eloquent.Table("user_vm_record").
		Where("`alter` > 0 AND `alter` != `used_vm` AND `expiry_date` IS NOT NULL AND `expiry_date` < ?", time.Now()).
		Find(&userVmRecords).Error
	if err != nil {
		log.Printf("Failed to query user_vm_records: %v", err)
		return
	}

	for _, record := range userVmRecords {
		// 计算需要扣除的积分
		pointsToDeduct := record.Alter - record.UsedVm

		if pointsToDeduct > 0 {
			// 更新 UserVm 表，防止 vm 变为负值，并更新 updated_at 字段
			sql := `
				UPDATE user_vm 
				SET vm = IF(vm - ? >= 0, vm - ?, 0), updated_at = ?
				WHERE uid = ?
			`
			err = orm.Eloquent.Exec(sql, pointsToDeduct, pointsToDeduct, time.Now(), record.Uid).Error
			if err != nil {
				log.Printf("Failed to update user_vm for uid %d: %v", record.Uid, err)
				continue
			}

			// 更新原有的 UserVmRecord，更新 used_vm 的值为 alter
			err = orm.Eloquent.Table("user_vm_record").Where("id=?", record.ID).
				Updates(map[string]interface{}{
					"used_vm":    record.Alter,
					"updated_at": time.Now(),
				}).Error
			if err != nil {
				log.Printf("Failed to update user_vm_record (used_vm) for record id %d: %v", record.ID, err)
				continue
			}

			// 创建新的 UserVmRecord 记录扣除过期积分
			newRecord := UserVmRecord{
				Uid:      record.Uid,
				BeforeVm: record.AfterVm,
				AfterVm:  record.AfterVm - uint32(pointsToDeduct),
				Alter:    -pointsToDeduct,
				Event:    VmEventExpired,
				Describe: "积分过期扣减",
				BillSn:   record.BillSn,
			}

			err = orm.Eloquent.Table("user_vm_record").Create(&newRecord).Error
			if err != nil {
				log.Printf("Failed to create new user_vm_record for uid %d: %v", record.Uid, err)
			}
		}
	}
}

// GetUserInfoByTel 通过手机号获取用户信息
func GetUserInfoByTel(tel string) (UserInfo, error) {
	var userInfo UserInfo
	err := orm.Eloquent.Table("user").Where("tel = ?", tel).Find(&userInfo).Error
	if err != nil {
		logger.Error("err:", logger.Field("err", err))
		return userInfo, err
	}

	return userInfo, nil
}

// CreateUid 找一个可以用的Uid
func CreateUid() uint32 {
	for {
		uid := utils.GenUid()
		var count int64
		if err := orm.Eloquent.Table("user").Where("uid = ?", uid).Count(&count).Error; err == nil && count > 0 {
			continue
		}
		return uid
	}
}

// IsInMemberLevels 判断用户是不是会员
func IsInMemberLevels(memberLevel uint32) bool {
	if memberLevel == MemberLevelUser || memberLevel == MemberLevelGold || memberLevel == MemberLevelPeriod ||
		memberLevel == MemberLevelPlatinum || memberLevel == MemberLevelBlackGold {
		return true
	}
	return false
}

// PrivilegeMember 零售尊享会员
type PrivilegeMember struct {
	Model
	Uid            uint32     `json:"uid" gorm:"column:uid;unique_index"` // 用户id
	Tel            string     `json:"tel"`                                // 电话
	StoreId        uint64     `json:"store_id"`                           // 门店id
	MemberLevel    uint32     `json:"member_level"`                       // 当前会员等级:1-普通用户，6-尊享会员
	MemberExpire   *time.Time `json:"member_expire"`                      // 会员到期时间
	OpenMemberTime *time.Time `json:"open_member_time"`                   // 开通会员时间
	ExtendStatus   uint32     `json:"extend_status"`                      // 延保状态:0-非会员, 1-已过期，2-待激活、3-已激活
	HostCode       string     `json:"host_code"`                          // 主机编码
	Images         string     `json:"images"`                             // 图片凭证
	AuditorId      uint32     `json:"auditor_id" gorm:"index"`            // 审核人id
	AuditorName    string     `json:"auditor_name"`                       // 审核人姓名
	AuditTime      *time.Time `json:"audit_time"`                         // 审核时间
	Remark         string     `json:"remark"`                             // 备注
	Store          *Store     `json:"store" gorm:"-"`                     // 门店信息
}

// PrivilegeMemberListReq 查询零售尊享会员列表入参
type PrivilegeMemberListReq struct {
	Uid               uint32   `json:"uid"`                 // 用户ID
	Tel               string   `json:"tel"`                 // 手机号
	HostCode          string   `json:"host_code"`           // 主机编码
	StoreId           []uint32 `json:"store_id"`            // 门店列表（支持复选）
	MemberLevel       uint32   `json:"member_level"`        // 当前会员等级
	AuditorId         uint32   `json:"auditor_id"`          // 审核人
	ExtendStatus      uint32   `json:"extend_status"`       // 延保状态
	OpenMemberStart   string   `json:"open_member_start"`   // 首次开通尊享会员-开始时间
	OpenMemberEnd     string   `json:"open_member_end"`     // 首次开通尊享会员-结束时间
	MemberExpireStart string   `json:"member_expire_start"` // 尊享会员到期时间-开始时间
	MemberExpireEnd   string   `json:"member_expire_end"`   // 尊享会员到期时间-结束时间
	AuditTimeStart    string   `json:"audit_time_start"`    // 审核开始时间
	AuditTimeEnd      string   `json:"audit_time_end"`      // 审核结束时间
	IsExport          uint32   `json:"is_export"`           // 1-导出excel
	PageIndex         int      `json:"pageIndex"`           // 页码
	PageSize          int      `json:"pageSize"`            // 页面条数
}

// PrivilegeMemberListResp 查询零售尊享会员列表出参
type PrivilegeMemberListResp struct {
	Total     int64             `json:"total"`      // 总条数
	PageIndex int               `json:"pageIndex"`  // 页码
	PageSize  int               `json:"pageSize"`   // 页面条数
	ExportUrl string            `json:"export_url"` // 导出excel路径
	List      []PrivilegeMember `json:"list"`       // 零售尊享会员信息
}

func (m *PrivilegeMemberListReq) PrivilegeMemberList(c *gin.Context) (*PrivilegeMemberListResp, error) {
	// 非管理员才判断所属门店
	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		sysUser, err := GetSysUserByCtx(c)
		if err != nil {
			return nil, errors.New("操作失败:" + err.Error())
		}

		// 返回sysUser未过期的门店id列表
		storeList := GetValidStoreIDs(sysUser.StoreData)
		if len(storeList) > 0 {
			m.StoreId = CompareLists(storeList, m.StoreId)
			if len(m.StoreId) == 0 { // 没有匹配的数据，表示入参门店不是用户有权限的门店
				return &PrivilegeMemberListResp{}, nil
			}
			m.StoreId = append(m.StoreId, 0)
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}

	page := m.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}
	resp := &PrivilegeMemberListResp{
		PageIndex: page + 1,
		PageSize:  m.PageSize,
	}
	var memberList []PrivilegeMember
	qs := orm.Eloquent.Model(&PrivilegeMember{}).Debug()

	if m.Uid != 0 {
		qs = qs.Where("uid = ?", m.Uid)
	}
	if m.Tel != "" {
		qs = qs.Where("tel = ?", m.Tel)
	}
	if m.HostCode != "" {
		qs = qs.Where("host_code = ?", m.HostCode)
	}
	if len(m.StoreId) != 0 {
		if len(m.StoreId) == 1 {
			qs = qs.Where("store_id = ?", m.StoreId[0])
		} else {
			qs = qs.Where("store_id IN (?)", m.StoreId)
		}
	}
	if m.MemberLevel != 0 {
		qs = qs.Where("member_level = ?", m.MemberLevel)
	}
	if m.AuditorId != 0 {
		qs = qs.Where("auditor_id = ?", m.AuditorId)
	}
	if m.ExtendStatus != 0 {
		qs = qs.Where("extend_status = ?", m.ExtendStatus)
	}
	if m.OpenMemberStart != "" {
		parse, err := time.Parse(QueryTimeFormat, m.OpenMemberStart)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("open_member_time > ?", parse)
	}
	if m.OpenMemberEnd != "" {
		parse, err := time.Parse(QueryTimeFormat, m.OpenMemberEnd)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("open_member_time < ?", parse)
	}
	if m.MemberExpireStart != "" {
		parse, err := time.Parse(QueryTimeFormat, m.MemberExpireStart)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("member_expire > ?", parse)
	}
	if m.MemberExpireEnd != "" {
		parse, err := time.Parse(QueryTimeFormat, m.MemberExpireEnd)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("member_expire < ?", parse)
	}
	if m.AuditTimeStart != "" {
		parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("audit_time > ?", parse)
	}
	if m.AuditTimeEnd != "" {
		parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
		if err != nil {
			logger.Errorf("err:", logger.Field("err", err))
			return nil, err
		}
		qs = qs.Where("audit_time < ?", parse)
	}

	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Error("count err:", logger.Field("err", err))
		return nil, err
	}

	if m.IsExport == 1 { // 导出excel
		err = qs.Order("id DESC").Find(&memberList).Error
		if err != nil && err != RecordNotFound {
			logger.Error("err:", logger.Field("err", err))
			return nil, err
		}
	} else {
		err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&memberList).Error
		if err != nil && err != RecordNotFound {
			logger.Error("err:", logger.Field("err", err))
			return nil, err
		}
	}

	// 查询门店信息
	storeList := make(map[uint32]Store)
	storeList = GetStoreMap()

	for i, u := range memberList {
		if u.StoreId == 0 {
			continue
		}
		// 添加门店信息
		store := storeList[uint32(u.StoreId)]
		memberList[i].Store = &store

		// 校验时间，如果为01-01-01 08:05，则赋值为空
		validateZeroTime(&memberList[i].AuditTime)
	}

	if m.IsExport == 1 {
		fileName, err := PrivilegeMemberExport(memberList, c)
		if err != nil {
			logger.Error("err:", logger.Field("err", err))
			return nil, err
		}
		resp.ExportUrl = fileName
	} else {
		resp.List = memberList
		resp.Total = count
		resp.PageSize = m.PageSize
		resp.PageIndex = m.PageIndex
	}

	return resp, nil
}

// PrivilegeMemberExport 尊享会员导出excel
func PrivilegeMemberExport(list []PrivilegeMember, c *gin.Context) (string, error) {
	file := excelize.NewFile()
	fSheet := "Sheet1"

	url := config.ExportConfig.Url
	fileName := time.Now().Format(TimeFormat) + "零售尊享会员" + ".xlsx"
	fmt.Println("url fileName:", url+fileName)

	// 判断是否有权限
	flag1, _ := checkRoleMenu(c, PrivilegeMemberMenu)

	nEndCount := 0
	title := []interface{}{"用户ID"}
	if flag1 { // 手机号
		title = append(title, "手机号")
		nEndCount += 1
	}

	title = append(title, "所属门店", "当前会员等级", "首次开通尊享会员时间", "尊享会员到期时间", "延保状态",
		"主机编码", "审核人", "审核时间")
	for i, _ := range title {
		cell, _ := excelize.CoordinatesToCellName(1+i, 1)
		err := file.SetCellValue(fSheet, cell, title[i])
		if err != nil {
			logger.Error("file set value err:", logger.Field("err", err))
		}
	}

	var row []interface{}
	nExcelStartRow := 0

	// 查询门店信息
	var storeList []Store
	err := orm.Eloquent.Table("store").Find(&storeList).Error
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return "", err
	}
	storeMap := make(map[uint32]string, 0)
	for i, _ := range storeList {
		storeMap[storeList[i].ID] = storeList[i].Name
	}
	fmt.Println("storeMap is:", storeMap)

	for i := 0; i < len(list); i++ {
		var strExtendStatus string
		switch list[i].ExtendStatus {
		case 1:
			strExtendStatus = "已过期"
		case 2:
			strExtendStatus = "待激活"
		case 3:
			strExtendStatus = "已激活"
		default:
			strExtendStatus = ""
		}

		row = []interface{}{
			list[i].Uid, // 用户ID
		}
		// 控制是否导出
		if flag1 { // 手机号
			row = append(row, list[i].Tel)
		}

		row = append(row, storeMap[uint32(list[i].StoreId)])                        // 所属门店
		row = append(row, getMemberLevelChineseDescription(list[i].MemberLevel))    // 当前会员等级
		row = append(row, tools.ConvertTimeToStringByPoint(list[i].OpenMemberTime)) // 首次开通尊享会员时间
		row = append(row, tools.ConvertTimeToStringByPoint(list[i].MemberExpire))   // 尊享会员到期时间
		row = append(row, strExtendStatus)                                          // 延保状态
		row = append(row, list[i].HostCode)                                         // 主机编码
		row = append(row, list[i].AuditorName)                                      // 审核人
		row = append(row, tools.ConvertTimeToStringByPoint(list[i].AuditTime))      // 审核时间

		for j, _ := range row {
			cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
			err = file.SetCellValue(fSheet, cell, row[j])
			if err != nil {
				logger.Error("file set value err:", logger.Field("err", err))
			}
		}
		nExcelStartRow++
	}

	// 设置所有单元格的样式: 居中、加边框
	style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
	"border":[{"type":"left","color":"000000","style":1},
	{"type":"top","color":"000000","style":1},
	{"type":"right","color":"000000","style":1},
	{"type":"bottom","color":"000000","style":1}]}`)

	// 设置单元格的样式: 居中、加边框、自动换行
	style1, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center","wrap_text":true},
	"border":[{"type":"left","color":"000000","style":1},
	{"type":"top","color":"000000","style":1},
	{"type":"right","color":"000000","style":1},
	{"type":"bottom","color":"000000","style":1}]}`)

	var endRow string
	switch nEndCount {
	case 1:
		endRow = fmt.Sprintf("J"+"%d", nExcelStartRow+1)
		// 应用样式到整个表格
		file.SetColWidth("Sheet1", "A", "A", 12)
		file.SetColWidth("Sheet1", "B", "B", 15)
		file.SetColWidth("Sheet1", "C", "C", 30)
		file.SetColWidth("Sheet1", "D", "D", 18)
		file.SetColWidth("Sheet1", "F", "E", 18)
		file.SetColWidth("Sheet1", "F", "F", 18)
		file.SetColWidth("Sheet1", "G", "G", 15)
		file.SetColWidth("Sheet1", "H", "H", 18)
		file.SetColWidth("Sheet1", "I", "I", 15)
		file.SetColWidth("Sheet1", "J", "J", 18)
		_ = file.SetCellStyle("Sheet1", "A1", "J1", style1)
	default:
		endRow = fmt.Sprintf("I"+"%d", nExcelStartRow+1)
		// 应用样式到整个表格
		file.SetColWidth("Sheet1", "A", "A", 12)
		file.SetColWidth("Sheet1", "B", "B", 30)
		file.SetColWidth("Sheet1", "C", "C", 18)
		file.SetColWidth("Sheet1", "D", "D", 18)
		file.SetColWidth("Sheet1", "F", "E", 18)
		file.SetColWidth("Sheet1", "F", "F", 15)
		file.SetColWidth("Sheet1", "G", "G", 18)
		file.SetColWidth("Sheet1", "H", "H", 15)
		file.SetColWidth("Sheet1", "I", "I", 18)
		_ = file.SetCellStyle("Sheet1", "A1", "I1", style1)
	}

	_ = file.SetCellStyle("Sheet1", "A2", endRow, style)

	fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
	if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
		fmt.Println(err)
	}
	return url + fileName, nil
}

type ActivateExtendedWarrantyReq struct {
	Uid      uint32 `json:"uid" binding:"required"`       // 用户ID
	HostCode string `json:"host_code" binding:"required"` // 主机编码
	Images   string `json:"images" binding:"required"`    // 图片凭证
	Remark   string `json:"remark"`                       // 备注
}

func (m *ActivateExtendedWarrantyReq) ActivateExtendedWarranty(c *gin.Context) error {
	sysUser, err := GetSysUserByCtx(c)
	if err != nil {
		logger.Errorf("err:%#v", err)
		return err
	}

	var userStoreId uint64
	// 查询用户尊享会员记录
	var memberInfo PrivilegeMember
	err = orm.Eloquent.Model(&PrivilegeMember{}).Debug().Where("uid = ?", m.Uid).Find(&memberInfo).Error
	if err != nil {
		return err
	}
	if memberInfo.StoreId == 0 {
		// 获取店员有效门店
		storeInfo, _ := GetUserEffectiveStore(uint32(sysUser.Uid))
		if len(storeInfo) != 0 {
			userStoreId = uint64(storeInfo[0].StoreID)
		}
	} else {
		userStoreId = memberInfo.StoreId
	}

	err = orm.Eloquent.Table("privilege_member").Where("uid = ?", m.Uid).Updates(map[string]interface{}{
		"store_id":      userStoreId,
		"extend_status": ExtendEffectivity,
		"host_code":     m.HostCode,
		"images":        m.Images,
		"remark":        m.Remark,
		"audit_time":    time.Now(),
		"auditor_name":  sysUser.NickName,
		"auditor_id":    sysUser.UserId,
		"updated_at":    time.Now(),
	}).Error
	if err != nil {
		logger.Error("order err:", logger.Field("err", err))
		return err
	}

	return nil
}

type CancelPrivilegeMembersReq struct {
	Uid uint32 `json:"uid" binding:"required"` // 用户ID
}

func (m *CancelPrivilegeMembersReq) CancelPrivilegeMembers() (*PrivilegeMember, error) {
	var userInfo PrivilegeMember
	err := orm.Eloquent.Table("privilege_member").Where("uid", m.Uid).Find(&userInfo).Error
	if err != nil {
		logger.Errorf("err:", logger.Field("err", err))
		return nil, err
	}

	if userInfo.MemberLevel != MemberLevelPrivilege {
		logger.Errorf("err:", logger.Field("err", "用户不是尊享会员"), logger.Field("uid", m.Uid))
		return nil, errors.New("取消失败，用户不是尊享会员")
	}

	nowTime := time.Now()
	userInfo.MemberLevel = MemberLevelUser
	userInfo.MemberExpire = &nowTime
	userInfo.ExtendStatus = ExtendExpire

	begin := orm.Eloquent.Begin()
	sql := fmt.Sprintf("UPDATE `privilege_member` SET member_level = 1,member_expire=?,updated_at=?,extend_status=1 WHERE uid = ?;")
	err = begin.Exec(sql, nowTime, nowTime, m.Uid).Error
	if err != nil {
		begin.Rollback()
		logger.Errorf("err:", logger.Field("err", err))
		return nil, err
	}

	//var userInvite UserInvite
	//orm.Eloquent.Table("user_invite").Where("to_uid=?", m.Uid).Where("spend_type=2").
	//	Order("id DESC").Limit(1).Find(&userInvite)
	//sqlInvite := fmt.Sprintf("UPDATE user_invite SET member_status=3,action=1,spend_type=1 WHERE id= ? ;")
	//err = orm.Eloquent.Exec(sqlInvite, userInvite.ID).Error
	//if err != nil {
	//	logger.Errorf("err:", logger.Field("err", err))
	//	return nil, err
	//}

	// 修改尊享会员优惠券，改为过期状态
	var userCoupon []UserCoupon
	err = orm.Eloquent.Table("user_coupon").Where("uid = ? and activity_id = 6", m.Uid).Find(&userCoupon).Error
	if err != nil || err == RecordNotFound {
		logger.Errorf("err:", logger.Field("err", err))
	}

	for i, _ := range userCoupon {
		if userCoupon[i].State == 1 { // 只更新未使用的优惠券
			err = begin.Table("user_coupon").Where("id = ?", userCoupon[i].ID).Updates(map[string]interface{}{
				"state":      3,
				"updated_at": time.Now(),
			}).Error
			if err != nil {
				begin.Rollback()
				logger.Error("UpdateCoupon err:", logger.Field("err", err))
				return nil, err
			}
		}
	}

	// 更新用户积分
	err = UserVmUpdate(begin, "", uint32(m.Uid), -199, VmEventCancelPrivilegeMember,
		"取消尊享会员")
	if err != nil {
		begin.Rollback()
		logger.Errorf("err:", err)
		return nil, err
	}

	err = begin.Commit().Error
	if err != nil {
		begin.Rollback()
		logger.Error("CancelPrivilegeMember err:", logger.Field("err", err))
		return nil, err
	}

	return &userInfo, nil
}

// GetUserType 获取会员类别：1-普通会员 2-黄金会员 4-白金会员 5-黑金会员 6-尊享会员 7-黄金&尊享 8-白金&尊享 9-黑金&尊享
func GetUserType(uid int) (int, error) {
	userType := 1 // 默认普通会员

	// 获取尊享会员信息
	var privilegeUserInfo PrivilegeMember
	if err := orm.Eloquent.Table("privilege_member").Where("uid = ?", uid).Find(&privilegeUserInfo).Error; err != nil {
		logger.Errorf("获取尊享会员信息出错:", logger.Field("err", err))
		return userType, err
	}

	// 获取用户信息
	var userInfo UserInfo
	if err := orm.Eloquent.Table("user").Where("uid = ?", uid).Find(&userInfo).Error; err != nil {
		logger.Errorf("获取用户信息出错:", logger.Field("err", err))
		return userType, err
	}

	// 判断用户类别
	switch userInfo.MemberLevel {
	case MemberLevelGold, MemberLevelPeriod: // 黄金会员或短期会员
		userType = 2
	case MemberLevelPlatinum: // 白金会员
		userType = 4
	case MemberLevelBlackGold: // 黑金会员
		userType = 5
	}

	// 如果是尊享会员，增加相应标志
	if privilegeUserInfo.MemberLevel == MemberLevelPrivilege {
		switch userType {
		case 2: // 黄金会员 & 尊享会员
			userType = 7
		case 4: // 白金会员 & 尊享会员
			userType = 8
		case 5: // 黑金会员 & 尊享会员
			userType = 9
		default: // 仅尊享会员
			userType = 6
		}
	}

	return userType, nil
}

// GetUserTypeString 将userType转换为对应的简写字符串
func GetUserTypeString(userType int) string {
	switch userType {
	case 1:
		return "普通会员"
	case 2:
		return "付费会员（黄金）"
	case 4:
		return "付费会员（白金）"
	case 5:
		return "付费会员（黑金）"
	case 6:
		return "付费会员（尊享）"
	case 7:
		return "付费会员（黄金&尊享）"
	case 8:
		return "付费会员（白金&尊享）"
	case 9:
		return "付费会员（黑金&尊享）"
	default:
		return "普通会员"
	}
}

func IsValidPrivilegeMember(uid uint32) bool {
	// 获取尊享会员信息
	var privilegeUserInfo PrivilegeMember
	if err := orm.Eloquent.Table("privilege_member").Where("uid = ?", uid).Find(&privilegeUserInfo).Error; err != nil {
		logger.Errorf("获取尊享会员信息出错:", logger.Field("err", err))
		return false
	}

	// 如果是尊享会员
	if privilegeUserInfo.MemberLevel == MemberLevelPrivilege {
		return true
	}

	return false
}

// GetUserBelongStore 查询会员的归属门店
// 规则：门店正常营业未闭店；优先返回会员归属门店；如果归属门店为空，则返回最近借卡门店
func GetUserBelongStore(uid uint32, storeId uint64) (*Store, error) {
	if uid == 0 {
		return nil, errors.New("用户uid为空")
	}

	// 如果用户有归属门店，则优先返回（需判断门店是否营业）
	if storeId != 0 {
		var store Store
		err := orm.Eloquent.Table("store").
			Where("id = ? AND is_online = 1", storeId).
			First(&store).Error
		if err == nil && store.ID != 0 {
			return &store, nil
		}
	}

	// 没有归属门店，查询最近一次借卡门店（按 delivery_time 降序）
	var recentCard OrderCard
	err := orm.Eloquent.Table("order_card").
		Where("uid = ? AND pay_status = 2 AND card_status IN (1,2,3)", uid).
		Order("delivery_time DESC").
		First(&recentCard).Error
	if err != nil || recentCard.ID == 0 {
		return nil, fmt.Errorf("无归属门店，且无法获取借卡记录: %v", err)
	}

	// 查询该借卡记录对应的门店信息
	var recentStore Store
	err = orm.Eloquent.Table("store").
		Where("id = ? AND is_online = 1", recentCard.StoreId).
		First(&recentStore).Error
	if err != nil || recentStore.ID == 0 {
		return nil, fmt.Errorf("最近借卡门店已闭店或不存在")
	}

	return &recentStore, nil
}
