package service import ( "fmt" "sort" "strconv" "crazy-fox-backend-api/utils" "crazy-fox-backend-api/config" "crazy-fox-backend-api/model" "crazy-fox-backend-api/utils/uniqid" "github.com/dablelv/go-huge-util/conv" "github.com/jmoiron/sqlx/types" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" ) type actRank struct{} // 展示数据处理 func (This *actRank) handleActShow(confInfo *model.ActConfInfo) (types.JSONText, error) { rewardPro, err := This.formatRankRewardProShow(confInfo.RewardPro) if err != nil { return nil, errors.WithStack(err) } extraData, err := This.formatRankExtraDataShow(confInfo) if err != nil { return nil, errors.WithStack(err) } ExtraConf := model.ExtraConf{ Reward: confInfo.Reward, ExtraReward: confInfo.ExtraReward, RewardConf: confInfo.RewardConf, RewardPro: rewardPro, ExtraData: extraData, } return jsoniter.Marshal(ExtraConf) } // 保存数据处理 func (This *actRank) handleActSave(confInfo *model.ActConfInfo) error { var rewardMap model.ExtraConf var err error if err = jsoniter.Unmarshal(confInfo.ActShowConf, &rewardMap); err != nil { return errors.Wrap(err, "锦标赛Json解析失败") } // 格式化奖励数据 if confInfo.RewardPro, err = This.formatRankRewardPro(rewardMap.RewardPro); err != nil { return errors.Wrap(err, "格式化奖励数据") } // 格式化收集积分配置 if confInfo.RewardConf, err = This.formatRankRewardConf(confInfo.Type, rewardMap.RewardConf); err != nil { return errors.Wrap(err, "格式化收集积分配置") } // 格式化分房与机器人配置 if confInfo.ExtraData, err = This.formatRankExtraData(confInfo.Type, rewardMap.ExtraData); err != nil { return errors.Wrap(err, "格式化分房与机器人配置") } return nil } // 分层数据处理 func (This *actRank) handleActRewardSection(confInfo *model.ActConfInfo, maps ...map[string]any) error { var repoConfMap map[int64]model.RankRewardRepoConf if err := jsoniter.Unmarshal(confInfo.RewardPro, &repoConfMap); err != nil { return errors.Wrap(err, "锦标赛 rewardPro 解析失败") } conditionMap, rewardMap := maps[0], maps[1] for idx1, item1 := range repoConfMap { for idx2, item2 := range item1.Stages { for idx3, item3 := range item2.Stages { stageKey := fmt.Sprintf("%d_%d_%d", idx1, idx2, idx3) conditionMap[stageKey] = Activity.buildStageCondition( model.LvRange{LvStart: item1.Start, LvEnd: item1.End}, model.SpinsRange{SpinsStart: item2.Start, SpinsEnd: item2.End}, item3.SsGroup, ) rewardMap[stageKey] = item3.Stages } } } return nil } // 导入数据处理 func (This *actRank) handleActImport(detailInfo *model.ActDetailInfo, excelInfo [][][]string) (json types.JSONText, err error) { isProgress := false // 是否为有进度活动 if utils.InSlice(detailInfo.Type, []string{config.ActRank, config.ActBuildRank}) { isProgress = true } sheetLen := utils.Ternary(isProgress, 8, 7) if len(excelInfo) != sheetLen { return json, errors.New("奖励配置异常") } isBuildRank := true // 是否为建筑锦标赛 if utils.InSlice(detailInfo.Type, []string{config.ActRank, config.ActRank2}) { isBuildRank = false } sheet2Array := excelInfo[1] sheet3Array := excelInfo[2] sheet4Array := excelInfo[3] sheet5Array := excelInfo[4] sheet6Array := excelInfo[5] sheet7Array := excelInfo[6] extraConf := model.ExtraConf{} if isBuildRank { // 建筑锦标赛积分配置 if extraConf.RewardConf, err = This.parseBuildRankScoreSheet(sheet2Array); err != nil { return json, errors.WithStack(err) } } else { // 锦标赛积分配置 if extraConf.RewardConf, err = This.parseRankScoreSheet(sheet2Array); err != nil { return json, errors.WithStack(err) } } // 锦标赛房间配置 if extraConf.ExtraData, err = This.parseRankExtraDataSheet(isBuildRank, sheet3Array, sheet4Array, sheet5Array); err != nil { return json, errors.WithStack(err) } // 锦标赛奖励配置 rewardSheetArr := [][][]string{sheet6Array, sheet7Array} if isProgress { rewardSheetArr = append(rewardSheetArr, excelInfo[7]) } if extraConf.RewardPro, err = This.parseRankRewardProSheet(rewardSheetArr); err != nil { return json, errors.WithStack(err) } if json, err = jsoniter.Marshal(extraConf); err != nil { return json, errors.Wrap(err, "锦标赛配置序列化失败") } return } func (This *actRank) formatRankRewardProShow(rewardPro types.JSONText) (types.JSONText, error) { var confMap map[int64]model.RankRewardRepoConf if err := jsoniter.Unmarshal(rewardPro, &confMap); err != nil { return nil, errors.Wrap(err, "锦标赛 rewardPro解析失败") } var rewardProArray []model.RankRewardShowConf for lvIdx, lvStages := range confMap { for spinIdx, spinsStages := range lvStages.Stages { for ssGroupIdx, ssGroupStages := range spinsStages.Stages { rewardProArray = append(rewardProArray, model.RankRewardShowConf{ Idx: Activity.buildLayerOrderId(lvIdx, spinIdx, ssGroupIdx), LvRange: model.LvRange{LvStart: lvStages.Start, LvEnd: lvStages.End}, SpinsRange: model.SpinsRange{SpinsStart: spinsStages.Start, SpinsEnd: spinsStages.End}, SsGroup: ssGroupStages.SsGroup, RankRewardShow: model.RankRewardShow{ Ranks: utils.MapValues(ssGroupStages.Stages.Ranks, true), Stages: utils.MapValues(ssGroupStages.Stages.Stages, true), }, }) } } } sort.SliceStable(rewardProArray, func(i, j int) bool { return rewardProArray[i].Idx < rewardProArray[j].Idx }) return jsoniter.Marshal(rewardProArray) } func (This *actRank) formatRankExtraDataShow(confInfo *model.ActConfInfo) (types.JSONText, error) { var dataRepo model.RankExtraDataRepo if err := jsoniter.Unmarshal(confInfo.ExtraData, &dataRepo); err != nil { return nil, errors.Wrap(err, "锦标赛 extraData 解析失败") } dataShow := model.RankExtraDataShow{ RankExtraData: dataRepo.RankExtraData, Robot: utils.MapValues(dataRepo.Robot, true), } // 锦标赛版本兼容 if utils.InSlice(confInfo.Type, []string{config.ActRank, config.ActRank2}) { dataShow.RoomAllotConf = This.formatRankRoomAllotConf(dataRepo) } return jsoniter.Marshal(dataShow) } func (This *actRank) formatRankRoomAllotConf(dataRepo model.RankExtraDataRepo) (showConfArr []model.RankRoomAllotShowConf) { if utils.IsEmpty(dataRepo.RoomAllotConf) { allotStage := make([]model.RankRoomAllotStage, 0, len(dataRepo.SpinsSet)) for i := 0; i < len(dataRepo.SpinsSet)-1; i++ { allotStage = append(allotStage, model.RankRoomAllotStage{ SpinsRange: model.SpinsRange{ SpinsStart: dataRepo.SpinsSet[i], SpinsEnd: dataRepo.SpinsSet[i+1] - 1, }, RobotStop: dataRepo.SpinsSetSpins[i], }) } dataRepo.RoomAllotConf = []model.RankRoomAllotRepoConf{ { LvRange: model.LvRange{ LvStart: 0, LvEnd: 999999999, }, Stages: allotStage, }, } } for _, item1 := range dataRepo.RoomAllotConf { for _, item2 := range item1.Stages { showConfArr = append(showConfArr, model.RankRoomAllotShowConf{ LvRange: item1.LvRange, SpinsRange: item2.SpinsRange, RobotStop: item2.RobotStop, }) } } return } // 格式化奖励数据 func (This *actRank) formatRankRewardPro(rewardProJson types.JSONText) (types.JSONText, error) { var ( err error rankRwdPro []model.RankRewardShowConf rankRwdProRepo = map[int64]model.RankRewardRepoConf{} unique = uniqid.GetUniqId() ) defer uniqid.DelMapByUniqId(unique) if err = jsoniter.Unmarshal(rewardProJson, &rankRwdPro); err != nil { return nil, errors.Wrap(err, "锦标赛Json解析失败") } for _, one := range rankRwdPro { idxes := uniqid.GetStageIdx(unique, one.LvRange, one.SpinsRange, one.SsGroup) lvIdx, spinIdx, ssIdx := idxes[0], idxes[1], idxes[2] if _, Ok := rankRwdProRepo[lvIdx]; !Ok { rankRwdProRepo[lvIdx] = model.RankRewardRepoConf{ StartEnd: model.StartEnd{Start: one.LvStart, End: one.LvEnd}, Stages: map[int64]model.RankRewardSpinsStage{}, } } if _, Ok := rankRwdProRepo[lvIdx].Stages[spinIdx]; !Ok { rankRwdProRepo[lvIdx].Stages[spinIdx] = model.RankRewardSpinsStage{ StartEnd: model.StartEnd{Start: one.SpinsStart, End: one.SpinsEnd}, Stages: map[int64]model.RankRewardSsGroupStage{}, } } if _, Ok := rankRwdProRepo[lvIdx].Stages[spinIdx].Stages[ssIdx]; !Ok { rankRwdProRepo[lvIdx].Stages[spinIdx].Stages[ssIdx] = model.RankRewardSsGroupStage{ SsGroup: one.SsGroup, Stages: model.RankRewardStage{ Ranks: utils.Slice2Map(one.Ranks), Stages: utils.Slice2Map(one.Stages), }, } } } return jsoniter.Marshal(rankRwdProRepo) } // 格式化收集积分配置 func (This *actRank) formatRankRewardConf(actType string, rewardConfJson types.JSONText) (types.JSONText, error) { var rankRewardConf any switch actType { case config.ActRank, config.ActRank2: rankRewardConf = model.RankCollectConf{} case config.ActBuildRank, config.ActBuildRank2: rankRewardConf = model.BuildRankScoreConf{} default: return nil, errors.Wrap(nil, "活动类型异常:"+actType) } var err error if err = jsoniter.Unmarshal(rewardConfJson, &rankRewardConf); err != nil { return nil, errors.Wrap(err, "锦标赛Json解析失败") } return jsoniter.Marshal(rankRewardConf) } // 格式化分房与机器人配置 func (This *actRank) formatRankExtraData(actType string, extraDataJson types.JSONText) (types.JSONText, error) { var dataShow model.RankExtraDataShow if err := jsoniter.Unmarshal(extraDataJson, &dataShow); err != nil { return nil, errors.Wrap(err, "锦标赛Json解析失败") } extraDataRepo := model.RankExtraDataRepo{ RankExtraData: dataShow.RankExtraData, Robot: utils.Slice2Map(dataShow.Robot), RoomAllotConf: This.mapParseRankRoomAllotConf(dataShow.RoomAllotConf), } extraDataRepo.SetType = 2 if utils.InSlice(actType, []string{config.ActRank, config.ActRank2}) { extraDataRepo.SetType = 10 } return jsoniter.Marshal(extraDataRepo) } // 排名奖励 func (This *actRank) parseRanksReward(sheet [][]string) (map[int64][]model.RankRanksReward, error) { var ( err error rewardsMap = map[int64][]model.RankRanksReward{} ) for i := 1; i < len(sheet); i++ { var ( one = model.RankRanksReward{} id int64 reward = make([]model.ExcelPrize, 6) ) if err = utils.DestructAssign(sheet[i], &id, &one.RankPos, &reward); err != nil { return nil, errors.Wrap(err, fmt.Sprintf("第%d行 解析出错", i+1)) } if one.Prize, err = Props.MultiParseActPrize(reward); err != nil { return nil, errors.WithStack(err) } rewardsMap[id] = append(rewardsMap[id], one) } return rewardsMap, nil } // 阶段奖励 func (This *actRank) parseStagesReward(sheetInfo [][]string) (map[int64][]model.RankStageReward, error) { var ( reward = model.RankStageReward{} err error mapIdx int64 rewardsMap = map[int64][]model.RankStageReward{} ) excelPrizes := make([]model.ExcelPrize, 6, 6) for i := 1; i < len(sheetInfo); i++ { if err := utils.DestructAssign(sheetInfo[i], &mapIdx, &reward.Stage, &reward.ProgressBarId, &reward.StepNum, &excelPrizes); err != nil { return nil, errors.Wrap(err, fmt.Sprintf("第%d行", i+1)) } if reward.Prize, err = Props.MultiParseActPrize(excelPrizes); err != nil { return nil, err } rewardsMap[mapIdx] = append(rewardsMap[mapIdx], reward) } return rewardsMap, nil } // 锦标赛积分配置 func (This *actRank) parseRankScoreSheet(sheet [][]string) (types.JSONText, error) { rewardConf := model.RankCollectConf{} for _, line := range sheet { var ( tag string val int64 ) if err := utils.DestructAssign(line, &tag, &val); err != nil { return nil, errors.WithStack(err) } switch tag { case config.CollectTypeAttackSuccessImportText: rewardConf.AttackSuccess = val case config.CollectTypeAttackBreakImportText: rewardConf.AttackBreak = val case config.CollectTypeStealSuccessImportText: rewardConf.StealSuccess = val case config.CollectTypeStealBreakImportText: rewardConf.StealBreak = val case config.CollectTypeThreeHitImportText: rewardConf.ThreeHit = val } } return jsoniter.Marshal(rewardConf) } // 建筑锦标赛积分配置 func (This *actRank) parseBuildRankScoreSheet(sheet [][]string) (types.JSONText, error) { rewardConf := model.BuildRankRewardConf{} if sheet[0][0] == config.BuildRankMinScoreImportText { rewardConf.MinScore = conv.ToAny[int64](sheet[0][1]) } rewardConf.ActionConfig = make([]model.BuildRankScoreConf, 0, len(sheet)) for i := 2; i < len(sheet); i++ { one := model.BuildRankScoreConf{} if err := utils.DestructAssign(sheet[i], &one.MinLv, &one.MaxLv, &one.SingleGet[0], &one.SingleGet[1]); err != nil { return nil, errors.WithStack(err) } rewardConf.ActionConfig = append(rewardConf.ActionConfig, one) } return jsoniter.Marshal(rewardConf) } // 锦标赛分房间配置 func (This *actRank) parseRankExtraDataSheet(isBuildRank bool, allotSheet, robotSheet, limitSheet [][]string) (types.JSONText, error) { var err error extraData := model.RankExtraDataShow{} // 配置版本 extraData.SetType = int64(utils.Ternary(isBuildRank, 2, 10)) // 房间分配配置 if isBuildRank { if extraData.UserLvSet, extraData.UserLvSetRobotStop, err = This.parseBuildRankRoomAllotSheet(allotSheet); err != nil { return nil, errors.WithStack(err) } } else { if extraData.RoomAllotConf, err = This.parseRankRoomAllotSheet(allotSheet); err != nil { return nil, errors.WithStack(err) } } // 机器人配置 if extraData.Robot, err = This.parseRankRobotSheet(robotSheet); err != nil { return nil, errors.WithStack(err) } // 人数限制配置 if extraData.RankLimit, err = This.parseRankLimitSheet(limitSheet); err != nil { return nil, errors.WithStack(err) } return jsoniter.Marshal(extraData) } // 房间分配配置 func (This *actRank) parseRankRoomAllotSheet(sheet [][]string) ([]model.RankRoomAllotShowConf, error) { allotConfArr := make([]model.RankRoomAllotShowConf, 0, len(sheet)) for i := 1; i < len(sheet); i++ { var one model.RankRoomAllotShowConf if err := utils.DestructAssign(sheet[i], &one.LvRange, &one.SpinsRange, &one.RobotStop); err != nil { return nil, errors.WithStack(err) } allotConfArr = append(allotConfArr, one) } return allotConfArr, nil } // 房间分配配置 func (This *actRank) parseBuildRankRoomAllotSheet(sheet [][]string) ([]int64, []int64, error) { userArr := make([]int64, 0, len(sheet)) robotArr := make([]int64, 0, len(sheet)) for i := 1; i < len(sheet); i++ { var user, robot int64 if err := utils.DestructAssign(sheet[i], &user, &robot); err != nil { return nil, nil, errors.WithStack(err) } userArr = append(userArr, user) robotArr = append(robotArr, robot) } return userArr, robotArr, nil } // 机器人配置 func (This *actRank) parseRankRobotSheet(sheet [][]string) ([]model.RankRobot, error) { robotArr := make([]model.RankRobot, 0, len(sheet)) for i := 1; i < len(sheet); i++ { var one model.RankRobot if err := utils.DestructAssign(sheet[i], &one.Id, &one.Pro, &one.Num, &one.Co1, &one.Co2); err != nil { return nil, errors.WithStack(err) } robotArr = append(robotArr, one) } return robotArr, nil } // 人数限制配置 func (This *actRank) parseRankLimitSheet(sheet [][]string) ([]model.RankLimit, error) { limitArr := make([]model.RankLimit, 0, len(sheet)) for i := 1; i < len(sheet); i++ { var one model.RankLimit if err := utils.DestructAssign(sheet[i], &one.Time, &one.Limit); err != nil { return nil, err } limitArr = append(limitArr, one) } return limitArr, nil } // 奖励配置 func (This *actRank) parseRankRewardProSheet(sheetArr [][][]string) (types.JSONText, error) { if !utils.InSlice(len(sheetArr), []int{2, 3}) { return nil, errors.New("奖励配置异常") } var ( rankRwdPro []model.RankRewardShowConf stagesMap []model.ThreeLayer rankRewards map[int64][]model.RankRanksReward stageRewards map[int64][]model.RankStageReward err error ) if stagesMap, err = Activity.parseThreeLayerConf(sheetArr[0]); err != nil { return nil, errors.WithStack(err) } if rankRewards, err = This.parseRanksReward(sheetArr[1]); err != nil { return nil, errors.WithStack(err) } if len(sheetArr) == 3 { if stageRewards, err = This.parseStagesReward(sheetArr[2]); err != nil { return nil, errors.WithStack(err) } if len(stageRewards) == 0 { return nil, errors.New("未配置阶段奖励") } } rankRwdPro = make([]model.RankRewardShowConf, 0, len(stagesMap)) for _, layer := range stagesMap { rankReward, Ok := rankRewards[layer.Id] if !Ok { return nil, errors.New(strconv.Itoa(int(layer.Id)) + ":未配置排行奖励") } rankRwdProItem := model.RankRewardShowConf{ Idx: layer.Id, LvRange: layer.LvRange, SpinsRange: layer.SpinsRange, SsGroup: layer.SsGroup, RankRewardShow: model.RankRewardShow{Ranks: rankReward}, } if len(stageRewards) > 0 { stageReward, Ok := stageRewards[layer.Id] if !Ok { return nil, errors.New(strconv.Itoa(int(layer.Id)) + ":未配置阶段奖励") } rankRwdProItem.Stages = stageReward } rankRwdPro = append(rankRwdPro, rankRwdProItem) } return jsoniter.Marshal(rankRwdPro) } // 房间分区配置解析 func (This *actRank) mapParseRankRoomAllotConf(conf []model.RankRoomAllotShowConf) []model.RankRoomAllotRepoConf { var repoConfArr []model.RankRoomAllotRepoConf for _, one := range conf { sameLvRange := false for i, repoConf := range repoConfArr { if repoConf.LvRange == one.LvRange { repoConfArr[i].Stages = append(repoConfArr[i].Stages, model.RankRoomAllotStage{ SpinsRange: one.SpinsRange, RobotStop: one.RobotStop, }) sameLvRange = true break } } if !sameLvRange { repoConfArr = append(repoConfArr, model.RankRoomAllotRepoConf{ LvRange: one.LvRange, Stages: []model.RankRoomAllotStage{ { SpinsRange: one.SpinsRange, RobotStop: one.RobotStop, }, }, }) } } return repoConfArr }