package couponusers import ( "CouponBackendGo/api/v1/couponusers" "CouponBackendGo/internal/dao" "CouponBackendGo/internal/model/dto" "CouponBackendGo/internal/service" "context" "database/sql" "errors" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/os/gtime" "github.com/xuri/excelize/v2" "mime/multipart" "strconv" "strings" "time" ) type sCouponUsers struct{} func init() { service.RegisterCouponUsers(&sCouponUsers{}) } // 根据优惠券id查看拥有优惠券的用户 func (s *sCouponUsers) GetCouponUsersByCondition(ctx context.Context, couponId, jwcode int, name string, pageNo, pageSize int) (users []couponusers.GetCouponUsersRes, err error) { db := dao.CouponUsers.Ctx(ctx) //基于量表JOIN查询 db = db.As("cu").InnerJoin("member_info mi", "cu.jwcode = mi.jwcode"). Where("cu.coupon_id = ?", couponId) //如果jwcode条件存在 if jwcode != 0 { db = db.Where("cu.jwcode = ?", jwcode) } //如果name条件存在 if name != "" { db = db.Where("mi.name like ?", "%"+name+"%") } //查询总数 total, err := db.Count() if err != nil { return nil, errors.New("查询总数失败") } //查询数据(分页) err = db.Fields("mi.jwcode, mi.name, mi.deptName, mi.shopName"). Page(pageNo, pageSize).Scan(&users) if err != nil { return nil, errors.New("查询数据失败") } //设置总数 for i := range users { users[i].Total = total } return users, err } // 根据jwcode,优惠券id删除用户 func (s *sCouponUsers) DeleteCouponUserByJwcode(ctx context.Context, couponId, jwcode int) (result sql.Result, err error) { if jwcode == 0 { return nil, errors.New("jwcode不能为空") } if couponId == 0 { return nil, errors.New("couponId不能为空") } result, err = dao.CouponUsers.Ctx(ctx).Where("coupon_id = ?", couponId).Where("jwcode = ?", jwcode).Delete() if err != nil { return nil, errors.New("删除用户失败") } return result, err } // 通过excel导入精网号, 并发放卡券 func (s *sCouponUsers) InsertJwcodeByExcel(ctx context.Context, file multipart.File, couponId int) (num, num1 int, err error) { // func (s *sCouponUsers) InsertJwcodeByExcel(file multipart.File) (jwcodes []int, err error) { //打开文件并返回一个excelize.File对象,用于读取和操作Excel文件的内容 f, err := excelize.OpenReader(file) if err != nil { return 0, 0, errors.New("打开文件失败") } // 延时关闭文件 defer func(f *excelize.File) { err := f.Close() if err != nil { return // 返回错误 } }(f) //读取所有工作表名称 GetSheetMap := f.GetSheetMap() if len(GetSheetMap) == 0 { return 0, 0, errors.New("没有工作表") } rows, err := f.GetRows("Sheet1") if err != nil { return 0, 0, err } // 将每行的第一列转换为int,并添加到切片中 var jwcodes []int for i, row := range rows { //跳过第一行 if i == 0 { continue } // 假设jwcode在每行的第一列 /*参数校验*/ //参数校验,检查每行是否有足够数据 if len(row) == 0 { continue // 跳过空行 } //参数校验,检查jwcode是否为非空字符串 jwcodeStr := row[0] if jwcodeStr == "" { continue // 跳过空行 } //将字符串转换为整数 jwcode, err := strconv.Atoi(jwcodeStr) if err != nil { return 0, 0, errors.New("参数转换失败") } jwcodes = append(jwcodes, jwcode) /*参数校验*/ } /*给用户发放卡券*/ num, num1, err = s.InsertCouponUsersByJwcodes(ctx, jwcodes, couponId) /*给用户发放卡券*/ //return //返回jwcodes切片 return num, num1, err } // 传来jwcodes字符串,解析并发放卡券 func (s *sCouponUsers) InsertCouponUsersByJwcodeStr(ctx context.Context, jwcodeStr string, couponId int) (num, num1 int, err error) { //将字符串转换为切片 jwcodes := strings.Split(jwcodeStr, ",") //转换成int var jwcodesInt []int for _, jwcode := range jwcodes { //参数校验,检查jwcode是否为非空字符串 if jwcode == "" { continue } jwcodeInt, err := strconv.Atoi(jwcode) if err != nil { return 0, 0, errors.New("参数转换失败") } jwcodesInt = append(jwcodesInt, jwcodeInt) } /*给用户发放卡券*/ num, num1, err = s.InsertCouponUsersByJwcodes(ctx, jwcodesInt, couponId) /*给用户发放卡券*/ return num, num1, err } // 根据精网号发放用户优惠券,群发 //不被controller层调用了,但不能删除 func (s *sCouponUsers) InsertCouponUsersByJwcodes(ctx context.Context, jwcodes []int, couponId int) (num, num1 int, err error) { //去重 m := make(map[int]bool) var uniqueJwcodes []int //存放去重后的精网号 for _, jwcode := range jwcodes { if _, exist := m[jwcode]; !exist { m[jwcode] = true uniqueJwcodes = append(uniqueJwcodes, jwcode) } } //插入数据 for _, jwcode := range uniqueJwcodes { //检查数据库表coupon_users中是否存在 count, err := dao.CouponUsers.Ctx(ctx).Where("jwcode = ?", jwcode).Where("coupon_id = ?", couponId).Count() if err != nil { return num, num1, errors.New("检索数据库中是否已存在数据失败") } //coupon_users中不存在,可以插入 if count == 0 { //判断在member_info表中是否存在 count1, err := dao.MemberInfo.Ctx(ctx).Where("jwcode = ?", jwcode).Count() if err != nil { return num, num1, errors.New("检索member_info中是否已存在数据失败") } //在member_info表中存在 if count1 > 0 { result, err := dao.CouponUsers.Ctx(ctx).Insert(g.Map{ "jwcode": jwcode, "coupon_id": couponId, "time": gtime.Now().Unix(), }) if err != nil { return num, num1, errors.New("插入数据库失败") } //获取受影响的行数 affected, err := result.RowsAffected() num += int(affected) } else { //在member_info表中不存在 num1++ } } else { //在coupon_users中存在,即已经有卡券了 num1++ } } return num, num1, err //返回受影响的行数,即新增的条数 } // 导入满足条件的用户jwcode到redis //不上传到redis了,上传到数据库表,到时候直接从表里查 func (s *sCouponUsers) InsertJwcodesToRedisByExcel(file multipart.File) (err error) { var ctx g.Ctx //打开文件并返回一个excelize.File对象,用于读取和操作Excel文件的内容 f, err := excelize.OpenReader(file) if err != nil { return errors.New("打开文件失败") } // 延时关闭文件 defer func(f *excelize.File) { err := f.Close() if err != nil { // 处理关闭文件时的错误 return } }(f) //读取所有工作表名称 GetSheetMap := f.GetSheetMap() if len(GetSheetMap) == 0 { return errors.New("没有工作表") } // 读取第一个工作表 rows, err := f.GetRows("Sheet1") if err != nil { return err } // 将每行的第一列转换为int,并添加到切片中 //var jwcodes []int for i, row := range rows { //跳过第一行 if i == 0 { continue } // 假设jwcode在每行的第一列 /*参数校验*/ //参数校验,检查每行是否有足够数据 if len(row) == 0 { continue // 跳过空行 } //参数校验,检查jwcode是否为非空字符串 jwcodeStr := row[0] if jwcodeStr == "" { continue // 跳过空行 } //将字符串转换为整数 jwcode, err := strconv.Atoi(jwcodeStr) if err != nil { return errors.New("参数转换失败") } // 判断jwcode是否在表coupon_qualified_users中 count, err := dao.CouponQualifiedUsers.Ctx(ctx).Where("jwcode = ?", jwcode).Count() if err != nil { return errors.New("检索数据库中是否已存在数据失败") } if count == 0 { //不存在,插入 _, err = dao.CouponQualifiedUsers.Ctx(ctx).Insert(g.Map{ "jwcode": jwcode, }) } //jwcodes = append(jwcodes, jwcode) /*参数校验*/ } return //返回nil表示成功 } // 判断某用户能否抽到卡券 func (s *sCouponUsers) IsEligibleUser(ctx context.Context, jwcode int, couponIds []int) (img string, err error) { //从数据库中获取符合条件的精网号EligibleJwcodes var EligibleJwcodes []couponusers.InsertCouponUserRes err = dao.CouponQualifiedUsers.Ctx(ctx).Fields("jwcode").Scan(&EligibleJwcodes) if err != nil { return "", errors.New("从数据库中获取符合条件的精网号失败") } if len(EligibleJwcodes) == 0 { return "", errors.New("核验数据库(满足条件)中数据为空") } //检查jwcode是否在EligibleJwcodes中 for _, EligibleJwcode := range EligibleJwcodes { if EligibleJwcode.Jwcode == jwcode { //存在,有资格,判断是否抽取过 for _, couponId := range couponIds { count, err := dao.CouponUsers.Ctx(ctx).Where("jwcode = ?", jwcode).Where("coupon_id = ?", couponId).Count() if err != nil { return "", errors.New("检索数据库中是否已存在数据失败") } //有记录,抽取过 if count > 0 { err = dao.CouponUsers.Ctx(ctx).Fields("img_url").Where("jwcode = ?", jwcode).Where("coupon_id = ?", couponId).Scan(&img) return img, errors.New("该用户已领取过该卡券") } } //所有的都没有记录,没有抽取过 return "", nil } } return "", errors.New("该用户不满足领取条件") } // 给单个用户发放卡券 func (s *sCouponUsers) IssueCouponToUser(ctx context.Context, jwcode, couponId int) (err error) { //查看库中是否已经存在 count, err := dao.CouponUsers.Ctx(ctx).Where("jwcode = ?", jwcode).Where("coupon_id = ?", couponId).Count() if err != nil { return errors.New("检索数据库中是否已存在数据失败") } //已存在 不添加,直接返回 if count > 0 { return errors.New("该用户已领取该卡券") } //不存在 查看是否满足条件,满足就添加,不满足就返回 //从数据库中获取符合条件的精网号EligibleJwcodes var EligibleJwcodes []couponusers.InsertCouponUserRes err = dao.CouponQualifiedUsers.Ctx(ctx).Fields("jwcode").Scan(&EligibleJwcodes) if err != nil { return errors.New("从数据库中获取符合条件的精网号失败") } if len(EligibleJwcodes) == 0 { return errors.New("核验数据库(满足条件)中数据为空") } //检查jwcode是否在EligibleJwcodes中 for _, EligibleJwcode := range EligibleJwcodes { if EligibleJwcode.Jwcode == jwcode { //存在,可以插入 _, err := dao.CouponUsers.Ctx(ctx).Insert(g.Map{ "jwcode": jwcode, "coupon_id": couponId, "time": gtime.Now().Unix(), }) if err != nil { return errors.New("插入数据库失败") } return err } } return errors.New("该用户精网号不符合领取条件") //遍历完了所有满足条件的用户,发现不在其中,不符合条件 } /*未编写*/ // 导出拥有卡券的用户列表 func (s *sCouponUsers) ExportCouponUsers(r *ghttp.Request, couponId, jwcode int, name string, pageNo, pageSize int) { //调用查询 users, err := s.GetCouponUsersByCondition(r.Context(), couponId, jwcode, name, pageNo, pageSize) if err != nil { r.Response.WriteJsonExit(dto.Error("查询失败:" + err.Error())) return } if len(users) == 0 { r.Response.WriteJsonExit(dto.Error("查询结果为空")) return } //创建 Excel文件 excelFile := excelize.NewFile() //默认会创建一个Sheet1 sheetName := "Sheet1" //设置表头 headers := []string{"序号", "精网号", "姓名", "部门", "门店"} for i, header := range headers { col := string('A' + i) //将索引转换为 Excel列名 excelFile.SetCellValue(sheetName, col+"1", header) } /*写入数据*/ rowIndex := 2 //从第二行开始写入数据 for _, user := range users { excelFile.SetCellValue(sheetName, "A"+strconv.Itoa(rowIndex), rowIndex-1) //序号 excelFile.SetCellValue(sheetName, "B"+strconv.Itoa(rowIndex), user.Jwcode) //精网号 excelFile.SetCellValue(sheetName, "C"+strconv.Itoa(rowIndex), user.Name) //姓名 excelFile.SetCellValue(sheetName, "D"+strconv.Itoa(rowIndex), user.DeptName) //部门 excelFile.SetCellValue(sheetName, "E"+strconv.Itoa(rowIndex), user.ShopName) //门店 rowIndex++ } /*写入数据*/ //设置文件名 fileName := "Users_" + time.Now().Format("20060102150405") + ".xlsx" //保存到缓冲区并返回 buffer, err := excelFile.WriteToBuffer() if err != nil { r.Response.WriteJsonExit(dto.Error("生成Excel文件失败:" + err.Error())) return } // 设置响应头,指定内容类型为Excel文件 r.Response.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") // 设置响应头,指定文件名为fileName r.Response.Header().Set("Content-Disposition", "attachment; filename="+fileName) // 将buffer中的内容写入响应 r.Response.Write(buffer.Bytes()) }