bilibili-backup/app/admin/main/growup/service/speical_award.go

1038 lines
27 KiB
Go
Raw Normal View History

2019-04-22 10:59:20 +08:00
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
}