package service import ( "strings" "crazy-fox-backend-api/config" "crazy-fox-backend-api/global" "crazy-fox-backend-api/model" "crazy-fox-backend-api/repo" "crazy-fox-backend-api/utils" "crazy-fox-backend-api/utils/zaplog" "github.com/pkg/errors" ) const ( statusRunning = 1 // 活动进行中 statusReward = 2 // 奖励领取中 statusUnStart = 3 // 活动未开始 statusFinished = 4 // 活动已结束 statusOffline = 5 // 活动已下线 ) const ( offline = int64(0) online = int64(1) ) // GetActList 获取活动列表 func (This *activityService) GetActList(req model.ReqActList) ([]model.ResActList, int64) { where := repo.Activity.GetActListWhere(req) tActList, total := repo.SearchOnePage[model.ActListInfo](req.Page, req.PageSize, where) // 注入公共配置 This.InjectCommonConf(tActList) actSkinMap := This.GetActSkinMap() var list = make([]model.ResActList, 0, len(tActList)) for _, oneAct := range tActList { list = append(list, model.ResActList{ Id: oneAct.Id, Name: oneAct.Name, Type: oneAct.Type, UcType: oneAct.UcType, Priority: oneAct.Priority, Status: This.judgeStatus(oneAct), Condition: This.judgeUserGroups(oneAct, actSkinMap[oneAct.Type]), StartTime: oneAct.StartTime, EndTime: oneAct.EndTime, }) } return list, total } func (This *activityService) InjectCommonConf(list []model.ActListInfo) { if len(list) == 0 { return } ids := utils.SliceColumn[model.ActListInfo, int64](list, "id") commonList := repo.Search[model.TActivityCommonConf]("WHERE aid in (?)", ids) commonMap := make(map[int64]model.ActCommonExtraConf, len(commonList)) for _, conf := range commonList { commonMap[conf.Aid] = conf.Config } for i, info := range list { list[i].ActCommonExtraConf = commonMap[info.Id] } } // GetActCommonConf 获取配置活动所需公告配置 func (This *activityService) GetActCommonConf() (commonConf model.ActCommonConf) { actSkinList := repo.Search[model.TActiveImgNameConfig]("") actSkinMap := make(map[string][]model.ActImgContent, len(actSkinList)) for _, oneSkinInfo := range actSkinList { actSkinMap[oneSkinInfo.Name] = utils.MapValues(oneSkinInfo.Content, false) } for destImgName, srcImgName := range config.ActImgNameReuseMap { actSkinMap[destImgName] = actSkinMap[srcImgName] } commonConf.ActSkinMap = actSkinMap return } // GetActSkinMap 获取活动皮肤的映射 func (This *activityService) GetActSkinMap() map[string]map[string]string { cacheKey := config.ActSkins // 缓存存在 且未过期 if cache, exist := global.LocalCache.Get(cacheKey); exist { return cache.(map[string]map[string]string) } // 从数据库获取原始数据 构建Map skinInfoMap := This.GetActCommonConf().ActSkinMap actSkinMap := make(map[string]map[string]string, len(skinInfoMap)) for actName, contents := range skinInfoMap { skinMap := make(map[string]string, len(contents)) for _, content := range contents { skinMap[content.Type] = content.Name } actSkinMap[actName] = skinMap } // 缓存道具皮肤配置 global.LocalCache.SetDefault(cacheKey, actSkinMap) return actSkinMap } // GetActDetailInfo 获取活动详情 func (This *activityService) GetActDetailInfo(actId int64) (detailInfo model.ActDetailInfo, err error) { var actConf model.ActConfInfo // 活动的详细信息 actConf.TActivityConfig = repo.Activity.GetOneActDetailInfo(actId) // 活动通用额外配置 actConf.CommonConf, _ = repo.Activity.GetActExtraCommonConf(actId) // 活动的额外奖励信息 actConf.TActivityStageRewardConfig = repo.Activity.GetOneActStageRewardInfo(actId) // 不同活动类型数据处理 if actConf.ActShowConf, err = This.NewSubAct(actConf.Type).handleActShow(&actConf); err != nil { return detailInfo, errors.WithStack(err) } return actConf.ActDetailInfo, nil } // InitBasicActConf 初始化活动基础配置项 func (This *activityService) InitBasicActConf(actInfo *model.TActivityConfig, actType string) { curTime := utils.CurTimestamp() actInfo.Name = "活动导入-" + actType actInfo.Type = actType actInfo.StartTime = curTime actInfo.EndTime = curTime + config.OneDay actInfo.RewardTime = curTime + config.OneDay - config.OneHour actInfo.LoopType = 1 actInfo.UserVipSection = "-" actInfo.UserScoreSection = "-" actInfo.ShowTitle = map[string]string{"en": "", "zh": "", "tw": "", "fr": "", "de": "", "es": "", "pt": "", "th": ""} actInfo.Bname = map[string]string{ "en": "Join Now!", "zh": "立即参加!", "tw": "立即參加!", "fr": "Adhésion immédiate", "de": "Jetzt beitreten!", "es": "¡Únete ahora!", "pt": "Entrar!", "th": "เข้าร่วมเดี๋ยวนี้!", } actInfo.Bcolor = 1 } // CleanActDetailInfo 清洗活动配置 func (This *activityService) CleanActDetailInfo(saveReq *model.ActConfInfo) (err error) { if saveReq.UserLevelSection != "-" { var lvRange []int64 err = utils.Explode(&lvRange, saveReq.UserLevelSection, "-") if err != nil || saveReq.UcType == 0 && (lvRange[0] == 0 || lvRange[1] == 0) || (lvRange[0] > lvRange[1]) { return errors.New("活动参与等级配置异常") } } if saveReq.EndTime <= saveReq.StartTime { return errors.New("保存失败,结束时间不大于开始时间") } saveReq.Name = strings.Trim(saveReq.Name, " ") if saveReq.AbType == 0 || !utils.InSlice(saveReq.AbType, []int64{1, 2}) { saveReq.AbTest, saveReq.TaTest = 0, 0 } // 额外公共配置格式化 appointUid := strings.Trim(strings.ReplaceAll(strings.ReplaceAll(saveReq.CommonConf.AppointUid, ",", ","), " ", ""), ",") if len(strings.Split(appointUid, ",")) > 1000 { return errors.New("指定UID参与活动的数量不能超过1000人") } saveReq.CommonConf.AppointUid = appointUid // 开发,体验环境 不检测资源是否存在 if !utils.IsEmpty(saveReq.ImgName) && !utils.InSlice(global.Config.System.Env, []string{config.EnvDev, config.EnvStaging}) { if err = This.isDirActSkinSrc(strings.ToLower(saveReq.ImgName)); err != nil { return errors.WithStack(err) } } // 分活动类型处理数据 if err = This.NewSubAct(saveReq.Type).handleActSave(saveReq); err != nil { return errors.Wrap(err, "活动数据处理失败") } return err } // SaveActDetailInfo 保存活动配置 func (This *activityService) SaveActDetailInfo(saveConf *model.ActConfInfo) (err error) { newAct := utils.Ternary(saveConf.Id > 0, false, true) // 更新活动或新增活动 if newAct { saveConf.Id = repo.Activity.InsertActInfo(&saveConf.TActivityConfig) } else { if err = repo.Update(&saveConf.TActivityConfig, "id"); err != nil { return errors.Wrap(err, "更新活动基础配置失败") } } // 刷新活动详情缓存 repo.Activity.HMSetActInfoCache(&saveConf.TActivityConfig) saveConf.Aid = saveConf.Id saveConf.AType = saveConf.Type // 更新活动分层奖励 if saveConf.Reward != nil || saveConf.ExtraReward != nil { if newAct { if _, err = repo.Insert(&saveConf.TActivityStageRewardConfig); err != nil { return errors.Wrap(err, "新增活动奖励配置失败") } } else { if err = repo.Update(&saveConf.TActivityStageRewardConfig, "aid"); err != nil { return errors.Wrap(err, "更新活动奖励配置失败") } } // 刷新活动奖励缓存 repo.Activity.HMSetActStageRewardInfoCache(&saveConf.TActivityStageRewardConfig) } // 刷新在线活动及权重 This.changeOnlineWeightActList(&saveConf.TActivityConfig) // 活动分层奖励 写缓存 写数据库 if err = This.writeActStageReward(saveConf); err != nil { return errors.WithStack(err) } if saveConf.UcType == 1 && len(saveConf.StaticConf) != 0 { if err = This.savePlacardStaticCfg(saveConf.Id, &saveConf.StaticConf); err != nil { return errors.Wrap(err, "保存海报静态配置失败") } } if err = This.saveActCommonCfg(saveConf.Id, saveConf.CommonConf); err != nil { return errors.Wrap(err, "保存活动额外共有配置失败") } return nil } // OnOffAct 上下线活动(自动:opType=1 手动:opType=0) func (This *activityService) OnOffAct(id int64) { actInfo := repo.Activity.GetOneActDetailInfo(id) // 反转活动状态 actInfo.IsOnline = utils.Ternary(actInfo.IsOnline == offline, online, offline) // 改变数据库字段值 repo.Activity.UpdateOnlineStatus(id, actInfo.IsOnline) // 刷新活动详情缓存 repo.Activity.HMSetActInfoCache(&actInfo) // 刷新在线活动及权重 This.changeOnlineWeightActList(&actInfo) // 上下线记录 zaplog.Info("上下线记录", map[string]any{ "方式": "手动", "aid": actInfo.Id, "type": actInfo.Type, "is_online": actInfo.IsOnline, }) // NSQ推送上下线 if err := This.pushOnlineActivity(actInfo); err != nil { panic(errors.Wrap(err, "nsq 活动上下线推送失败")) } } // DelAct 删除活动 func (This *activityService) DelAct(id int64) { // 获取在线状态 if isOnline := repo.Activity.GetActOnlineStatus(id); isOnline == 1 { panic(errors.New("操作失败,活动在上线中")) } // 删除 repo.Activity.DelActById(id) } func (This *activityService) FormatTokenGoods() {} // GetOneActImgNameByType 通过活动类型获取活动皮肤列表 func (This *activityService) GetOneActImgNameByType(typeName string) model.ActThemeConf { if utils.InSlice(typeName, []string{"0", ""}) { return model.ActThemeConf{} } if match, Ok := config.ActImgNameReuseMap[typeName]; Ok { typeName = match } oneActImgConf := repo.Activity.GetOneActImgNameConfig(typeName) return model.ActThemeConf{ ActImgNameConfBasic: oneActImgConf.ActImgNameConfBasic, Content: utils.MapValues(oneActImgConf.Content, false), } }