package service import ( "crypto/md5" "encoding/hex" "encoding/json" "fmt" "math" "math/rand" "strconv" "strings" "time" "unicode/utf8" "go-common/app/interface/main/answer/model" "go-common/library/ecode" "go-common/library/log" "go-common/library/text/translate/chinese" "github.com/pkg/errors" "golang.org/x/net/context" ) const ( _hashSalt = "bilirqeust" // _ansURI = "/answer/img?qs_id=%v&ans1_hash=%s&ans2_hash=%s&ans3_hash=%s&ans4_hash=%s" _baseTypeID = 36 // 官方基础题库 _rankBtn = 7 * 24 * time.Hour _minType = 3 _maxType = 10 ) var ( _typeIdsMapping = map[int][]int{ 100001: {15, 16, 17}, 100002: {29, 30}, 100003: {12, 13}, // 22: 21, // 24: 23, // 35: 31, 36: 31, // 32: 30, 33: 30, 34: 30, // 29: 28, 37: 28, 7: 28, 8: 28, // 41: 5, 42: 5, 43: 5, 44: 5, 45: 5, 46: 5, 47: 5, 48: 5, 49: 5, 50: 5, 51: 5, 52: 5, } // 对外展示方式1 _typeMap1 = []*model.TypeInfo{ {Name: "游戏", Subs: []*model.SubType{ {ID: 8, Name: "动作射击"}, {ID: 9, Name: "冒险格斗"}, {ID: 100003, Name: "策略模拟"}, // {ID: 13, Name: "策略模拟"}, {ID: 14, Name: "音乐体育"}, }}, {Name: "影视", Subs: []*model.SubType{ {ID: 15, Name: "纪录片"}, {ID: 16, Name: "电影"}, {ID: 17, Name: "电视剧"}, }}, {Name: "科技", Subs: []*model.SubType{ {ID: 18, Name: "军事"}, {ID: 19, Name: "地理"}, {ID: 20, Name: "历史"}, {ID: 21, Name: "文学"}, {ID: 22, Name: "数学"}, {ID: 23, Name: "物理"}, {ID: 24, Name: "化学"}, {ID: 25, Name: "生物"}, {ID: 26, Name: "数码科技"}, }}, {Name: "动画", Subs: []*model.SubType{ {ID: 27, Name: "国创"}, {ID: 28, Name: "番剧"}, }}, {Name: "艺术", Subs: []*model.SubType{ {ID: 100002, Name: "音乐"}, // {ID: 30, Name: "音乐"}, {ID: 31, Name: "绘画"}, }}, {Name: "流行前线", Subs: []*model.SubType{ {ID: 32, Name: "娱乐"}, {ID: 33, Name: "时尚"}, {ID: 34, Name: "运动"}, }}, {Name: "鬼畜", Subs: []*model.SubType{ {ID: 35, Name: "鬼畜"}, }}, } // 推荐分区映射 _recTypeIDMap = map[int]map[string][]int{ 124: {"main_tid": []int{1, 167}, "sub_tid": []int{3, 129}}, 127: {"main_tid": []int{1, 167}, "sub_tid": []int{3, 4}}, 126: {"main_tid": []int{3, 119}, "sub_tid": []int{1}}, 123: {"main_tid": []int{3}, "sub_tid": []int{129, 119}}, 121: {"main_tid": []int{36, 177}, "sub_tid": []int{160}}, 125: {"main_tid": []int{4}, "sub_tid": []int{129}}, 129: {"main_tid": []int{36, 177}, "sub_tid": []int{160}}, 130: {"main_tid": []int{23, 11}, "sub_tid": []int{160}}, 128: {"main_tid": []int{119}, "sub_tid": []int{160}}, } ) // BaseQ base question. func (s *Service) BaseQ(c context.Context, mid int64, lang string, mobile bool) (res *model.AnsQueDetailList, err error) { var aqs *model.AnsQuesList if aqs, err = s.BaseQs(c, mid, lang, mobile); err != nil { err = errors.Wrapf(err, "s.ansRPC.BaseQs(%d,%t)", mid, mobile) return } res = s.convertModel(aqs) return } // BaseQs get base question func (s *Service) BaseQs(c context.Context, mid int64, lang string, mobile bool) (rqs *model.AnsQuesList, err error) { var ( ids []int64 now = time.Now() ) if s.checkAnswerBlock(c, mid) { err = ecode.AnswerBlock return } h, err := s.history(c, mid) if err == nil && h != nil { if h.StartTime.Add(s.answerDuration()).After(now) && h.Score == 0 { if h.StepExtraCompleteTime != 0 { err = ecode.AnswerProNoPass // extra question pass return } err = ecode.AnswerExtraNoPass return } if h.Score > 0 && h.IsPassCaptcha == 0 { err = ecode.AnswerCaptchaNoPassed return } } ids, err = s.answerDao.IdsCache(c, mid, model.Q) if err != nil || len(ids) != s.c.Answer.BaseNum { ids, err = s.answerDao.QidByType(c, _baseTypeID, uint8(s.c.Answer.BaseNum)) if err != nil { log.Error("s.answerDao.QidByType(%d,%d) error(%v)", _baseTypeID, s.c.Answer.BaseNum, err) return } if len(ids) == 0 { err = ecode.AnswerQsNumErr log.Error("qidByType ids len(%d) is 0", len(ids)) return } } rqs, err = s.concatData(c, mid, ids, lang, mobile, s.c.Answer.BaseNum) if err != nil { log.Error("BaseQs s.concatData(%d, %d, %d) error(%v)", c, mid, ids, err) return } at := &model.AnswerTime{ Stime: now, Etimes: 0, } err = s.answerDao.SetExpireCache(c, mid, at) rqs.CurrentTime = at.Stime rqs.EndTime = at.Stime.Add(s.answerDuration()) s.answerDao.DelIdsCache(c, mid, model.BaseExtraPassQ) s.answerDao.DelIdsCache(c, mid, model.BaseExtraNoPassQ) return } // ConvertExtraQs extra question. func (s *Service) ConvertExtraQs(c context.Context, mid int64, lang string, mobile bool) (res *model.AnsQueDetailList, err error) { var ans *model.AnsQuesList if ans, err = s.ExtraQs(c, mid, lang, mobile); err != nil { err = errors.Wrapf(err, "s.ansRPC.ExtraQues(%d,%t)", mid, mobile) return } res = s.convertExtraModel(ans) return } // ExtraQs extra question. func (s *Service) ExtraQs(c context.Context, mid int64, lang string, mobile bool) (rqs *model.AnsQuesList, err error) { var ( ids []int64 passids []int64 npassids []int64 now = time.Now() ) if s.checkAnswerBlock(c, mid) { err = ecode.AnswerBlock return } h, err := s.checkExtraState(c, mid, now) if err != nil { return } // keep on answer passids, _ = s.answerDao.IdsCache(c, mid, model.BaseExtraPassQ) npassids, err = s.answerDao.IdsCache(c, mid, model.BaseExtraNoPassQ) if err != nil || len(passids) != s.c.Answer.BaseExtraPassNum || len(npassids) != s.c.Answer.BaseExtraNoPassNum { var ( ok bool ) ok, passids, npassids = s.extraQueByBigData(c, mid, "") if !ok { // if bigdata get extra mid faild passids, err = s.answerDao.ExtraQidByType(c, model.BaseExtraPassQ, uint8(s.c.Answer.BaseExtraPassNum)) if err != nil { log.Error("s.answerDao.ExtraQidByType(%d, %d, %d) error(%v)", model.BaseExtraPassQ, s.c.Answer.BaseExtraPassNum, len(passids), err) return } if len(passids) != s.c.Answer.BaseExtraPassNum { err = ecode.AnswerQsNumErr log.Warn("passids lenth(%d) neq BaseExtraPassNum(%d)", len(passids), s.c.Answer.BaseExtraPassNum) return } npassids, err = s.answerDao.ExtraQidByType(c, model.BaseExtraNoPassQ, uint8(s.c.Answer.BaseExtraNoPassNum)) if err != nil { log.Error("s.answerDao.ExtraQidByType(%d, %d, %d) error(%v)", model.BaseExtraNoPassQ, s.c.Answer.BaseExtraNoPassNum, len(npassids), err) return } if len(npassids) != s.c.Answer.BaseExtraNoPassNum { err = ecode.AnswerQsNumErr log.Warn("npassids lenth(%d) neq BaseExtraNoPassNum(%d)", len(npassids), s.c.Answer.BaseExtraNoPassNum) return } } } ids = append(passids, npassids...) rqs, err = s.concatExtraData(c, mid, ids, passids, npassids, lang, mobile, s.c.Answer.BaseExtraPassNum+s.c.Answer.BaseExtraNoPassNum) if err != nil { log.Error("BaseExtraQs s.concatExtraData(%d, %d, %d) error(%v)", c, mid, ids, err) return } rqs.CurrentTime = now rqs.EndTime = h.StartTime.Add(s.answerDuration()) if _, err = s.answerDao.UpdateExtraStartTime(c, h.ID, mid, now); err != nil { log.Error("s.answerDao.UpdateExtraStartTime( %d, %d) error(%v)", h.ID, mid, err) return } h.StepExtraStartTime = now h.Mtime = now s.userActionLog(mid, model.ExtraStartTime, h) s.answerDao.DelHistoryCache(c, mid) return } func (s *Service) checkExtraState(c context.Context, mid int64, now time.Time) (h *model.AnswerHistory, err error) { h, err = s.history(c, mid) if err != nil { log.Error("s.history(%v) is nil error(%v)", h, err) err = ecode.AnswerBaseNotPassed return } if h != nil { if h.Score > 0 && h.IsPassCaptcha == 0 { err = ecode.AnswerCaptchaNoPassed return } // if base pass if h.StartTime.Add(s.answerDuration()).After(now) && h.Score == 0 { if h.StepExtraCompleteTime != 0 { err = ecode.AnswerProNoPass } return } err = ecode.AnswerBaseNotPassed return } err = ecode.AnswerBaseNotPassed return } // ProTypes get promotion types. func (s *Service) proTypes(c context.Context, mid int64) (res *model.ProTypes, err error) { var ( repro bool ah *model.AnswerHistory now = time.Now() ) if s.checkAnswerBlock(c, mid) { err = ecode.AnswerBlock return } if ah, err = s.checkBase(c, mid, now); err != nil { return } qsidsMc, err := s.answerDao.IdsCache(c, mid, model.Q) if err == nil && len(qsidsMc) == s.c.Answer.ProNum { repro = true } res = &model.ProTypes{List: _typeMap1, EndTime: ah.StartTime.Add(s.answerDuration()), CurrentTime: now, Repro: repro} return } // ProType type. func (s *Service) ProType(c context.Context, mid int64, lang string) (res *model.AnsProType, err error) { var ( repro string list = []*model.AnsTypeList{} ) rpcRes, err := s.proTypes(c, mid) if err != nil { log.Error("s.proTypes(%+d) error (%v)", mid, err) return } for _, vt := range rpcRes.List { var sub = []*model.AnsType{} for _, vst := range vt.Subs { ansType := &model.AnsType{ID: vst.ID, Name: vst.Name} if lang == model.LangZhTW { ansType.Name = chinese.Convert(c, ansType.Name) } sub = append(sub, ansType) } ansTypeList := &model.AnsTypeList{Name: vt.Name, Fields: sub} if lang == model.LangZhTW { ansTypeList.Name = chinese.Convert(c, ansTypeList.Name) } list = append(list, ansTypeList) } if rpcRes.Repro { repro = "yes" } else { repro = "no" } res = &model.AnsProType{List: list, CurrentTime: rpcRes.CurrentTime.Unix(), EndTime: rpcRes.EndTime.Unix(), Repro: repro} return } // ConvertProQues pro question. func (s *Service) ConvertProQues(c context.Context, mid int64, tIds string, lang string, mobile bool) (res []*model.AnsQueDetail, err error) { var ( ans *model.AnsQuesList ansdl *model.AnsQueDetailList ) if ans, err = s.ProQues(c, mid, tIds, lang, mobile); err != nil { err = errors.Wrapf(err, "s.ProQues(%d,%v,%t)", mid, tIds, mobile) return } ansdl = s.convertModel(ans) res = ansdl.QuesList return } // ProQues question info. func (s *Service) ProQues(c context.Context, mid int64, qtsStr string, lang string, mobile bool) (rqs *model.AnsQuesList, err error) { var ( ah *model.AnswerHistory now = time.Now() allQids []int64 tIds, realTIDs []int ) if s.checkAnswerBlock(c, mid) { err = ecode.AnswerBlock return } if ah, err = s.checkBase(c, mid, now); err != nil { return } allQids, err = s.answerDao.IdsCache(c, mid, model.Q) if err != nil || len(allQids) != s.c.Answer.ProNum { tIDStrArr := strings.Split(qtsStr, ",") if len(tIDStrArr) < _minType || len(tIDStrArr) > _maxType { err = ecode.AnswerTypeIDsErr return } if tIds, err = sliceAtoi(tIDStrArr); err != nil { err = ecode.AnswerTypeIDsErr return } for _, qt := range tIds { if qt <= 0 { err = ecode.RequestErr return } if mapIDS, ok := _typeIdsMapping[qt]; ok { realTIDs = append(realTIDs, mapIDS...) continue } realTIDs = append(realTIDs, qt) } num := math.Ceil(float64(s.c.Answer.ProNum) / float64(len(realTIDs))) log.Warn("realTIDs:%v", realTIDs) for _, qt := range realTIDs { var t []int64 t, err = s.answerDao.QidByType(c, qt, uint8(num)) if err != nil { log.Error("s.answerDao.QidByType(%d, %f, %d) error(%+v)", qt, num, len(t), err) return } if len(t) == 0 { log.Error("mid:%d the QidByType(%d, %f, %d) of len is 0", mid, qt, num, len(t)) err = ecode.AnswerMidDBQueErr return } allQids = append(allQids, t...) } if len(allQids) == 0 || len(allQids) < s.c.Answer.ProNum { log.Error("ProQues allQids len is 0 or allQids len less(%d, %d, %f, %v, %d)", len(allQids), s.c.Answer.ProNum, num, realTIDs, mid) err = ecode.NothingFound return } } if rqs, err = s.concatData(c, mid, allQids, lang, mobile, s.c.Answer.ProNum); err != nil { log.Error("ProQues s.concatData(%d, %d, %d) error(%v)", c, mid, allQids, err) return } if _, err = s.answerDao.UpdateStepTwoTime(c, ah.ID, mid, now); err != nil { return } ah.StepTwoStartTime = now ah.Mtime = now s.userActionLog(mid, model.ProQues, ah) s.answerDao.DelHistoryCache(c, mid) return } func (s *Service) checkBase(c context.Context, mid int64, now time.Time) (ah *model.AnswerHistory, err error) { ah, err = s.history(c, mid) if err != nil || ah == nil || ah.StartTime.Add(s.answerDuration()).Before(now) || ah.Score != 0 || ah.StepOneCompleteTime == 0 { err = ecode.AnswerBaseNotPassed log.Error("checkBase(%d, %v) AnswerExpire error(%v)", mid, now, err) return } if ah.StepExtraCompleteTime == 0 { err = ecode.AnswerExtraNoPass return } if ah.Score > 0 && ah.IsPassCaptcha == 0 { err = ecode.AnswerCaptchaNoPassed } return } func (s *Service) checkTime(c context.Context, mid int64, now time.Time) (at *model.AnswerTime, rs bool) { var err error if at, err = s.answerDao.ExpireCache(c, mid); err != nil { return } if at == nil || at.Stime.Add(s.answerDuration()).Before(now) { return } rs = true return } func (s *Service) concatData(c context.Context, mid int64, ids []int64, lang string, mobile bool, qs int) (rqs *model.AnsQuesList, err error) { var ( list []*model.AnsQue qm map[int64]*model.Question ) if qm, err = s.answerDao.ByIds(c, ids); err != nil { log.Error("s.answerDao.ByIds(%v) error(%v)", ids, err) err = ecode.NothingFound return } for _, d := range ids { i := qm[d] rq := s.imgPosition(c, i, mid, lang, mobile) list = append(list, rq) } if len(list) > qs { list = list[:qs] } rqs = &model.AnsQuesList{QuesList: list} if err := s.answerDao.SetIdsCache(c, mid, ids, model.Q); err != nil { log.Error("s.answerDao.SetIdsCache(%d, %d) error(%v)", mid, ids, err) } log.Info("s.concatData load que success(%d, %v, %v, %d)", mid, ids, mobile, qs) return } func (s *Service) concatExtraData(c context.Context, mid int64, ids []int64, passids []int64, nopassids []int64, lang string, mobile bool, qs int) (rqs *model.AnsQuesList, err error) { var ( list []*model.AnsQue qm map[int64]*model.ExtraQst ) if qm, err = s.answerDao.ExtraByIds(c, ids); err != nil || len(qm) < qs { log.Error("s.answerDao.ExtraByIds(%v) error(%+v)", ids, err) return } for _, d := range ids { i := qm[d] rq := s.imgExtraPosition(c, i, mid, lang, mobile) list = append(list, rq) } if len(list) > qs { list = list[:qs] } rqs = &model.AnsQuesList{QuesList: list} if err = s.answerDao.SetIdsCache(c, mid, passids, model.BaseExtraPassQ); err != nil { log.Error("s.answerDao.SetIdsCache(%d, %d) error(%v)", mid, passids, err) return } if err = s.answerDao.SetIdsCache(c, mid, nopassids, model.BaseExtraNoPassQ); err != nil { log.Error("s.answerDao.SetIdsCache(%d, %d) error(%v)", mid, nopassids, err) return } log.Info("s.concatData extra load que success(%d, %v, %v, %d)", mid, ids, mobile, qs) return } // ansHash get answer hash. func (s *Service) ansHash(mid int64, ans string) (ansHash string) { h := md5.New() h.Write([]byte(fmt.Sprintf("%s%d%s", ans, mid, _hashSalt))) return hex.EncodeToString(h.Sum(nil)) } func (s *Service) imgPosition(c context.Context, qs *model.Question, mid int64, lang string, mobile bool) (rq *model.AnsQue) { var ( y float64 qsLineLength float64 = 36 questionFontSize float64 = 10 questionTitleSize float64 = 12 ans = make([]*model.AnsPosition, 4) imgStr = "v3_%s_A-%s_B-%s_C-%s_D-%s_%s" p = map[bool]string{true: "H5", false: "PC"} bfsHost = "https://i0.hdslb.com/bfs/member/" as [4]string ) rq = &model.AnsQue{ID: qs.ID} if mobile { qsLineLength = 11 questionFontSize = 12 questionTitleSize = 16 } qsLength := utf8.RuneCountInString(qs.Question) if float64(qsLength) > qsLineLength { line := math.Ceil(float64(qsLength) / qsLineLength) rq.Height = 2 * line * questionTitleSize rq.PositionY = y } else { rq.Height = 2 * questionTitleSize } y = rq.Height if lang == model.LangZhTW { qs.Question = chinese.Convert(c, qs.Question) qs.Ans[0] = chinese.Convert(c, qs.Ans[0]) qs.Ans[1] = chinese.Convert(c, qs.Ans[1]) qs.Ans[2] = chinese.Convert(c, qs.Ans[2]) qs.Ans[3] = chinese.Convert(c, qs.Ans[3]) } idx := rand.Perm(4) for i := range qs.Ans { ans[i] = &model.AnsPosition{ AnsHash: s.ansHash(mid, qs.Ans[idx[i]]), Height: 2 * questionFontSize, PositionY: y, } y += 2 * questionFontSize as[i] = qs.Ans[idx[i]] } m := md5.New() m.Write([]byte(fmt.Sprintf(imgStr, strconv.FormatInt(qs.ID, 10), as[0], as[1], as[2], as[3], p[mobile]))) fname := hex.EncodeToString(m.Sum(nil)) + ".jpg" if s.c.Answer.Debug { fname = fmt.Sprintf("debug_%s", fname) } rq.Img = bfsHost + fname rq.Ans = ans return } func (s *Service) imgExtraPosition(c context.Context, qs *model.ExtraQst, mid int64, lang string, mobile bool) (rq *model.AnsQue) { var ( y float64 qsLineLength float64 = 36 questionFontSize float64 = 10 questionTitleSize float64 = 12 ans = make([]*model.AnsPosition, 2) imgStr = "%s_A-%s_B-%s_%s" p = map[bool]string{true: "H5", false: "PC"} bfsHost = "https://i0.hdslb.com/bfs/member/" as [2]string ) rq = &model.AnsQue{ID: qs.ID} if mobile { qsLineLength = 11 questionFontSize = 12 questionTitleSize = 16 } qsLength := utf8.RuneCountInString(qs.Question) if float64(qsLength) > qsLineLength { line := math.Ceil(float64(qsLength) / qsLineLength) rq.Height = 2 * line * questionTitleSize rq.PositionY = y } else { rq.Height = 2 * questionTitleSize } y = rq.Height if lang == model.LangZhTW { as = [2]string{chinese.Convert(c, model.ExtraAnsA), chinese.Convert(c, model.ExtraAnsB)} } else { as = [2]string{model.ExtraAnsA, model.ExtraAnsB} } for k, v := range as { ans[k] = &model.AnsPosition{ AnsHash: s.ansHash(mid, v), Height: 2 * questionFontSize, PositionY: y, } y += 2 * questionFontSize } m := md5.New() m.Write([]byte(fmt.Sprintf(imgStr, strconv.FormatInt(qs.OriginID, 10), as[0], as[1], p[mobile]))) fname := hex.EncodeToString(m.Sum(nil)) + ".jpg" if s.c.Answer.Debug { fname = fmt.Sprintf("debug_%s", fname) } rq.Img = bfsHost + fname rq.Ans = ans return } func (s *Service) loadQidsCache() { qs, err := s.answerDao.QidsByState(context.Background(), model.PassCheck) if len(qs) == 0 || err != nil { log.Error("s.answerDao.loadQidsCache(%d) size is zero error(%v)", model.PassCheck, err) } qmap := map[int8][]int64{} for _, q := range qs { qmap[q.TypeID] = append(qmap[q.TypeID], q.ID) } for k, v := range qmap { s.answerDao.DelQidsCache(context.Background(), int(k)) s.answerDao.SetQids(context.Background(), v, int(k)) } log.Info("s.answerDao.loadQidsCache suc(%v)", qmap) } func (s *Service) loadExtraQidsCache() { qs, err := s.answerDao.QidsExtraByState(context.Background(), model.MaxLoadQueSize) if len(qs) == 0 || err != nil { log.Error("s.answerDao.QidsExtraByState(%d) size is zero error(%v)", model.MaxLoadQueSize, err) return } qmap := map[int8][]int64{} for _, q := range qs { qmap[q.Ans] = append(qmap[q.Ans], q.ID) } for k, v := range qmap { s.answerDao.DelExtraQidsCache(context.Background(), k) s.answerDao.SetExtraQids(context.Background(), v, k) } log.Info("s.answerDao.loadExtraQidsCache suc(%v)", qmap) } // Cool . func (s *Service) Cool(c context.Context, hid, mid int64) (cool *model.AnsCool, err error) { var ( his *model.AnswerHistory types []*model.TypeInfo li = []*model.CoolPower{ {Name: "动画", Num: 0}, {Name: "艺术", Num: 0}, {Name: "游戏", Num: 0}, {Name: "科技", Num: 0}, {Name: "影视", Num: 0}, {Name: "鬼畜", Num: 0}, } completeResult = make(map[int8]int64) ) his, err = s.historyByHid(c, hid) if err != nil { return } cool = &model.AnsCool{ Score: his.Score, IsSameUser: his.Mid == mid, IsFirstPass: his.IsFirstPass, Level: his.PassedLevel, Share: &model.CoolShare{}, VideoInfo: &model.CoolVideo{}, Rank: &model.CoolRank{}, } cool.CanShowRankBtn = his.Score >= 85 && his.Mtime.Before(time.Now().Add(_rankBtn)) r := _pendantIDNameMap[int(his.RankID)] if r != "" { if rid, ok := _oldPIDToNewMap[his.RankID]; ok { his.RankID = rid } rs := _rankShire[his.RankID] idx := rand.Perm(len(rs.VideoArr)) cool.ViewMore = rs.ViewMore cool.Share = rs.Share cool.VideoInfo = rs.VideoArr[idx[0]] cool.Rank = &model.CoolRank{ ID: int(his.RankID), Name: r, Img: "https://i0.hdslb.com" + _pendantIDImgMap[his.RankID], } } us, err := s.accInfo(c, his.Mid) if err != nil || us == nil { log.Error("CheckQueCaptcha accInfo(%d) info is null error(%v)", mid, err) return } cool.Name = us.Name cool.Face = us.Face if err = json.Unmarshal([]byte(his.CompleteResult), &completeResult); err != nil { log.Error("json.Unmarshal(%s) error(%v)", his.CompleteResult, err) err = nil } log.Info("hid(%d), completeResult: %v+", hid, completeResult) for k := range completeResult { for _, t := range s.questionTypeCache { if len(t.Subs) != 0 { for _, s := range t.Subs { if int64(k) == s.ID { types = append(types, &model.TypeInfo{ID: s.ID, Name: s.Name, LabelName: s.LabelName}) } } } if int64(k) == t.ID { types = append(types, t) } } } log.Info("hid(%d), cool types: %v+", hid, types) for _, t := range types { for _, p := range li { if p.Name == t.LabelName { p.Num += completeResult[int8(t.ID)] } } } log.Info("hid(%d), power types: %v+", hid, li) cool.Powers = append(cool.Powers, li...) if _, ok := _recTypeIDMap[int(his.RankID)]; ok { cool.MainTids = _recTypeIDMap[int(his.RankID)]["main_tid"] cool.SubTids = _recTypeIDMap[int(his.RankID)]["sub_tid"] } return } // ExtraScore . func (s *Service) ExtraScore(c context.Context, mid int64) (res *model.ExtraScoreReply, err error) { res = &model.ExtraScoreReply{} h, err := s.history(c, mid) if err != nil { return } res.Score = h.StepExtraScore + int64(s.c.Answer.BaseNum) return } func (s *Service) history(c context.Context, mid int64) (ah *model.AnswerHistory, err error) { cok := true if ah, err = s.answerDao.HistoryCache(c, mid); err != nil { cok = false return } if ah != nil { return } ah, err = s.answerDao.History(c, mid) if err != nil { return } if ah != nil && cok { s.answerDao.SetHistoryCache(c, mid, ah) } return } func (s *Service) answerDuration() (d time.Duration) { return time.Duration(s.c.Answer.Duration) * time.Minute } func sliceAtoi(sa []string) ([]int, error) { si := make([]int, 0, len(sa)) for _, a := range sa { i, err := strconv.Atoi(a) if err != nil { return si, err } si = append(si, i) } return si, nil } func (s *Service) extraQueByBigData(c context.Context, mid int64, ip string) (ok bool, passids []int64, npassids []int64) { passids, npassids, err := s.accountDao.ExtraIds(c, mid, ip) if err != nil || len(passids) != s.c.Answer.BaseExtraPassNum || len(npassids) != s.c.Answer.BaseExtraNoPassNum { return } ids := append(passids, npassids...) if qm, err := s.answerDao.ExtraByIds(c, ids); err != nil || len(qm) != (s.c.Answer.BaseExtraPassNum+s.c.Answer.BaseExtraNoPassNum) { log.Error("s.answerDao.ExtraByIds(%v) error(%v)", ids, err) return } ok = true return } func (s *Service) loadtypes() (t map[int64]*model.TypeInfo) { tys, err := s.answerDao.Types(context.Background()) if err != nil { log.Error("s.questionDao.Types error(%v)", err) return } tmp := map[int64]*model.TypeInfo{} for _, v := range tys { if v.Parentid == 0 && tmp[v.ID] == nil { tmp[v.ID] = &model.TypeInfo{ID: v.ID, Name: v.Name, Subs: []*model.SubType{}} } else if tmp[v.Parentid] != nil { tmp[v.Parentid].Subs = append(tmp[v.Parentid].Subs, &model.SubType{ID: v.ID, Name: v.Name, LabelName: v.LabelName}) } } s.questionTypeCache = tmp t = tmp log.Info("load question type cacheproc success,%v", t) return }