package dao import ( "context" "encoding/json" "fmt" item "go-common/app/service/openplatform/ticket-item/api/grpc/v1" "go-common/app/service/openplatform/ticket-item/model" "go-common/library/ecode" "go-common/library/log" "go-common/library/time" "strconv" "strings" xtime "time" "github.com/jinzhu/gorm" ) // DelBannerInfo 删除缓存所需banner信息 type DelBannerInfo struct { Order int32 Position int32 SubPosition int32 DistrictIDs []string } // AddBanner 添加新投放 func (d *Dao) AddBanner(c context.Context, info *item.BannerEditRequest) (bannerID int64, verID uint64, err error) { // 开启事务 tx := d.db.Begin() //创建banner信息 banner := model.Banner{ PubStart: time.Time(info.PubStart), PubEnd: time.Time(info.PubEnd), Name: info.Name, Pic: info.Pic, URL: info.Url, From: info.From, TargetUser: info.TargetUser, } if err = tx.Create(&banner).Error; err != nil { log.Error("创建banner失败:%s", err) tx.Rollback() return 0, 0, err } bannerID = banner.ID if bannerID == 0 { log.Error("bannerID为0") tx.Rollback() return 0, 0, err } var mainInfo []byte mainInfo, err = json.Marshal(info) if err != nil { log.Error("jsonMarshal版本详情失败:%s", err) tx.Rollback() return bannerID, 0, err } //生成新审核版本ver,verExt str := fmt.Sprintf("%d%d%.2d", info.Position, info.SubPosition, info.Order) forInt, _ := strconv.ParseInt(str, 10, 64) verInfo := model.Version{ Type: model.VerTypeBanner, Status: info.OpType, ItemName: info.Name, TargetItem: bannerID, AutoPub: 1, // 自动上架 PubStart: time.Time(info.PubStart), PubEnd: time.Time(info.PubEnd), For: forInt, } err = d.AddVersion(c, tx, &verInfo, &model.VersionExt{ Type: model.VerTypeBanner, MainInfo: string(mainInfo), }) if err != nil { log.Error("创建banner版本失败: %s", err) return 0, verInfo.VerID, ecode.TicketAddVersionFailed } if verInfo.VerID == 0 { log.Error("创建后获取verID为0") return 0, verInfo.VerID, ecode.TicketAddVersionFailed } // 提交事务 tx.Commit() return bannerID, verInfo.VerID, nil } // EditBanner 编辑投放 func (d *Dao) EditBanner(c context.Context, info *item.BannerEditRequest) (err error) { // 开启事务 tx := d.db.Begin() var mainInfo []byte mainInfo, err = json.Marshal(info) if err != nil { log.Error("jsonMarshal版本详情失败:%s", err) tx.Rollback() return err } //更新审核版本ver,verExt str := fmt.Sprintf("%d%d%.2d", info.Position, info.SubPosition, info.Order) forInt, _ := strconv.ParseInt(str, 10, 64) if err = tx.Model(&model.Version{}).Where("ver_id = ?", info.VerId).Updates( map[string]interface{}{ "item_name": info.Name, "status": info.OpType, "pub_start": time.Time(info.PubStart), "pub_end": time.Time(info.PubEnd), "for": forInt, }).Error; err != nil { log.Error("更新banner版本失败:%s", err) tx.Rollback() return err } if err = tx.Model(&model.VersionExt{}).Where("ver_id = ?", info.VerId).Updates( map[string]interface{}{ "main_info": mainInfo, }).Error; err != nil { log.Error("更新banner版本详情失败:%s", err) tx.Rollback() return err } // 提交事务 tx.Commit() return nil } // PassOrPublishBanner 审核通过或上架banner版本 func (d *Dao) PassOrPublishBanner(c context.Context, verID uint64) (err error) { //获取版本信息 verInfo, verExtInfo, getErr := d.GetVersion(c, verID, true) if getErr != nil { return getErr } //解析mainInfo var decodedMainInfo item.BannerEditRequest err = json.Unmarshal([]byte(verExtInfo.MainInfo), &decodedMainInfo) if err != nil { return err } bannerID := verInfo.TargetItem tx := d.db.Begin() //如果存在审核通过/进行中版本 删除版本 var bannerVersions []model.Version if err = tx.Where("target_item = ? and status in (?) and ver_id != ? and deleted_at='0000-00-00 00:00:00'", bannerID, []int32{model.VerStatusReadyForSale, model.VerStatusOnShelf}, verID).Find(&bannerVersions).Error; err != nil { log.Error("获取banner所有审核通过/已上架版本失败:%s", err) tx.Rollback() return err } var delCacheInfos []DelBannerInfo var verIDs []uint64 var delPosition int32 var delSubPosition int32 var delOrder int32 var delDistrictIDs []string for _, v := range bannerVersions { //获取该版本详情 删除对应bannerDistrict信息 if delPosition, delSubPosition, delOrder, delDistrictIDs, err = d.DelBannerDistrictByVerID(c, tx, v.VerID, bannerID); err != nil { return } delCacheInfos = append(delCacheInfos, DelBannerInfo{ Order: delOrder, Position: delPosition, SubPosition: delSubPosition, DistrictIDs: delDistrictIDs, }) verIDs = append(verIDs, v.VerID) } if verIDs != nil { if err = tx.Exec("UPDATE version SET deleted_at=? WHERE ver_id in (?)", xtime.Now().Format("2006-01-02 15:04:05"), verIDs).Error; err != nil { log.Error("删除banner版本失败:%s", err) tx.Rollback() return err } if err = tx.Exec("UPDATE version_ext SET deleted_at=? WHERE ver_id in (?)", xtime.Now().Format("2006-01-02 15:04:05"), verIDs).Error; err != nil { log.Error("删除banner ext版本失败:%s", err) tx.Rollback() return err } } //如果达到投放开始时间 还要更新bannerDistrict并直接上架 var newVerStatus int32 var newBannerStatus int32 var districtIDs []string if decodedMainInfo.PubStart <= xtime.Now().Unix() { districtIDs = strings.Split(decodedMainInfo.Location, ",") for _, districtID := range districtIDs { newDistrictID, _ := strconv.ParseInt(districtID, 10, 64) if err = d.CreateOrUpdateBannerDistrict(c, tx, model.BannerDistrict{ BannerID: bannerID, Position: decodedMainInfo.Position, SubPosition: decodedMainInfo.SubPosition, Order: decodedMainInfo.Order, DistrictID: newDistrictID, }); err != nil { return err } } newVerStatus = model.VerStatusOnShelf newBannerStatus = 1 } else { newVerStatus = model.VerStatusReadyForSale newBannerStatus = 0 } //更新banner表 if err = tx.Model(&model.Banner{}).Where("id = ?", bannerID).Updates( map[string]interface{}{ "pub_start": time.Time(decodedMainInfo.PubStart), "pub_end": time.Time(decodedMainInfo.PubEnd), "name": decodedMainInfo.Name, "pic": decodedMainInfo.Pic, "url": decodedMainInfo.Url, "from": decodedMainInfo.From, "status": newBannerStatus, "target_user": decodedMainInfo.TargetUser, }).Error; err != nil { log.Error("更新banner失败:%s", err) tx.Rollback() return err } //更新version状态为审核通过(待上架)或已上架 if err = tx.Model(&model.Version{}).Where("ver_id = ?", verID).Updates( map[string]interface{}{ "status": newVerStatus, }).Error; err != nil { log.Error("更新banner审核版本失败:%s", err) tx.Rollback() return err } tx.Commit() //如果新状态是上架状态 删除相关缓存 if newVerStatus == model.VerStatusOnShelf { _, err = d.DelBannerCache(c, decodedMainInfo.Position, decodedMainInfo.SubPosition, decodedMainInfo.Order, districtIDs, bannerID) if err != nil { return } for _, v := range delCacheInfos { _, err = d.DelBannerCache(c, v.Position, v.SubPosition, v.Order, v.DistrictIDs, 0) if err != nil { return } } } return } // DelBannerCache 删除banner相关缓存 func (d *Dao) DelBannerCache(c context.Context, position int32, subPosition int32, order int32, districtIDs []string, bannerID int64) (res bool, err error) { var ( keys []interface{} ) conn := d.redis.Get(c) defer func() { conn.Flush() conn.Close() }() for _, districtID := range districtIDs { // DEL bannerList keys = append(keys, keyBannerList(order, districtID, position, subPosition)) } //删除bannerInfo缓存 if bannerID != 0 { keys = append(keys, keyBannerInfo(bannerID)) } log.Info("DEL %v", keys) //DEL bannerList if err = conn.Send("DEL", keys...); err != nil { log.Error("DEL %v, error(%v)", keys, err) } if err != nil { return false, err } return true, err } //DelBannerDistrictByVerID 删除版本详情内对应的关系表信息 func (d *Dao) DelBannerDistrictByVerID(c context.Context, tx *gorm.DB, verID uint64, bannerID int64) (position int32, subPosition int32, order int32, districtIDs []string, err error) { var verExtInfo model.VersionExt var delDecodedInfo item.BannerEditRequest //获取该版本详情 删除对应bannerDistrict信息 if err = tx.Where("ver_id = ?", verID).First(&verExtInfo).Error; err != nil { log.Error("获取需要删除版本详情失败:%s", err) tx.Rollback() return 0, 0, 0, nil, err } //解析mainInfo err = json.Unmarshal([]byte(verExtInfo.MainInfo), &delDecodedInfo) if err != nil { tx.Rollback() return 0, 0, 0, nil, err } districtIDs = strings.Split(delDecodedInfo.Location, ",") for _, districtID := range districtIDs { if err = tx.Exec("UPDATE banner_district SET is_deleted=1 WHERE banner_id = ? and district_id = ? and position = ? and sub_position = ? and `order` = ?", bannerID, districtID, delDecodedInfo.Position, delDecodedInfo.SubPosition, delDecodedInfo.Order).Error; err != nil { log.Error("删除bannerDistrict失败:%s", err) tx.Rollback() return 0, 0, 0, nil, err } } return delDecodedInfo.Position, delDecodedInfo.SubPosition, delDecodedInfo.Order, districtIDs, err } // CreateOrUpdateBannerDistrict 更新或新建bannerDistrict关系记录 func (d *Dao) CreateOrUpdateBannerDistrict(c context.Context, tx *gorm.DB, info model.BannerDistrict) (err error) { var bannerDist model.BannerDistrict log.Info("bannerDist:%v", info) err = tx.Where("district_id = ? and position = ? and sub_position = ? and `order` = ?", info.DistrictID, info.Position, info.SubPosition, info.Order).First(&bannerDist).Error //除去没查找到记录的报错 其他直接抛错 if err != nil && err != ecode.NothingFound { log.Error("获取banner dist信息失败:%s", err) tx.Rollback() return } if bannerDist.ID != 0 { //update log.Info("update bannerDistrict") if err = tx.Exec("UPDATE banner_district SET banner_id=?,is_deleted=0 WHERE district_id = ? and position = ? and sub_position = ? and `order` = ?", info.BannerID, info.DistrictID, info.Position, info.SubPosition, info.Order).Error; err != nil { log.Error("更新bannerDistrict失败:%s", err) tx.Rollback() return err } } else { //create log.Info("insert bannerDistrict") if err = tx.Create(&model.BannerDistrict{ BannerID: info.BannerID, Position: info.Position, SubPosition: info.SubPosition, Order: info.Order, DistrictID: info.DistrictID, }).Error; err != nil { log.Error("创建bannerDistrict失败:%s", err) tx.Rollback() return err } } return nil } // DeleteBanner 删除banner func (d *Dao) DeleteBanner(c context.Context, verID uint64) (err error) { tx := d.db.Begin() if err = tx.Exec("UPDATE version SET deleted_at=? WHERE ver_id = ?", xtime.Now().Format("2006-01-02 15:04:05"), verID).Error; err != nil { tx.Rollback() log.Error("删除banner版本失败:%s", err) return err } if err = tx.Exec("UPDATE version_ext SET deleted_at=? WHERE ver_id=?", xtime.Now().Format("2006-01-02 15:04:05"), verID).Error; err != nil { tx.Rollback() log.Error("删除banner ext版本失败:%s", err) return err } tx.Commit() return } // UnpublishBannerManual 手动取消激活banner func (d *Dao) UnpublishBannerManual(c context.Context, verID uint64) (err error) { //取消激活banner //获取版本信息 tx := d.db.Begin() verInfo, _, getErr := d.GetVersion(c, verID, true) if getErr != nil { return getErr } bannerID := verInfo.TargetItem if err = tx.Exec("UPDATE banner SET status = 0 WHERE id = ?", bannerID).Error; err != nil { tx.Rollback() log.Error("更新banner未激活状态失败:%s", err) return err } //更新版本为草稿状态 if err = tx.Exec("UPDATE version SET status = ? WHERE ver_id = ?", model.VerStatusNotReviewed, verID).Error; err != nil { tx.Rollback() log.Error("更新banner版本为草稿状态失败:%s", err) return err } //删除此版本bannerDistrict信息 var delPosition int32 var delSubPosition int32 var delOrder int32 var delDistrictIDs []string if delPosition, delSubPosition, delOrder, delDistrictIDs, err = d.DelBannerDistrictByVerID(c, tx, verID, bannerID); err != nil { return } //如果存在除这个版本以外同个投放id的版本 删除版本 var bannerVersions []model.Version if err = tx.Where("target_item = ? and ver_id != ? and deleted_at='0000-00-00 00:00:00'", bannerID, verID).Find(&bannerVersions).Error; err != nil { log.Error("获取banner所有其他版本失败:%s", err) tx.Rollback() return err } var verIDs []uint64 for _, v := range bannerVersions { //获取该版本详情 删除对应bannerDistrict信息 _, _, _, _, err = d.DelBannerDistrictByVerID(c, tx, v.VerID, bannerID) if err != nil { return } verIDs = append(verIDs, v.VerID) } if verIDs != nil { if err = tx.Exec("UPDATE version SET deleted_at=? WHERE ver_id in (?)", xtime.Now().Format("2006-01-02 15:04:05"), verIDs).Error; err != nil { log.Error("删除banner版本失败:%s", err) tx.Rollback() return err } if err = tx.Exec("UPDATE version_ext SET deleted_at=? WHERE ver_id in (?)", xtime.Now().Format("2006-01-02 15:04:05"), verIDs).Error; err != nil { log.Error("删除banner ext版本失败:%s", err) tx.Rollback() return err } } tx.Commit() //删除下架相关缓存 _, err = d.DelBannerCache(c, delPosition, delSubPosition, delOrder, delDistrictIDs, bannerID) return } // UnpublishBannerForced 已过期自动下架操作 func (d *Dao) UnpublishBannerForced(c context.Context, verID uint64) (err error) { //获取版本信息 tx := d.db.Begin() verInfo, _, getErr := d.GetVersion(c, verID, true) if getErr != nil { return getErr } //取消激活banner bannerID := verInfo.TargetItem if err = tx.Exec("UPDATE banner SET status = 0 WHERE id = ?", bannerID).Error; err != nil { tx.Rollback() log.Error("更新banner未激活状态失败:%s", err) return err } //删除bannerDistrict信息 var delPosition int32 var delSubPosition int32 var delOrder int32 var delDistrictIDs []string if delPosition, delSubPosition, delOrder, delDistrictIDs, err = d.DelBannerDistrictByVerID(c, tx, verID, bannerID); err != nil { return } //更新版本为强制下架状态 if err = tx.Exec("UPDATE version SET status = ? WHERE ver_id = ?", model.VerStatusOffShelfForced, verID).Error; err != nil { tx.Rollback() log.Error("更新banner版本为强制下架状态失败:%s", err) return err } tx.Commit() //删除下架相关缓存 _, err = d.DelBannerCache(c, delPosition, delSubPosition, delOrder, delDistrictIDs, bannerID) return } // CgBannerStatus 更改banner版本状态 func (d *Dao) CgBannerStatus(c context.Context, info *item.VersionStatusRequest) (err error) { switch info.OpType { case 0: //手动取消激活操作 err = d.UnpublishBannerManual(c, info.VerId) case 1: //提交审核操作 err = d.db.Exec("UPDATE version SET status = ? WHERE ver_id = ?", model.VerStatusReadyForReview, info.VerId).Error if err != nil { return err } //提交审核时 记入versionLog err = d.AddVersionLog(c, &model.VersionLog{ VerID: info.VerId, Type: 2, //用户操作记录 Log: "提交审核", Uname: info.Uname, }) case 2: //删除操作 err = d.DeleteBanner(c, info.VerId) case 3: //上架操作 err = d.PassOrPublishBanner(c, info.VerId) case 4: //已过期自动下架操作 err = d.UnpublishBannerForced(c, info.VerId) default: return ecode.NothingFound } return }