package service import ( "fmt" "gadmin/config" "gadmin/internal/admin/consts" "gadmin/internal/admin/forms" "gadmin/internal/elastic/eapi" "gadmin/internal/gorm/model" "gadmin/internal/gorm/query" "gadmin/utility" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "os" "strings" ) // Chapter 章节服务 var Chapter = new(sChapter) type sChapter struct{} //func (s *sChapter) OrdinaryList(ctx *gin.Context, req forms.ChapterOrdinaryListReq) (resp serializer.Response) { // type passData struct { // Id int32 `json:"id"` // Name string `json:"name"` // RoomCount int32 `json:"roomCount"` // Count int64 `json:"count"` // Difficulty int64 `json:"difficulty"` // Pass bool `json:"pass"` // IsActivity bool `json:"isActivity"` // } // // DB, err := player.GetDBByUserId(req.PlayerId) // if err != nil { // return serializer.Err(consts.CodeParamErr, "GetDBByUserId err", err) // } // // var ( // p = query.Use(config.GDBGroup[DB]).PlayerMaterial // passDatas []passData // models forms.ListRes // ) // material, err := p.WithContext(ctx).Where(p.Playerid.Eq(req.PlayerId)).First() // if err != nil { // return serializer.Err(consts.CodeParamErr, "查询出错 Find", err) // } // // if material == nil || material.ID == 0 || material.PassRoom == "null" { // return serializer.Suc(models) // } // // if err := json.Unmarshal([]byte(material.PassRoom), &passDatas); err != nil { // return serializer.Err(consts.CodeParamErr, "Unmarshal err", err) // } // // tmp := make([]passData, 0) // for k, v := range passDatas { // if v.Id == 0 || v.Id > 99 { // continue // } // data := gmdata.GetChapterById(v.Id) // if data == nil { // data = &gmdata.Chapter{ // Name: `未知`, // } // } // passDatas[k].Name = data.Name // passDatas[k].RoomCount = data.RoomCount // tmp = append(tmp, passDatas[k]) // } // // // 使用自定义的 Less 函数来指定排序规则 // sort.SliceStable(tmp, func(i, j int) bool { // if tmp[i].Id != tmp[j].Id { // return tmp[i].Id < tmp[j].Id // 根据 Id 升序排列 // } // return tmp[i].Difficulty < tmp[j].Difficulty // 如果 Id 相同,则根据 Difficulty 升序排列 // }) // // models.List = tmp // // return serializer.Suc(models) //} //func (s *sChapter) ActivityList(ctx *gin.Context, req forms.ChapterActivityListReq) (resp serializer.Response) { // type passData struct { // Id int32 `json:"id"` // Difficulty int32 `json:"difficulty"` // DifficultyName string `json:"difficultyName"` // Name string `json:"name"` // Degree int32 `json:"degree"` // RewardMulti float64 `json:"rewardMulti"` // RewardEffectTime int64 `json:"rewardEffectTime"` // ChallengeCount int64 `json:"challenge_count"` // ClearanceCount int64 `json:"clearance_count"` // FailCount int64 `json:"fail_count"` // } // // DB, err := player.GetDBByUserId(req.PlayerId) // if err != nil { // return serializer.Err(consts.CodeParamErr, "GetDBByUserId err", err) // } // // var ( // c = query.Use(config.DB).Chapter // passDatas []passData // models forms.ListRes // z = query.Use(config.GDBGroup[DB]).ZoneActivity // ) // chapters, err := c.WithContext(ctx).Where(c.PlayerID.Eq(req.PlayerId)).Find() // if err != nil { // return serializer.Err(consts.CodeParamErr, "查询出错 Find", err) // } // // if len(chapters) == 0 { // return serializer.Suc(models) // } // // zone, err := z.WithContext(ctx).Where(z.Playerid.Eq(req.PlayerId)).First() // if err != nil { // return serializer.Err(consts.CodeParamErr, "查询出错 Find", err) // } // // // BonusProperties 加成属性 // type BonusProperties struct { // DifScale int `json:"difScale"` // 难度系数 // RewardMulti float64 `json:"rewardMulti"` // 奖励倍数 // RewardEffectTime int64 `json:"rewardEffectTime"` // 奖励倍数生效时间 // } // // bonusProperties := make(map[string]*BonusProperties) // //difficulty := make(map[string]int32) // if zone != nil { // if err = json.Unmarshal([]byte(zone.BonusProperties), &bonusProperties); err != nil { // return serializer.Err(consts.CodeParamErr, "Unmarshal err", err) // } // } // // logrus.Warnf("bonusProperties:%+v", bonusProperties) // // //chapterIds := []int64{100, 101, 102, 103} // //var difficultys = []int32{0, 1, 2} // // for _, v := range chapters { // var data = gmdata.GetChapterById(v.ChapterID) // if data == nil { // data = &gmdata.Chapter{ // Name: `未知`, // } // } // // //var ds = []int32{0, 1, 2} // //if v.ChapterID == 103 { // // ds = []int32{0} // //} // // // //for _, difficulty := range ds { // // // // // //} // // bs, ok := bonusProperties[fmt.Sprintf("%v_%v", v.ChapterID, v.Difficulty)] // if ok { // passDatas = append(passDatas, passData{ // Id: v.ChapterID, // Difficulty: v.Difficulty, // DifficultyName: gmdata.GetDifficultName(int64(v.Difficulty)), // Name: data.Name, // Degree: int32(bs.DifScale), // RewardMulti: bs.RewardMulti, // RewardEffectTime: bs.RewardEffectTime, // ChallengeCount: int64(v.ClearanceCount + v.FailCount), // ClearanceCount: int64(v.ClearanceCount), // FailCount: int64(v.FailCount), // }) // } else { // // 没有数据视为没有参与过,直接不显示 // //passDatas = append(passDatas, passData{ // // Id: v.ChapterID, // // Difficulty: difficulty, // // Name: data.Name, // // Degree: 100, // 这里写死了100,其实有的初始值并不是100,需要知道 // // RewardMulti: 1, // // RewardEffectTime: 0, // // ChallengeCount: int64(v.ClearanceCount + v.FailCount), // // ClearanceCount: int64(v.ClearanceCount), // // FailCount: int64(v.FailCount), // //}) // } // // } // // // 远征 // var ( // cf = query.Use(config.GDBGroup[DB]).Climbfloor // ) // cfd, _ := cf.WithContext(ctx).Where(cf.Playerid.Eq(req.PlayerId)).First() // //if err != nil { // // return serializer.Err(consts.CodeParamErr, "查询出错 Climbfloor Find", err) // //} // // if cfd == nil { // passDatas = append(passDatas, passData{ // Id: 105, // Name: "远征", // Degree: 0, // DifficultyName: gmdata.GetDifficultName(int64(0)), // //ChallengeCount: int64(v.ClearanceCount + v.FailCount), // //ClearanceCount: int64(v.ClearanceCount), // //FailCount: int64(v.FailCount), // }) // } else { // passDatas = append(passDatas, passData{ // Id: 105, // Name: "远征", // Degree: cfd.MaxFloor, // DifficultyName: gmdata.GetDifficultName(int64(0)), // //ChallengeCount: int64(v.ClearanceCount + v.FailCount), // //ClearanceCount: int64(v.ClearanceCount), // //FailCount: int64(v.FailCount), // }) // } // // models.List = passDatas // // return serializer.Suc(models) //} func (s *sChapter) doReconnectFromDB(ctx *gin.Context, params forms.ChapterReconnectReq, chapterId, difficulty int32, isNew bool) (count, userCount int64, err error) { type Result struct { TotalCount int64 `gorm:"total_count"` UserCount int64 `gorm:"user_count"` } begin, end, _ := utility.GetBeginAndEndOfDay2(params.Day, params.EndDay) end = end + 1 table := model.GetChapterTable2(chapterId) var ( q = query.Use(config.DB).ChapterLog.Table(table) db = q.UnderlyingDB() ) db = db.Where("event_id = 2 and extra like '%0%' and difficulty = ? and event_at >= ? and event_at <= ?", difficulty, begin, end) if params.ServerId > 0 { db = db.Where("server_id = ?", params.ServerId) } switch params.ChannelId { case consts.ChannelIdNone: // 不选择渠道 case consts.ChannelIdAllAdv, consts.ChannelIdAllWx, consts.ChannelIdAllTT: // 所有广告渠道 db = db.Where("channel_id in (?)", Channel.GetIdsByType(params.ChannelId)) default: // 选择指定渠道 db = db.Where("channel_id = ?", params.ChannelId) } res := make([]*Result, 0) if isNew { err = db.Select("count(*) AS total_count, count( DISTINCT user_id ) AS user_count, DATE (FROM_UNIXTIME( user_created_at )) AS d").Where("user_created_at >= ? and user_created_at <= ?", begin, end).Group("d").Find(&res).Error } else { err = db.Select("count(*) AS total_count, count( DISTINCT user_id ) AS user_count").Find(&res).Error } if err != nil { logrus.Errorf("查询出错:%+v", err) if strings.Contains(err.Error(), "1146") { createSql := "CREATE TABLE IF NOT EXISTS `%s` (`id` bigint unsigned NOT NULL AUTO_INCREMENT,`channel_id` varchar(128) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '渠道ID',`flag` int DEFAULT '0',`user_id` bigint unsigned NOT NULL COMMENT '用户id',`server_id` int NOT NULL DEFAULT '1' COMMENT '服务器ID',`event_id` tinyint unsigned NOT NULL COMMENT '埋点id',`chapter_id` smallint unsigned NOT NULL COMMENT '关卡id',`difficulty` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '困难度',`room_id` bigint NOT NULL COMMENT '房间id',`user_created_at` int unsigned NOT NULL COMMENT '用户注册时间',`event_at` int unsigned NOT NULL COMMENT '埋点事件触发的时间',`event_at_ns` bigint unsigned NOT NULL,`token` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '登陆的token',`extra` text COLLATE utf8mb4_general_ci COMMENT '其他参数',PRIMARY KEY (`id`),UNIQUE KEY `user_event_ns` (`user_id`,`event_at_ns`),KEY `created_chapter_event_event_at_idx` (`user_created_at`,`chapter_id`,`event_id`,`event_at`),KEY `event_id_event_at_idx` (`event_id`,`event_at`),KEY `server_id` (`server_id`),KEY `channel_id` (`channel_id`),KEY `idx_event_id` (`event_id`) USING BTREE,KEY `server_id_difficulty_user_id_event_id_extra_index` (`server_id`,`difficulty`,`user_id`,`event_id`),KEY `chapter_logs_100_event_at_index` (`event_at`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='关卡信息埋点日志';" if err := q.UnderlyingDB().Exec(fmt.Sprintf(createSql, table)).Error; err != nil { logrus.Errorf("创建表%s错误:%+v", table, err) } } return 0, 0, err } for _, v := range res { count += v.TotalCount userCount += v.UserCount } return } func (s *sChapter) doReconnect(ctx *gin.Context, params forms.ChapterReconnectReq, chapterId, difficulty int32, isNew bool) (count, userCount int64, err error) { begin, end, _ := utility.GetBeginAndEndOfDay2(params.Day, params.EndDay) end = end + 1 index := fmt.Sprintf("%s%s", os.Getenv("ELASTIC_TOPIC"), model.GetChapterTable2(chapterId)) var ( mustNot []eapi.M where eapi.M ) must := []eapi.M{ { "term": eapi.M{ "event_id": "2", }, }, { "match": eapi.M{ "extra": "0", }, }, { "term": eapi.M{ "chapter_id": chapterId, }, }, { "term": eapi.M{ "difficulty": difficulty, }, }, { "range": eapi.M{ "event_at": eapi.M{ "gte": begin, "lte": end, }, }, }, } if params.ServerId > 0 { must = append(must, eapi.M{ "term": eapi.M{ "server_id": params.ServerId, }, }) } switch params.ChannelId { case consts.ChannelIdNone: // 不选择渠道 case consts.ChannelIdAllAdv, consts.ChannelIdAllWx, consts.ChannelIdAllTT: // 所有广告渠道 must = append(must, eapi.M{ "terms": eapi.M{ "channel_id": Channel.GetIdsByType(params.ChannelId), }, }) default: // 选择指定渠道 must = append(must, eapi.M{ "term": eapi.M{ "channel_id": params.ChannelId, }, }) } //if params.ChannelId != "" { // if params.ChannelId == "1" { // mustNot = append(mustNot, eapi.M{ // "term": eapi.M{ // "channel_id": "0", // }, // }) // } else { // must = append(must, eapi.M{ // "term": eapi.M{ // "channel_id": params.ChannelId, // }, // }) // } // //} // 新用户 if isNew { // 同一天 if begin+86400 == end { must = append(must, eapi.M{ "range": eapi.M{ "user_created_at": eapi.M{ "gte": begin, "lte": end, }, }, }) } else { // 多天的,分析每天的新用户 for i := begin; i < end; i += 86400 { var newMust = must newMust = append(newMust, eapi.M{ "range": eapi.M{ "user_created_at": eapi.M{ "gte": i, "lte": i + 86400, }, }, }) if len(mustNot) > 0 { where = eapi.M{ "query": eapi.M{ "bool": eapi.M{ "must": newMust, "must_not": mustNot, }, }, } } else { where = eapi.M{ "query": eapi.M{ "bool": eapi.M{ "must": newMust, }, }, } } res, err := eapi.Count(ctx, index, where) if err != nil { return 0, 0, err } if res > 0 { count += res } res2, err := eapi.Cardinality(ctx, index, where, "user_id") if err != nil { return 0, 0, err } if res2 > 0 { userCount += res2 } } return } } if len(mustNot) > 0 { where = eapi.M{ "query": eapi.M{ "bool": eapi.M{ "must": must, "must_not": mustNot, }, }, } } else { where = eapi.M{ "query": eapi.M{ "bool": eapi.M{ "must": must, }, }, } } //logrus.Warnf("doReconnect index:%v\n where:%v\n", index, utility.DumpToJSON(where)) res, err := eapi.Count(ctx, index, where) if err != nil { return 0, 0, err } res2, err := eapi.Cardinality(ctx, index, where, "user_id") if err != nil { return 0, 0, err } return res, res2, nil } //func (s *sChapter) Reconnect(ctx *gin.Context, params forms.ChapterReconnectReq) (resp serializer.Response) { // chapterMap := gmdata.GetChaptersMap() // var ( // wg sync.WaitGroup // errCh = make(chan error, len(chapterMap)) // ) // // list := make([]forms.ChapterReconnectItem, 0) // for _, v := range chapterMap { // wg.Add(1) // go func(v *gmdata.Chapter) { // defer wg.Done() // //count, users, err := s.doReconnect(ctx, params, int32(v.ID), int32(v.Difficulty), false) // count, users, err := s.doReconnectFromDB(ctx, params, int32(v.ID), int32(v.Difficulty), false) // if err != nil { // errCh <- err // return // } // // //newCount, newUsers, err := s.doReconnect(ctx, params, int32(v.ID), int32(v.Difficulty), true) // newCount, newUsers, err := s.doReconnectFromDB(ctx, params, int32(v.ID), int32(v.Difficulty), true) // if err != nil { // errCh <- err // return // } // // list = append(list, forms.ChapterReconnectItem{ // Id: len(list), // ChapterId: int(v.ID), // Chapter: Dash.GetChapterName(v.ID, v.Difficulty), // DifficultyIndex: int(v.Difficulty), // Difficulty: gmdata.GetDifficultName(v.Difficulty), // DieCount: count, // DieUserCount: users, // NewDieCount: newCount, // NewDieUserCount: newUsers, // }) // }(v) // } // // wg.Wait() // // select { // case err1 := <-errCh: // return serializer.Err(consts.CodeParamErr, err1.Error(), err1) // default: // // } // // for k, v := range list { // list[k].Index = v.ChapterId*1000 + v.DifficultyIndex // } // sort.Sort(forms.ChapterReconnectItemSlice(list)) // // pageCount := int64(len(list)) // models := new(forms.ChapterReconnectRespData) // models.Page = params.Page // models.PerPage = params.PerPage // models.PageCount = int64(math.Ceil(float64(pageCount) / float64(params.PerPage))) // // startInx := (models.Page - 1) * models.PerPage // endInx := (models.Page) * models.PerPage // if startInx < 0 { // startInx = 0 // } // if endInx > pageCount { // endInx = pageCount // } // subList := list[startInx:endInx] // // models.List = subList // return serializer.Suc(models) //}