activity.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. package service
  2. import (
  3. "strings"
  4. "crazy-fox-backend-api/config"
  5. "crazy-fox-backend-api/global"
  6. "crazy-fox-backend-api/model"
  7. "crazy-fox-backend-api/repo"
  8. "crazy-fox-backend-api/utils"
  9. "crazy-fox-backend-api/utils/zaplog"
  10. "github.com/pkg/errors"
  11. )
  12. const (
  13. statusRunning = 1 // 活动进行中
  14. statusReward = 2 // 奖励领取中
  15. statusUnStart = 3 // 活动未开始
  16. statusFinished = 4 // 活动已结束
  17. statusOffline = 5 // 活动已下线
  18. )
  19. const (
  20. offline = int64(0)
  21. online = int64(1)
  22. )
  23. // GetActList 获取活动列表
  24. func (This *activityService) GetActList(req model.ReqActList) ([]model.ResActList, int64) {
  25. where := repo.Activity.GetActListWhere(req)
  26. tActList, total := repo.SearchOnePage[model.ActListInfo](req.Page, req.PageSize, where)
  27. // 注入公共配置
  28. This.InjectCommonConf(tActList)
  29. actSkinMap := This.GetActSkinMap()
  30. var list = make([]model.ResActList, 0, len(tActList))
  31. for _, oneAct := range tActList {
  32. list = append(list, model.ResActList{
  33. Id: oneAct.Id,
  34. Name: oneAct.Name,
  35. Type: oneAct.Type,
  36. UcType: oneAct.UcType,
  37. Priority: oneAct.Priority,
  38. Status: This.judgeStatus(oneAct),
  39. Condition: This.judgeUserGroups(oneAct, actSkinMap[oneAct.Type]),
  40. StartTime: oneAct.StartTime,
  41. EndTime: oneAct.EndTime,
  42. })
  43. }
  44. return list, total
  45. }
  46. func (This *activityService) InjectCommonConf(list []model.ActListInfo) {
  47. if len(list) == 0 {
  48. return
  49. }
  50. ids := utils.SliceColumn[model.ActListInfo, int64](list, "id")
  51. commonList := repo.Search[model.TActivityCommonConf]("WHERE aid in (?)", ids)
  52. commonMap := make(map[int64]model.ActCommonExtraConf, len(commonList))
  53. for _, conf := range commonList {
  54. commonMap[conf.Aid] = conf.Config
  55. }
  56. for i, info := range list {
  57. list[i].ActCommonExtraConf = commonMap[info.Id]
  58. }
  59. }
  60. // GetActCommonConf 获取配置活动所需公告配置
  61. func (This *activityService) GetActCommonConf() (commonConf model.ActCommonConf) {
  62. actSkinList := repo.Search[model.TActiveImgNameConfig]("")
  63. actSkinMap := make(map[string][]model.ActImgContent, len(actSkinList))
  64. for _, oneSkinInfo := range actSkinList {
  65. actSkinMap[oneSkinInfo.Name] = utils.MapValues(oneSkinInfo.Content, false)
  66. }
  67. for destImgName, srcImgName := range config.ActImgNameReuseMap {
  68. actSkinMap[destImgName] = actSkinMap[srcImgName]
  69. }
  70. commonConf.ActSkinMap = actSkinMap
  71. return
  72. }
  73. // GetActSkinMap 获取活动皮肤的映射
  74. func (This *activityService) GetActSkinMap() map[string]map[string]string {
  75. cacheKey := config.ActSkins
  76. // 缓存存在 且未过期
  77. if cache, exist := global.LocalCache.Get(cacheKey); exist {
  78. return cache.(map[string]map[string]string)
  79. }
  80. // 从数据库获取原始数据 构建Map
  81. skinInfoMap := This.GetActCommonConf().ActSkinMap
  82. actSkinMap := make(map[string]map[string]string, len(skinInfoMap))
  83. for actName, contents := range skinInfoMap {
  84. skinMap := make(map[string]string, len(contents))
  85. for _, content := range contents {
  86. skinMap[content.Type] = content.Name
  87. }
  88. actSkinMap[actName] = skinMap
  89. }
  90. // 缓存道具皮肤配置
  91. global.LocalCache.SetDefault(cacheKey, actSkinMap)
  92. return actSkinMap
  93. }
  94. // GetActDetailInfo 获取活动详情
  95. func (This *activityService) GetActDetailInfo(actId int64) (detailInfo model.ActDetailInfo, err error) {
  96. var actConf model.ActConfInfo
  97. // 活动的详细信息
  98. actConf.TActivityConfig = repo.Activity.GetOneActDetailInfo(actId)
  99. // 活动通用额外配置
  100. actConf.CommonConf, _ = repo.Activity.GetActExtraCommonConf(actId)
  101. // 活动的额外奖励信息
  102. actConf.TActivityStageRewardConfig = repo.Activity.GetOneActStageRewardInfo(actId)
  103. // 不同活动类型数据处理
  104. if actConf.ActShowConf, err = This.NewSubAct(actConf.Type).handleActShow(&actConf); err != nil {
  105. return detailInfo, errors.WithStack(err)
  106. }
  107. return actConf.ActDetailInfo, nil
  108. }
  109. // InitBasicActConf 初始化活动基础配置项
  110. func (This *activityService) InitBasicActConf(actInfo *model.TActivityConfig, actType string) {
  111. curTime := utils.CurTimestamp()
  112. actInfo.Name = "活动导入-" + actType
  113. actInfo.Type = actType
  114. actInfo.StartTime = curTime
  115. actInfo.EndTime = curTime + config.OneDay
  116. actInfo.RewardTime = curTime + config.OneDay - config.OneHour
  117. actInfo.LoopType = 1
  118. actInfo.UserVipSection = "-"
  119. actInfo.UserScoreSection = "-"
  120. actInfo.ShowTitle = map[string]string{"en": "", "zh": "", "tw": "", "fr": "", "de": "", "es": "", "pt": "", "th": ""}
  121. actInfo.Bname = map[string]string{
  122. "en": "Join Now!",
  123. "zh": "立即参加!",
  124. "tw": "立即參加!",
  125. "fr": "Adhésion immédiate",
  126. "de": "Jetzt beitreten!",
  127. "es": "¡Únete ahora!",
  128. "pt": "Entrar!",
  129. "th": "เข้าร่วมเดี๋ยวนี้!",
  130. }
  131. actInfo.Bcolor = 1
  132. }
  133. // CleanActDetailInfo 清洗活动配置
  134. func (This *activityService) CleanActDetailInfo(saveReq *model.ActConfInfo) (err error) {
  135. if saveReq.UserLevelSection != "-" {
  136. var lvRange []int64
  137. err = utils.Explode(&lvRange, saveReq.UserLevelSection, "-")
  138. if err != nil || saveReq.UcType == 0 && (lvRange[0] == 0 || lvRange[1] == 0) || (lvRange[0] > lvRange[1]) {
  139. return errors.New("活动参与等级配置异常")
  140. }
  141. }
  142. if saveReq.EndTime <= saveReq.StartTime {
  143. return errors.New("保存失败,结束时间不大于开始时间")
  144. }
  145. saveReq.Name = strings.Trim(saveReq.Name, " ")
  146. if saveReq.AbType == 0 || !utils.InSlice(saveReq.AbType, []int64{1, 2}) {
  147. saveReq.AbTest, saveReq.TaTest = 0, 0
  148. }
  149. // 额外公共配置格式化
  150. appointUid := strings.Trim(strings.ReplaceAll(strings.ReplaceAll(saveReq.CommonConf.AppointUid, ",", ","), " ", ""), ",")
  151. if len(strings.Split(appointUid, ",")) > 1000 {
  152. return errors.New("指定UID参与活动的数量不能超过1000人")
  153. }
  154. saveReq.CommonConf.AppointUid = appointUid
  155. // 开发,体验环境 不检测资源是否存在
  156. if !utils.IsEmpty(saveReq.ImgName) && !utils.InSlice(global.Config.System.Env, []string{config.EnvDev, config.EnvStaging}) {
  157. if err = This.isDirActSkinSrc(strings.ToLower(saveReq.ImgName)); err != nil {
  158. return errors.WithStack(err)
  159. }
  160. }
  161. // 分活动类型处理数据
  162. if err = This.NewSubAct(saveReq.Type).handleActSave(saveReq); err != nil {
  163. return errors.Wrap(err, "活动数据处理失败")
  164. }
  165. return err
  166. }
  167. // SaveActDetailInfo 保存活动配置
  168. func (This *activityService) SaveActDetailInfo(saveConf *model.ActConfInfo) (err error) {
  169. newAct := utils.Ternary(saveConf.Id > 0, false, true)
  170. // 更新活动或新增活动
  171. if newAct {
  172. saveConf.Id = repo.Activity.InsertActInfo(&saveConf.TActivityConfig)
  173. } else {
  174. if err = repo.Update(&saveConf.TActivityConfig, "id"); err != nil {
  175. return errors.Wrap(err, "更新活动基础配置失败")
  176. }
  177. }
  178. // 刷新活动详情缓存
  179. repo.Activity.HMSetActInfoCache(&saveConf.TActivityConfig)
  180. saveConf.Aid = saveConf.Id
  181. saveConf.AType = saveConf.Type
  182. // 更新活动分层奖励
  183. if saveConf.Reward != nil || saveConf.ExtraReward != nil {
  184. if newAct {
  185. if _, err = repo.Insert(&saveConf.TActivityStageRewardConfig); err != nil {
  186. return errors.Wrap(err, "新增活动奖励配置失败")
  187. }
  188. } else {
  189. if err = repo.Update(&saveConf.TActivityStageRewardConfig, "aid"); err != nil {
  190. return errors.Wrap(err, "更新活动奖励配置失败")
  191. }
  192. }
  193. // 刷新活动奖励缓存
  194. repo.Activity.HMSetActStageRewardInfoCache(&saveConf.TActivityStageRewardConfig)
  195. }
  196. // 刷新在线活动及权重
  197. This.changeOnlineWeightActList(&saveConf.TActivityConfig)
  198. // 活动分层奖励 写缓存 写数据库
  199. if err = This.writeActStageReward(saveConf); err != nil {
  200. return errors.WithStack(err)
  201. }
  202. if saveConf.UcType == 1 && len(saveConf.StaticConf) != 0 {
  203. if err = This.savePlacardStaticCfg(saveConf.Id, &saveConf.StaticConf); err != nil {
  204. return errors.Wrap(err, "保存海报静态配置失败")
  205. }
  206. }
  207. if err = This.saveActCommonCfg(saveConf.Id, saveConf.CommonConf); err != nil {
  208. return errors.Wrap(err, "保存活动额外共有配置失败")
  209. }
  210. return nil
  211. }
  212. // OnOffAct 上下线活动(自动:opType=1 手动:opType=0)
  213. func (This *activityService) OnOffAct(id int64) {
  214. actInfo := repo.Activity.GetOneActDetailInfo(id)
  215. // 反转活动状态
  216. actInfo.IsOnline = utils.Ternary(actInfo.IsOnline == offline, online, offline)
  217. // 改变数据库字段值
  218. repo.Activity.UpdateOnlineStatus(id, actInfo.IsOnline)
  219. // 刷新活动详情缓存
  220. repo.Activity.HMSetActInfoCache(&actInfo)
  221. // 刷新在线活动及权重
  222. This.changeOnlineWeightActList(&actInfo)
  223. // 上下线记录
  224. zaplog.Info("上下线记录", map[string]any{
  225. "方式": "手动",
  226. "aid": actInfo.Id,
  227. "type": actInfo.Type,
  228. "is_online": actInfo.IsOnline,
  229. })
  230. // NSQ推送上下线
  231. if err := This.pushOnlineActivity(actInfo); err != nil {
  232. panic(errors.Wrap(err, "nsq 活动上下线推送失败"))
  233. }
  234. }
  235. // DelAct 删除活动
  236. func (This *activityService) DelAct(id int64) {
  237. // 获取在线状态
  238. if isOnline := repo.Activity.GetActOnlineStatus(id); isOnline == 1 {
  239. panic(errors.New("操作失败,活动在上线中"))
  240. }
  241. // 删除
  242. repo.Activity.DelActById(id)
  243. }
  244. func (This *activityService) FormatTokenGoods() {}
  245. // GetOneActImgNameByType 通过活动类型获取活动皮肤列表
  246. func (This *activityService) GetOneActImgNameByType(typeName string) model.ActThemeConf {
  247. if utils.InSlice(typeName, []string{"0", ""}) {
  248. return model.ActThemeConf{}
  249. }
  250. if match, Ok := config.ActImgNameReuseMap[typeName]; Ok {
  251. typeName = match
  252. }
  253. oneActImgConf := repo.Activity.GetOneActImgNameConfig(typeName)
  254. return model.ActThemeConf{
  255. ActImgNameConfBasic: oneActImgConf.ActImgNameConfBasic,
  256. Content: utils.MapValues(oneActImgConf.Content, false),
  257. }
  258. }