12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037 |
- 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 // <mid, *winner>
- prizeInfo map[int64]*model.AwardPrize // <prize_id, *prize>
- divisionInfo map[int64]*model.AwardDivision // <division_id, *division>
- 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 // <mid, *winner>
- prizeInfo map[int64]*model.AwardPrize // <prize_id, *prize>
- divisionInfo map[int64]*model.AwardDivision // <division_id, *division>
- 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
- }
|