act_super_gashapon.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. package service
  2. import (
  3. "fmt"
  4. "sort"
  5. "crazy-fox-backend-api/config"
  6. "crazy-fox-backend-api/model"
  7. "crazy-fox-backend-api/utils"
  8. "crazy-fox-backend-api/utils/uniqid"
  9. "github.com/jmoiron/sqlx/types"
  10. jsoniter "github.com/json-iterator/go"
  11. "github.com/pkg/errors"
  12. )
  13. const (
  14. normalPrize = int64(0)
  15. bigPrize = int64(1)
  16. luckyPrize = int64(2)
  17. )
  18. type actSuperGashapon struct{}
  19. // 展示数据处理
  20. func (This *actSuperGashapon) handleActShow(confInfo *model.ActConfInfo) (json types.JSONText, err error) {
  21. var repoConf map[int64]model.SuperGashaponRepoConf
  22. if err = jsoniter.Unmarshal(confInfo.Reward, &repoConf); err != nil {
  23. return json, errors.Wrap(err, "超级扭蛋 奖励Json解析失败")
  24. }
  25. var repoTokenGoodsConf map[string]model.TokenGoods
  26. if err = jsoniter.Unmarshal(confInfo.ExtraData, &repoTokenGoodsConf); err != nil {
  27. return json, errors.Wrap(err, "超级扭蛋 代币商品Json解析失败")
  28. }
  29. // 数据转换
  30. showConf := This.convertIntoShowConf(repoConf, repoTokenGoodsConf)
  31. if json, err = jsoniter.Marshal(showConf); err != nil {
  32. return json, errors.Wrap(err, "超级扭蛋 奖励序列化失败")
  33. }
  34. return
  35. }
  36. // 保存数据处理
  37. func (This *actSuperGashapon) handleActSave(confInfo *model.ActConfInfo) (err error) {
  38. var showConf []model.SuperGashaponShowConf
  39. if err = jsoniter.Unmarshal(confInfo.ActShowConf, &showConf); err != nil {
  40. return errors.Wrap(err, "超级扭蛋 奖励Json解析失败")
  41. }
  42. // 数据合法性验证
  43. if err = This.verifyConf(showConf); err != nil {
  44. return errors.WithStack(err)
  45. }
  46. repoConf := This.convertIntoRepoConf(showConf)
  47. if confInfo.Reward, err = jsoniter.Marshal(repoConf); err != nil {
  48. return errors.Wrap(err, "超级扭蛋 奖励序列化失败")
  49. }
  50. if confInfo.ExtraData, err = This.convertTokenGoodsIntoRepoConf(showConf); err != nil {
  51. return errors.Wrap(err, "超级扭蛋 奖励序列化失败")
  52. }
  53. return
  54. }
  55. // 分层数据处理
  56. func (This *actSuperGashapon) handleActRewardSection(confInfo *model.ActConfInfo, maps ...map[string]any) error {
  57. var repoConf map[int64]model.SuperGashaponRepoConf
  58. if err := jsoniter.Unmarshal(confInfo.Reward, &repoConf); err != nil {
  59. return errors.Wrap(err, "超级扭蛋 奖励Json解析失败")
  60. }
  61. var extraRewardRepoConfMap map[string]model.TokenGoods
  62. if err := jsoniter.Unmarshal(confInfo.ExtraData, &extraRewardRepoConfMap); err != nil {
  63. return errors.Wrap(err, "皮纳塔奖励解析失败")
  64. }
  65. conditionMap, rewardMap, extraRewardMap := maps[0], maps[1], maps[2]
  66. for idx1, item1 := range repoConf {
  67. for idx2, item2 := range item1.Stages {
  68. for idx3, item3 := range item2.Stages {
  69. stageKey := fmt.Sprintf("%d_%d_%d", idx1, idx2, idx3)
  70. conditionMap[stageKey] = Activity.buildStageCondition(item1.LvRange, item2.SpinsRange, item3.SsGroup)
  71. rewardMap[stageKey] = item3.Reward
  72. extraRewardMap[stageKey] = model.StageExtraRepoConf{TokenGoods: extraRewardRepoConfMap[stageKey]}
  73. }
  74. }
  75. }
  76. return nil
  77. }
  78. // 导入数据处理
  79. func (This *actSuperGashapon) handleActImport(_ *model.ActDetailInfo, excelInfo [][][]string) (json types.JSONText, err error) {
  80. if len(excelInfo) < 3 {
  81. return json, errors.New("工作表数量不匹配")
  82. }
  83. var showConfArr []model.SuperGashaponShowConf
  84. if showConfArr, err = This.sheetResolver(excelInfo); err != nil {
  85. return json, errors.Wrap(err, "超级扭蛋 工作表解析失败")
  86. }
  87. if json, err = jsoniter.Marshal(showConfArr); err != nil {
  88. return json, errors.Wrap(err, "超级扭蛋 配置序列化失败")
  89. }
  90. return
  91. }
  92. func (This *actSuperGashapon) convertIntoShowConf(repoConfMap map[int64]model.SuperGashaponRepoConf, repoTokenGoodsConf map[string]model.TokenGoods) (showConfArr []model.SuperGashaponShowConf) {
  93. for lvId, lvStageReward := range repoConfMap {
  94. for spinsId, spinsStageReward := range lvStageReward.Stages {
  95. for ssId, ssStageReward := range spinsStageReward.Stages {
  96. stagekey := fmt.Sprintf("%d_%d_%d", lvId, spinsId, ssId)
  97. showConfArr = append(showConfArr, model.SuperGashaponShowConf{
  98. ThreeLayer: model.ThreeLayer{
  99. Id: Activity.buildLayerOrderId(lvId, spinsId, ssId),
  100. LvRange: lvStageReward.LvRange,
  101. SpinsRange: spinsStageReward.SpinsRange,
  102. SsGroup: ssStageReward.SsGroup,
  103. },
  104. Reward: utils.MapValues(ssStageReward.Reward, true),
  105. TokenGoods: repoTokenGoodsConf[stagekey],
  106. })
  107. }
  108. }
  109. }
  110. sort.SliceStable(showConfArr, func(i, j int) bool { return showConfArr[i].Id < showConfArr[j].Id })
  111. return
  112. }
  113. func (This *actSuperGashapon) verifyConf(showConfArr []model.SuperGashaponShowConf) (err error) {
  114. for i := 0; i < len(showConfArr); i++ {
  115. prizeStat := make(map[int64][]int)
  116. for j := 0; j < len(showConfArr[i].Reward); j++ {
  117. oneRewardInfo := showConfArr[i].Reward[j]
  118. if oneRewardInfo.GashType != luckyPrize {
  119. if len(oneRewardInfo.Prize) != 1 {
  120. return Activity.jointError("非幸运蛋奖励必须配置且唯一", i+1, j+1)
  121. }
  122. } else {
  123. if len(oneRewardInfo.Prize) != 0 {
  124. return Activity.jointError("幸运蛋不能配置奖励", i+1, j+1)
  125. }
  126. }
  127. prizeStat[oneRewardInfo.Layer] = append(prizeStat[oneRewardInfo.Layer], utils.Ternary(oneRewardInfo.GashType == luckyPrize, 1, 0))
  128. }
  129. for layer, stats := range prizeStat {
  130. errPrefix := fmt.Sprintf("第 %d 行,第 %d 层,", i+1, layer)
  131. // 幸运蛋最多只能有一个
  132. if utils.SliceSum(stats) > 1 {
  133. return Activity.jointError(utils.Concat(errPrefix, "每层幸运蛋最多一个"))
  134. }
  135. // 总奖励数最多10个
  136. if len(stats) > 10 {
  137. return Activity.jointError(utils.Concat(errPrefix, "每层扭蛋不能超10个"))
  138. }
  139. }
  140. }
  141. return
  142. }
  143. func (This *actSuperGashapon) convertIntoRepoConf(showConfArr []model.SuperGashaponShowConf) (repoConfMap map[int64]model.SuperGashaponRepoConf) {
  144. repoConfMap = map[int64]model.SuperGashaponRepoConf{}
  145. var unique = uniqid.GetUniqId()
  146. defer uniqid.DelMapByUniqId(unique)
  147. for i := 0; i < len(showConfArr); i++ {
  148. oneRowInfo := showConfArr[i]
  149. idxes := uniqid.GetStageIdx(unique, oneRowInfo.LvRange, oneRowInfo.SpinsRange, oneRowInfo.SsGroup)
  150. lvIdx, spinIdx, ssIdx := idxes[0], idxes[1], idxes[2]
  151. if _, Ok := repoConfMap[lvIdx]; !Ok {
  152. repoConfMap[lvIdx] = model.SuperGashaponRepoConf{
  153. LvRange: oneRowInfo.LvRange,
  154. Stages: map[int64]model.SuperGashaponSpinsStage{},
  155. }
  156. }
  157. if _, Ok := repoConfMap[lvIdx].Stages[spinIdx]; !Ok {
  158. repoConfMap[lvIdx].Stages[spinIdx] = model.SuperGashaponSpinsStage{
  159. SpinsRange: oneRowInfo.SpinsRange,
  160. Stages: map[int64]model.SuperGashaponSsStage{},
  161. }
  162. }
  163. repoConfMap[lvIdx].Stages[spinIdx].Stages[ssIdx] = model.SuperGashaponSsStage{
  164. SsGroup: oneRowInfo.SsGroup,
  165. Reward: utils.Slice2Map(oneRowInfo.Reward),
  166. }
  167. }
  168. return
  169. }
  170. func (This *actSuperGashapon) convertTokenGoodsIntoRepoConf(showConfArr []model.SuperGashaponShowConf) (types.JSONText, error) {
  171. repoConfMap := map[string]model.TokenGoods{}
  172. var unique = uniqid.GetUniqId()
  173. defer uniqid.DelMapByUniqId(unique)
  174. for i := 0; i < len(showConfArr); i++ {
  175. oneRowInfo := showConfArr[i]
  176. idxes := uniqid.GetStageIdx(unique, oneRowInfo.LvRange, oneRowInfo.SpinsRange, oneRowInfo.SsGroup)
  177. lvIdx, spinIdx, ssIdx := idxes[0], idxes[1], idxes[2]
  178. stageKey := fmt.Sprintf("%d_%d_%d", lvIdx, spinIdx, ssIdx)
  179. repoConfMap[stageKey] = oneRowInfo.TokenGoods
  180. }
  181. return jsoniter.Marshal(repoConfMap)
  182. }
  183. func (This *actSuperGashapon) sheetResolver(sheetList [][][]string) ([]model.SuperGashaponShowConf, error) {
  184. sheet2Array, sheet3Array, sheet4Array := sheetList[1], sheetList[2], sheetList[3]
  185. // 解析分组ID配置项
  186. stageConfArr, err := Activity.parseThreeLayerConf(sheet2Array)
  187. if err != nil {
  188. return nil, errors.WithStack(err)
  189. }
  190. // 解析奖励配置项
  191. rewardMap, err := This.parseRewardSheet(sheet3Array)
  192. if err != nil {
  193. return nil, errors.WithStack(err)
  194. }
  195. // 解析奖励配置项
  196. tokenGoodsMap, err := Activity.ParseTokenGoodsSheet(sheet4Array, config.ActSuperGashapon)
  197. if err != nil {
  198. return nil, errors.WithStack(err)
  199. }
  200. showConfArr, err := This.packageShowConf(stageConfArr, rewardMap, tokenGoodsMap)
  201. if err != nil {
  202. return nil, errors.WithStack(err)
  203. }
  204. return showConfArr, nil
  205. }
  206. func (This *actSuperGashapon) parseRewardSheet(rewardsSheet [][]string) (map[int64][]model.SuperGashaponStageReward, error) {
  207. var err error
  208. stageRewardArrMap := map[int64][]model.SuperGashaponStageReward{}
  209. gashTypeMap := map[string]int64{"普通": 0, "大奖": 1, "幸运蛋": 2}
  210. for rowIdx := 1; rowIdx < len(rewardsSheet); rowIdx++ {
  211. var (
  212. id int64
  213. gashType string
  214. reward = make([]model.ExcelPrize, 1)
  215. one model.SuperGashaponStageReward
  216. )
  217. // 解析行配置
  218. if err = utils.DestructAssign(rewardsSheet[rowIdx], &id, &one.Layer, &gashType, &one.Weight, &one.NeedCoins, &reward); err != nil {
  219. return nil, errors.WithStack(err)
  220. }
  221. if gashTye, Ok := gashTypeMap[gashType]; !Ok {
  222. return nil, errors.New("未配置奖励类型 唯一ID:" + rewardsSheet[rowIdx][0])
  223. } else {
  224. one.GashType = gashTye
  225. }
  226. one.Prize = []model.ActPrize{}
  227. if one.GashType != luckyPrize {
  228. if one.Prize, err = Props.MultiParseActPrize(reward); err != nil {
  229. return nil, errors.WithStack(err)
  230. }
  231. }
  232. stageRewardArrMap[id] = append(stageRewardArrMap[id], one)
  233. }
  234. return stageRewardArrMap, nil
  235. }
  236. func (This *actSuperGashapon) packageShowConf(layers []model.ThreeLayer, rewardMap map[int64][]model.SuperGashaponStageReward, tokenGoodsMap map[int64]model.TokenGoods) (showConfArr []model.SuperGashaponShowConf, err error) {
  237. showConfArr = make([]model.SuperGashaponShowConf, 0, len(layers))
  238. for _, layer := range layers {
  239. reward, Ok := rewardMap[layer.Id]
  240. if !Ok {
  241. return showConfArr, errors.New("未配置奖励项")
  242. }
  243. tokenGoods, Ok := tokenGoodsMap[layer.Id]
  244. if !Ok {
  245. return showConfArr, errors.New("未配置代币商品项")
  246. }
  247. showConfArr = append(showConfArr, model.SuperGashaponShowConf{
  248. ThreeLayer: layer,
  249. Reward: reward,
  250. TokenGoods: tokenGoods,
  251. })
  252. }
  253. return
  254. }