package service import ( "bytes" "context" "fmt" "sort" "strconv" "strings" "time" "go-common/app/admin/main/growup/dao" "go-common/app/admin/main/growup/dao/resource" "go-common/app/admin/main/growup/model" "go-common/app/admin/main/growup/util" "go-common/library/database/sql" "go-common/library/ecode" "go-common/library/log" "go-common/library/xstr" ) const ( awardEditable = iota + 1 awardInfoEditable awardDivisionEditable awardPrizeEditable awardResourceEditable ) const ( _awardResourceTypeRule = 1 _awardResourceTypeDetail = 3 _awardResourceTypeQ = 5 _awardResourceTypeA = 6 ) func awardEditPerms(award *model.Award) (res map[int]bool) { var ( now = time.Now() notDisplay = award.DisplayStatus == 1 notFinished = award.OpenStatus == 1 preCycleStart = now.Before(award.CycleStart) ) res = map[int]bool{ awardEditable: notDisplay || notFinished, awardInfoEditable: notDisplay || preCycleStart, awardDivisionEditable: notDisplay || preCycleStart, awardPrizeEditable: notDisplay || notFinished, awardResourceEditable: notDisplay || notFinished, } return } func (s *Service) generateAwardID() (awardID int64, err error) { awardID, err = util.NewSnowFlake().Generate() return } func (s *Service) validateAwardCycle(c context.Context, awardID int64, start, end time.Time) (ok bool, err error) { // simplified version: check all awardBases, err := s.dao.ListAward(c) if err != nil { return } between := func(t, a, b time.Time) bool { return !(t.Before(a) || t.After(b)) } for _, v := range awardBases { if awardID == v.AwardID || v.DisplayStatus != 2 { continue } if between(start, v.CycleStart, v.CycleEnd) || between(end, v.CycleStart, v.CycleEnd) { ok = false return } } ok = true return } // AddAward . func (s *Service) AddAward(c context.Context, arg *model.AddAwardArg, username string) (awardID int64, err error) { // 1. validation if !(arg.DisplayStatus == 1 || arg.DisplayStatus == 2) { err = ecode.RequestErr return } // 2. args // generate awardID awardID, err = s.generateAwardID() if err != nil { return } // cycle start := util.ToDayStart(time.Unix(arg.CycleStart, 0)) end := util.ToDayEnd(time.Unix(arg.CycleEnd, 0)) if arg.CycleStart > 0 && arg.CycleEnd > 0 && arg.DisplayStatus == 2 { var validCycle bool validCycle, err = s.validateAwardCycle(c, awardID, start, end) if err != nil { return } if !validCycle { err = ecode.Error(ecode.RequestErr, "评选周期重叠") return } } // total totalWinner, totalBonus := 0, 0 if len(arg.Prizes) > 0 { for _, v := range arg.Prizes { totalWinner += v.Quota totalBonus += v.Bonus * v.Quota } } // 3. tx insert var ( cycleStart = start.Format("2006-01-02 15:04:05") cycleEnd = end.Format("2006-01-02 15:04:05") announce = util.ToDayNoon(time.Unix(arg.AnnounceDate, 0)) announceDate = announce.Format("2006-01-02") openTime = announce.Format("2006-01-02 15:04:05") ) err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) { _, err = dao.AddAward(tx, awardID, arg.AwardName, cycleStart, cycleEnd, announceDate, openTime, arg.DisplayStatus, totalWinner, totalBonus, username) if err != nil { return } if len(arg.Divisions) > 0 { fields, values := saveDivisionStr(awardID, arg.Divisions) if values != "" { _, err = dao.SaveDivisions(tx, fields, values) if err != nil { return } } } if len(arg.Prizes) > 0 { fields, values := savePrizesStr(awardID, arg.Prizes) if values != "" { _, err = dao.SavePrizes(tx, fields, values) if err != nil { return } } } if arg.Resources != nil { fields, values := saveResourcesStr(awardID, arg.Resources) if values != "" { _, err = dao.SaveResource(tx, fields, values) if err != nil { return } } } return nil }) return } func saveWinnerStr(winnersM map[int64]*model.AwardWinner) (fields, values string) { if len(winnersM) == 0 { return } fields = "award_id,mid,division_id,prize_id,tag_id" var buf bytes.Buffer for _, v := range winnersM { buf.WriteString("(") buf.WriteString(strconv.FormatInt(v.AwardID, 10)) buf.WriteByte(',') buf.WriteString(strconv.FormatInt(v.MID, 10)) buf.WriteByte(',') buf.WriteString(strconv.FormatInt(v.DivisionID, 10)) buf.WriteByte(',') buf.WriteString(strconv.FormatInt(v.PrizeID, 10)) buf.WriteByte(',') buf.WriteString(strconv.FormatInt(v.TagID, 10)) buf.WriteString(")") buf.WriteByte(',') } if buf.Len() > 0 { buf.Truncate(buf.Len() - 1) } values = buf.String() values += " ON DUPLICATE KEY UPDATE division_id=VALUES(division_id), prize_id=VALUES(prize_id), tag_id=VALUES(tag_id), is_deleted=0" buf.Reset() return } func saveDivisionStr(awardID int64, divisions []*model.AwardDivision) (fields, values string) { if len(divisions) == 0 { return } vs := make([]string, 0) for i, v := range divisions { vs = append(vs, fmt.Sprintf("(%d,%d,'%s',%d)", awardID, i+1, v.DivisionName, v.TagID)) } if len(vs) > 0 { fields = "award_id,division_id,division_name,tag_id" values = strings.Join(vs, ",") + " ON DUPLICATE KEY UPDATE division_name=VALUES(division_name), tag_id=VALUES(tag_id), is_deleted=0" } return } func savePrizesStr(awardID int64, prizes []*model.AwardPrize) (fields, values string) { if len(prizes) == 0 { return } vs := make([]string, 0) for i, v := range prizes { vs = append(vs, fmt.Sprintf("(%d,%d,%d,%d)", awardID, i+1, v.Bonus, v.Quota)) } if len(vs) > 0 { fields = "award_id,prize_id,bonus,quota" values = strings.Join(vs, ",") + " ON DUPLICATE KEY UPDATE bonus=VALUES(bonus), quota=VALUES(quota), is_deleted=0" } return } func delResourcesStr(awardID int64, arg *model.AwardResource) (delWhere string) { if len(arg.QA) == 0 { return fmt.Sprintf("award_id = %d AND resource_type IN (%d,%d)", awardID, _awardResourceTypeQ, _awardResourceTypeA) } idx := make([]int64, 0) for i := range arg.QA { idx = append(idx, int64(i+1)) } return fmt.Sprintf("award_id = %d AND resource_type IN (%d,%d) AND resource_index NOT IN (%s)", awardID, _awardResourceTypeQ, _awardResourceTypeA, xstr.JoinInts(idx)) } func saveResourcesStr(awardID int64, arg *model.AwardResource) (fields, values string) { if arg == nil { return } vs := make([]string, 0) vs = append(vs, fmt.Sprintf("(%d,%d,1,'%s')", awardID, _awardResourceTypeRule, arg.Rule)) vs = append(vs, fmt.Sprintf("(%d,%d,1,'%s')", awardID, _awardResourceTypeDetail, arg.Detail)) if len(arg.QA) > 0 { for i, qa := range arg.QA { vs = append(vs, fmt.Sprintf("(%d,%d,%d,'%s')", awardID, _awardResourceTypeQ, i+1, qa.Q)) vs = append(vs, fmt.Sprintf("(%d,%d,%d,'%s')", awardID, _awardResourceTypeA, i+1, qa.A)) } } if len(vs) > 0 { fields = "award_id,resource_type,resource_index,content" values = strings.Join(vs, ",") + " ON DUPLICATE KEY UPDATE content=VALUES(content), is_deleted=0" } return } // UpdateAward . func (s *Service) UpdateAward(c context.Context, arg *model.SaveAwardArg) (err error) { // 1. if !(arg.DisplayStatus == 1 || arg.DisplayStatus == 2) || arg.AwardID == 0 { return ecode.Error(ecode.RequestErr, "illegal param") } awardID := arg.AwardID award, err := s.dao.Award(c, awardID) if err != nil { return } if award == nil { err = ecode.Error(ecode.RequestErr, "illegal award_id") return } // permission := awardEditPerms(award) if !permission[awardEditable] { err = ecode.Error(ecode.RequestErr, "award no longer editable") return } // sum totalQuota, totalBonus := 0, 0 if len(arg.Prizes) > 0 { for _, v := range arg.Prizes { totalQuota += v.Quota totalBonus += v.Bonus * v.Quota } } newAward := &model.Award{ AwardName: arg.AwardName, CycleStart: util.ToDayStart(time.Unix(arg.CycleStart, 0)), CycleEnd: util.ToDayEnd(time.Unix(arg.CycleEnd, 0)), AnnounceDate: time.Unix(arg.AnnounceDate, 0), OpenTime: util.ToDayNoon(time.Unix(arg.AnnounceDate, 0)), DisplayStatus: arg.DisplayStatus, TotalQuota: totalQuota, TotalBonus: totalBonus, } if permission[awardInfoEditable] && arg.DisplayStatus == 2 { if !newAward.CycleStart.Equal(award.CycleStart) || !newAward.CycleEnd.Equal(award.CycleEnd) { var ok bool ok, err = s.validateAwardCycle(c, awardID, newAward.CycleStart, newAward.CycleEnd) if err != nil { return } if !ok { err = ecode.Error(ecode.RequestErr, "评选周期重叠") return } } } err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) { // lock award, err = dao.SelectAwardForUpdate(tx, awardID) if err != nil { return } if award == nil { return ecode.Error(ecode.RequestErr, "award not found") } //// award info if permission[awardInfoEditable] { updateAwardStr := fmt.Sprintf(`award_name='%s', cycle_start='%s', cycle_end='%s', announce_date='%s', open_time='%s', display_status=%d, total_quota=%d, total_bonus=%d`, newAward.AwardName, newAward.CycleStart.Format("2006-01-02 15:04:05"), newAward.CycleEnd.Format("2006-01-02 15:04:05"), newAward.AnnounceDate.Format("2006-01-02"), newAward.OpenTime.Format("2006-01-02 15:04:05"), newAward.DisplayStatus, newAward.TotalQuota, newAward.TotalBonus) _, err = dao.UpdateAward(tx, awardID, updateAwardStr) if err != nil { return } } //// divisions if permission[awardDivisionEditable] { switch { case len(arg.Divisions) == 0: _, err = dao.DelDivisionAll(tx, awardID) if err != nil { return } default: // del argDivisionIDs := make([]int64, 0) for i, v := range arg.Divisions { v.DivisionID = int64(i + 1) argDivisionIDs = append(argDivisionIDs, v.DivisionID) } _, err = dao.DelDivisionsExclude(tx, awardID, argDivisionIDs) if err != nil { return } // save fields, values := saveDivisionStr(awardID, arg.Divisions) _, err = dao.SaveDivisions(tx, fields, values) if err != nil { return } } } //// prizes if permission[awardPrizeEditable] { switch { case len(arg.Prizes) == 0: _, err = dao.DelPrizeAll(tx, awardID) if err != nil { return } default: // del argPrizeIDs := make([]int64, 0) for i, v := range arg.Prizes { v.PrizeID = int64(i + 1) argPrizeIDs = append(argPrizeIDs, v.PrizeID) } _, err = dao.DelPrizesExclude(tx, awardID, argPrizeIDs) if err != nil { return } fields, values := savePrizesStr(awardID, arg.Prizes) _, err = dao.SavePrizes(tx, fields, values) if err != nil { return } } } //// resources if permission[awardResourceEditable] { switch { case arg.Resources == nil: _, err = dao.DelResources(tx, fmt.Sprintf("award_id = %d", awardID)) if err != nil { return } default: delWhere := delResourcesStr(awardID, arg.Resources) _, err = dao.DelResources(tx, delWhere) if err != nil { return } fields, values := saveResourcesStr(awardID, arg.Resources) _, err = dao.SaveResource(tx, fields, values) if err != nil { return } } } return nil }) return err } // ListAward . func (s *Service) ListAward(c context.Context, from, limit int) (total int64, data []*model.AwardListModel, err error) { data = make([]*model.AwardListModel, 0) var ( awardToWinnerC map[int64]int awards []*model.Award divisions []*model.AwardDivision ) err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) { total, err = dao.CountAward(tx) if err != nil { return } if total == 0 { return } awards, err = dao.ListAward(tx, from, limit) if err != nil { return } if len(awards) == 0 { return } awardIDs := make([]int64, 0) for _, v := range awards { awardIDs = append(awardIDs, v.AwardID) } divisions, err = dao.ListAwardsDivision(tx, fmt.Sprintf("award_id IN (%s)", xstr.JoinInts(awardIDs))) if err != nil { return } awardToWinnerC, err = dao.GroupCountAwardWinner(tx, fmt.Sprintf("award_id IN (%s)", xstr.JoinInts(awardIDs))) if err != nil { return } return nil }) if err != nil || total == 0 || len(awards) == 0 { return } // divisions group by award_id var ( tagIDToName map[int64]string awardToDivisions = make(map[int64][]*model.AwardDivision) ) tagIDToName, err = resource.VideoCategoryIDToName(c) if err != nil { return } for _, division := range divisions { if _, ok := awardToDivisions[division.AwardID]; !ok { awardToDivisions[division.AwardID] = make([]*model.AwardDivision, 0) } awardToDivisions[division.AwardID] = append(awardToDivisions[division.AwardID], division) } for _, award := range awards { v := &model.AwardListModel{ ID: award.ID, AwardID: award.AwardID, AwardName: award.AwardName, CycleStart: award.CycleStart.Unix(), CycleEnd: award.CycleEnd.Unix(), TotalQuota: award.TotalQuota, TotalBonus: award.TotalBonus, AnnounceDate: award.AnnounceDate.Unix(), OpenStatus: award.OpenStatus, OpenTime: award.OpenTime.Unix(), CTime: award.CTime.Unix(), CreatedBy: award.CreatedBy, SelectionStatus: 1, Tags: make([]string, 0), DivisionNames: make([]string, 0), } // status if count, ok := awardToWinnerC[v.AwardID]; ok && count == v.TotalQuota { v.SelectionStatus = 2 } tagIDs := make([]int64, 0) for _, division := range awardToDivisions[v.AwardID] { tagIDs = append(tagIDs, division.TagID) v.DivisionNames = append(v.DivisionNames, division.DivisionName) } for _, tagID := range tagIDs { v.Tags = append(v.Tags, tagIDToName[tagID]) } data = append(data, v) } return } // DetailAward . func (s *Service) DetailAward(c context.Context, awardID int64) (data *model.AwardDetail, err error) { data = &model.AwardDetail{} var ( winners = 0 typeIdxContent map[int]map[int]string ) err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) { data.Award, err = dao.Award(tx, awardID) if err != nil { return } if data.Award == nil { err = ecode.Errorf(ecode.RequestErr, "award not found, awardID{%d}", awardID) return } data.Divisions, err = dao.ListDivision(tx, awardID) if err != nil { return } data.Prizes, err = dao.ListPrize(tx, awardID) if err != nil { return } typeIdxContent, err = dao.ListResource(tx, awardID) if err != nil { return } total, err := dao.CountAwardWinner(tx, awardID, "") if err != nil { return } winners = int(total) return nil }) if err != nil { return } data.Award.SelectionStatus = 1 if data.Award.TotalQuota == winners { data.Award.SelectionStatus = 2 } // tags if len(data.Divisions) > 0 { var tagNames map[int64]string tagNames, err = resource.VideoCategoryIDToName(c) if err != nil { return } for _, division := range data.Divisions { if tagName, ok := tagNames[division.TagID]; ok { division.Tag = tagName } } } data.Resources = &model.AwardResource{ Rule: typeIdxContent[1][1], Detail: typeIdxContent[3][1], QA: make([]*model.AwardQA, 0), } questions, answers := typeIdxContent[5], typeIdxContent[6] if len(questions) > 0 && len(answers) > 0 { for idx, question := range questions { data.Resources.QA = append(data.Resources.QA, &model.AwardQA{Index: idx, Q: question, A: answers[idx]}) } } sort.Slice(data.Resources.QA, func(i, j int) bool { return data.Resources.QA[i].Index < data.Resources.QA[j].Index }) data.Award.GenStr() return } // ListAwardWinner . func (s *Service) ListAwardWinner(c context.Context, arg *model.QueryAwardWinnerArg) (total int64, res []*model.AwardWinner, err error) { res = make([]*model.AwardWinner, 0) if pass := s.validateQueryAwardWinner(c, arg); !pass { return } where := s.queryAwardWinnerWhere(arg) var ( winnerInfo map[int64]*model.AwardWinner // prizeInfo map[int64]*model.AwardPrize // divisionInfo map[int64]*model.AwardDivision // mids = make([]int64, 0) ) err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) { total, err = dao.CountAwardWinner(tx, arg.AwardID, where) if err != nil { return } if total == 0 { return } winnerInfo, err = dao.QueryAwardWinner(tx, arg.AwardID, fmt.Sprintf("%s ORDER BY id DESC LIMIT %d,%d", where, arg.From, arg.Limit)) if err != nil { return } if len(winnerInfo) > 0 { // divisions divisionInfo, err = dao.DivisionInfo(tx, arg.AwardID) if err != nil { return } // prizes prizeInfo, err = dao.PrizeInfo(tx, arg.AwardID) if err != nil { return } } return nil }) if err != nil || total == 0 || len(winnerInfo) == 0 { return } categories, err := resource.VideoCategoryIDToName(c) if err != nil { return } for mid := range winnerInfo { mids = append(mids, mid) } upNames, err := resource.NamesByMIDs(c, mids) if err != nil { return } for mid, info := range winnerInfo { if division, ok := divisionInfo[info.DivisionID]; ok { info.DivisionName = division.DivisionName } if prize, ok := prizeInfo[info.PrizeID]; ok { info.Bonus = prize.Bonus } // tag if data, ok := categories[info.TagID]; ok { info.Tag = data } // nickname if nickname, ok := upNames[mid]; ok { info.Nickname = nickname } } res = make([]*model.AwardWinner, 0) for _, v := range winnerInfo { res = append(res, v) } return } // ExportAwardWinner . func (s *Service) ExportAwardWinner(c context.Context, arg *model.QueryAwardWinnerArg) (res []byte, err error) { records, err := s.listAwardWinnerAll(c, arg) if err != nil { return } data := make([][]string, 0, len(records)+1) data = append(data, model.AwardWinnerExportFields()) for _, v := range records { data = append(data, v.ExportStrings()) } if res, err = FormatCSV(data); err != nil { log.Error("FormatCSV error(%v)", err) } return } func (s *Service) listAwardWinnerAll(c context.Context, arg *model.QueryAwardWinnerArg) (records []*model.AwardWinner, err error) { records = make([]*model.AwardWinner, 0) if pass := s.validateQueryAwardWinner(c, arg); !pass { return } where := s.queryAwardWinnerWhere(arg) var ( winnerInfo map[int64]*model.AwardWinner // prizeInfo map[int64]*model.AwardPrize // divisionInfo map[int64]*model.AwardDivision // mids = make([]int64, 0) ) err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) { winnerInfo, err = dao.QueryAwardWinner(tx, arg.AwardID, fmt.Sprintf("%s ORDER BY id DESC", where)) if err != nil { return } if len(winnerInfo) > 0 { // divisions divisionInfo, err = dao.DivisionInfo(tx, arg.AwardID) if err != nil { return } // prizes prizeInfo, err = dao.PrizeInfo(tx, arg.AwardID) if err != nil { return } } return nil }) if err != nil { return } if len(winnerInfo) == 0 { return } categories, err := resource.VideoCategoryIDToName(c) if err != nil { return } for mid := range winnerInfo { mids = append(mids, mid) } upNames, err := resource.NamesByMIDs(c, mids) if err != nil { return } for mid, info := range winnerInfo { if division, ok := divisionInfo[info.DivisionID]; ok { info.DivisionName = division.DivisionName } if prize, ok := prizeInfo[info.PrizeID]; ok { info.Bonus = prize.Bonus } // tag if data, ok := categories[info.TagID]; ok { info.Tag = data } // nickname if nickname, ok := upNames[mid]; ok { info.Nickname = nickname } } for _, v := range winnerInfo { records = append(records, v) } return } func (s *Service) validateQueryAwardWinner(c context.Context, arg *model.QueryAwardWinnerArg) (pass bool) { if arg.Nickname != "" { mid, err := resource.MidByNickname(c, arg.Nickname) if err != nil || mid == 0 { return } if arg.MID == 0 { arg.MID = mid } if arg.MID != mid { log.Error("illegal mid(%d) and nickname(%s) pair", arg.MID, arg.Nickname) return } } return true } func (s *Service) queryAwardWinnerWhere(arg *model.QueryAwardWinnerArg) string { str := "" if arg.MID > 0 { str += fmt.Sprintf(" AND mid=%d", arg.MID) } if arg.TagID > 0 { str += fmt.Sprintf(" AND tag_id=%d", arg.TagID) } return str } // ReplaceAwardWinner . func (s *Service) ReplaceAwardWinner(c context.Context, awardID, prevMID, mid int64) (err error) { records, err := s.dao.ListAwardRecord(c, awardID, fmt.Sprintf("AND (mid=%d OR mid=%d)", prevMID, mid)) if err != nil { return } midsM := make(map[int64]bool) for _, v := range records { midsM[v.MID] = true } if !midsM[prevMID] { return ecode.Errorf(ecode.RequestErr, "mid(%d) not in award(%d)", prevMID, awardID) } if !midsM[mid] { return ecode.Errorf(ecode.RequestErr, "mid(%d) not in award(%d)", mid, awardID) } err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) { // lock award award, err := dao.SelectAwardForUpdate(tx, awardID) if err != nil { return } if award == nil { return ecode.Error(ecode.RequestErr, "award not found") } if award.OpenStatus != 1 { return ecode.Error(ecode.RequestErr, "illegal operation") } // winner info res, err := dao.QueryAwardWinner(tx, awardID, fmt.Sprintf("AND (mid=%d OR mid=%d)", prevMID, mid)) if err != nil { return } prevWinner, ok := res[prevMID] if !ok { return ecode.Error(ecode.RequestErr, "invalid old winner") } if _, ok = res[mid]; ok { return ecode.Error(ecode.RequestErr, "invalid new winner") } // replace rows, err := dao.DelWinner(tx, awardID, fmt.Sprintf(" AND mid=%d", prevMID)) if err != nil { return } if rows != 1 { return ecode.Error(ecode.ServerErr, "failed to del old winner") } fields, values := saveWinnerStr(map[int64]*model.AwardWinner{ awardID: { AwardID: awardID, MID: mid, DivisionID: prevWinner.DivisionID, PrizeID: prevWinner.PrizeID, TagID: prevWinner.TagID, }, }) rows, err = dao.SaveWinners(tx, fields, values) if err != nil { return } if rows != 1 { return ecode.Error(ecode.ServerErr, "failed to add new winner") } return }) return } // SaveAwardResult . func (s *Service) SaveAwardResult(c context.Context, arg *model.AwardResult) (err error) { var ( awardID = arg.AwardID winnersM = make(map[int64]*model.AwardWinner) prizeWinnerC = make(map[int64]int) divisionInfo map[int64]*model.AwardDivision ) divisionInfo, err = s.dao.AwardDivisionInfo(c, awardID) if err != nil { return } for divisionI, division := range arg.Divisions { divisionID := int64(divisionI + 1) for prizeI, prize := range division.Prizes { prizeID := int64(prizeI + 1) prizeWinnerC[prizeID] += len(prize.MIDs) for _, mid := range prize.MIDs { if _, ok := winnersM[mid]; ok { return ecode.Error(ecode.RequestErr, "UID重复,请重新录入") } winnersM[mid] = &model.AwardWinner{ MID: mid, AwardID: awardID, DivisionID: divisionID, PrizeID: prizeID, TagID: divisionInfo[divisionID].TagID, } } } } mids := make([]int64, 0, len(winnersM)) for k := range winnersM { mids = append(mids, k) } if len(winnersM) == 0 { return ecode.Error(ecode.RequestErr, "奖项人数不符,保存失败") } // 是否已报名专项奖 { var winnerRecords []*model.AwardRecord winnerRecords, err = s.dao.ListAwardRecord(c, awardID, fmt.Sprintf("AND mid IN (%s)", xstr.JoinInts(mids))) if err != nil { return } if len(winnersM) != len(winnerRecords) { var ( awardRecordM = make(map[int64]bool) unSignedMIDs []int64 ) for _, rcr := range winnerRecords { awardRecordM[rcr.MID] = true } for _, mid := range mids { if !awardRecordM[mid] { unSignedMIDs = append(unSignedMIDs, mid) } } return ecode.Errorf(ecode.RequestErr, "%s 未报名专项奖,保存失败", xstr.JoinInts(unSignedMIDs)) } } // 是否已签约激励 { var signedUPs map[int64]struct{} signedUPs, err = s.dao.GetUpInfoByState(c, "up_info_video", mids, 3) if err != nil { return } if len(mids) != len(signedUPs) { var unSignedMIDs []int64 for _, mid := range mids { if _, ok := signedUPs[mid]; !ok { unSignedMIDs = append(unSignedMIDs, mid) } } return ecode.Errorf(ecode.RequestErr, "%s 非签约状态,保存失败", xstr.JoinInts(unSignedMIDs)) } } // save winners updateAwardStr := fmt.Sprintf("open_time = '%s'", time.Unix(arg.OpenTime, 0).Format("2006-01-02 15:04:05")) fields, values := saveWinnerStr(winnersM) err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) { award, err := dao.SelectAwardForUpdate(tx, awardID) if err != nil { return } if award == nil { return ecode.Errorf(ecode.RequestErr, "award not found, awardID{%d}", awardID) } if award.OpenStatus != 1 { return ecode.Error(ecode.RequestErr, "已发奖,不能再修改名单") } if award.TotalQuota != len(mids) { return ecode.Error(ecode.RequestErr, "奖项人数不符,保存失败") } prizeInfo, err := dao.PrizeInfo(tx, awardID) if err != nil { return } for prizeID, info := range prizeInfo { if prizeWinnerC[prizeID] != info.Quota { return ecode.Error(ecode.RequestErr, "奖项人数不符,保存失败") } } _, err = dao.UpdateAward(tx, awardID, updateAwardStr) if err != nil { return } _, err = dao.DelWinnerAll(tx, awardID) if err != nil { return } _, err = dao.SaveWinners(tx, fields, values) if err != nil { return } return nil }) return } // AwardResult . func (s *Service) AwardResult(c context.Context, awardID int64) (res *model.AwardResult, err error) { var ( award *model.Award winners []*model.AwardWinner prizeInfo map[int64]*model.AwardPrize divisionInfo map[int64]*model.AwardDivision data = make(map[int64]map[int64][]int64) ) err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) { award, err = dao.Award(tx, awardID) if err != nil { return } if award == nil { err = ecode.Errorf(ecode.RequestErr, "award not found, awardID{%d}", awardID) return } winners, err = dao.AwardWinnerAll(tx, awardID) if err != nil { return } // divisions divisionInfo, err = dao.DivisionInfo(tx, awardID) if err != nil { return } // prizes prizeInfo, err = dao.PrizeInfo(tx, awardID) if err != nil { return } return nil }) if err != nil { return } // init for divisionID := range divisionInfo { data[divisionID] = make(map[int64][]int64) for prizeID := range prizeInfo { data[divisionID][prizeID] = make([]int64, 0) } } // mids for _, v := range winners { data[v.DivisionID][v.PrizeID] = append(data[v.DivisionID][v.PrizeID], v.MID) } // res res = &model.AwardResult{ AwardID: awardID, OpenTime: award.OpenTime.Unix(), AnnounceDate: award.AnnounceDate.Unix(), CycleEnd: award.CycleEnd.Unix(), Divisions: make([]*model.AwardDivisionResult, 0), } for divisionID, division := range divisionInfo { dv := &model.AwardDivisionResult{ DivisionID: divisionID, DivisionName: division.DivisionName, Prizes: make([]*model.AwardPrizeResult, 0), } for prizeID := range prizeInfo { mids := data[divisionID][prizeID] dv.Prizes = append(dv.Prizes, &model.AwardPrizeResult{MIDs: mids, PrizeID: prizeID}) } sort.Slice(dv.Prizes, func(i, j int) bool { return dv.Prizes[i].PrizeID < dv.Prizes[j].PrizeID }) res.Divisions = append(res.Divisions, dv) } sort.Slice(res.Divisions, func(i, j int) bool { return res.Divisions[i].DivisionID < res.Divisions[j].DivisionID }) return }