speical_award.go 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. package service
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "sort"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "go-common/app/admin/main/growup/dao"
  11. "go-common/app/admin/main/growup/dao/resource"
  12. "go-common/app/admin/main/growup/model"
  13. "go-common/app/admin/main/growup/util"
  14. "go-common/library/database/sql"
  15. "go-common/library/ecode"
  16. "go-common/library/log"
  17. "go-common/library/xstr"
  18. )
  19. const (
  20. awardEditable = iota + 1
  21. awardInfoEditable
  22. awardDivisionEditable
  23. awardPrizeEditable
  24. awardResourceEditable
  25. )
  26. const (
  27. _awardResourceTypeRule = 1
  28. _awardResourceTypeDetail = 3
  29. _awardResourceTypeQ = 5
  30. _awardResourceTypeA = 6
  31. )
  32. func awardEditPerms(award *model.Award) (res map[int]bool) {
  33. var (
  34. now = time.Now()
  35. notDisplay = award.DisplayStatus == 1
  36. notFinished = award.OpenStatus == 1
  37. preCycleStart = now.Before(award.CycleStart)
  38. )
  39. res = map[int]bool{
  40. awardEditable: notDisplay || notFinished,
  41. awardInfoEditable: notDisplay || preCycleStart,
  42. awardDivisionEditable: notDisplay || preCycleStart,
  43. awardPrizeEditable: notDisplay || notFinished,
  44. awardResourceEditable: notDisplay || notFinished,
  45. }
  46. return
  47. }
  48. func (s *Service) generateAwardID() (awardID int64, err error) {
  49. awardID, err = util.NewSnowFlake().Generate()
  50. return
  51. }
  52. func (s *Service) validateAwardCycle(c context.Context, awardID int64, start, end time.Time) (ok bool, err error) {
  53. // simplified version: check all
  54. awardBases, err := s.dao.ListAward(c)
  55. if err != nil {
  56. return
  57. }
  58. between := func(t, a, b time.Time) bool {
  59. return !(t.Before(a) || t.After(b))
  60. }
  61. for _, v := range awardBases {
  62. if awardID == v.AwardID || v.DisplayStatus != 2 {
  63. continue
  64. }
  65. if between(start, v.CycleStart, v.CycleEnd) || between(end, v.CycleStart, v.CycleEnd) {
  66. ok = false
  67. return
  68. }
  69. }
  70. ok = true
  71. return
  72. }
  73. // AddAward .
  74. func (s *Service) AddAward(c context.Context, arg *model.AddAwardArg, username string) (awardID int64, err error) {
  75. // 1. validation
  76. if !(arg.DisplayStatus == 1 || arg.DisplayStatus == 2) {
  77. err = ecode.RequestErr
  78. return
  79. }
  80. // 2. args
  81. // generate awardID
  82. awardID, err = s.generateAwardID()
  83. if err != nil {
  84. return
  85. }
  86. // cycle
  87. start := util.ToDayStart(time.Unix(arg.CycleStart, 0))
  88. end := util.ToDayEnd(time.Unix(arg.CycleEnd, 0))
  89. if arg.CycleStart > 0 && arg.CycleEnd > 0 && arg.DisplayStatus == 2 {
  90. var validCycle bool
  91. validCycle, err = s.validateAwardCycle(c, awardID, start, end)
  92. if err != nil {
  93. return
  94. }
  95. if !validCycle {
  96. err = ecode.Error(ecode.RequestErr, "评选周期重叠")
  97. return
  98. }
  99. }
  100. // total
  101. totalWinner, totalBonus := 0, 0
  102. if len(arg.Prizes) > 0 {
  103. for _, v := range arg.Prizes {
  104. totalWinner += v.Quota
  105. totalBonus += v.Bonus * v.Quota
  106. }
  107. }
  108. // 3. tx insert
  109. var (
  110. cycleStart = start.Format("2006-01-02 15:04:05")
  111. cycleEnd = end.Format("2006-01-02 15:04:05")
  112. announce = util.ToDayNoon(time.Unix(arg.AnnounceDate, 0))
  113. announceDate = announce.Format("2006-01-02")
  114. openTime = announce.Format("2006-01-02 15:04:05")
  115. )
  116. err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) {
  117. _, err = dao.AddAward(tx, awardID, arg.AwardName, cycleStart, cycleEnd, announceDate, openTime,
  118. arg.DisplayStatus, totalWinner, totalBonus, username)
  119. if err != nil {
  120. return
  121. }
  122. if len(arg.Divisions) > 0 {
  123. fields, values := saveDivisionStr(awardID, arg.Divisions)
  124. if values != "" {
  125. _, err = dao.SaveDivisions(tx, fields, values)
  126. if err != nil {
  127. return
  128. }
  129. }
  130. }
  131. if len(arg.Prizes) > 0 {
  132. fields, values := savePrizesStr(awardID, arg.Prizes)
  133. if values != "" {
  134. _, err = dao.SavePrizes(tx, fields, values)
  135. if err != nil {
  136. return
  137. }
  138. }
  139. }
  140. if arg.Resources != nil {
  141. fields, values := saveResourcesStr(awardID, arg.Resources)
  142. if values != "" {
  143. _, err = dao.SaveResource(tx, fields, values)
  144. if err != nil {
  145. return
  146. }
  147. }
  148. }
  149. return nil
  150. })
  151. return
  152. }
  153. func saveWinnerStr(winnersM map[int64]*model.AwardWinner) (fields, values string) {
  154. if len(winnersM) == 0 {
  155. return
  156. }
  157. fields = "award_id,mid,division_id,prize_id,tag_id"
  158. var buf bytes.Buffer
  159. for _, v := range winnersM {
  160. buf.WriteString("(")
  161. buf.WriteString(strconv.FormatInt(v.AwardID, 10))
  162. buf.WriteByte(',')
  163. buf.WriteString(strconv.FormatInt(v.MID, 10))
  164. buf.WriteByte(',')
  165. buf.WriteString(strconv.FormatInt(v.DivisionID, 10))
  166. buf.WriteByte(',')
  167. buf.WriteString(strconv.FormatInt(v.PrizeID, 10))
  168. buf.WriteByte(',')
  169. buf.WriteString(strconv.FormatInt(v.TagID, 10))
  170. buf.WriteString(")")
  171. buf.WriteByte(',')
  172. }
  173. if buf.Len() > 0 {
  174. buf.Truncate(buf.Len() - 1)
  175. }
  176. values = buf.String()
  177. values += " ON DUPLICATE KEY UPDATE division_id=VALUES(division_id), prize_id=VALUES(prize_id), tag_id=VALUES(tag_id), is_deleted=0"
  178. buf.Reset()
  179. return
  180. }
  181. func saveDivisionStr(awardID int64, divisions []*model.AwardDivision) (fields, values string) {
  182. if len(divisions) == 0 {
  183. return
  184. }
  185. vs := make([]string, 0)
  186. for i, v := range divisions {
  187. vs = append(vs, fmt.Sprintf("(%d,%d,'%s',%d)", awardID, i+1, v.DivisionName, v.TagID))
  188. }
  189. if len(vs) > 0 {
  190. fields = "award_id,division_id,division_name,tag_id"
  191. values = strings.Join(vs, ",") + " ON DUPLICATE KEY UPDATE division_name=VALUES(division_name), tag_id=VALUES(tag_id), is_deleted=0"
  192. }
  193. return
  194. }
  195. func savePrizesStr(awardID int64, prizes []*model.AwardPrize) (fields, values string) {
  196. if len(prizes) == 0 {
  197. return
  198. }
  199. vs := make([]string, 0)
  200. for i, v := range prizes {
  201. vs = append(vs, fmt.Sprintf("(%d,%d,%d,%d)", awardID, i+1, v.Bonus, v.Quota))
  202. }
  203. if len(vs) > 0 {
  204. fields = "award_id,prize_id,bonus,quota"
  205. values = strings.Join(vs, ",") + " ON DUPLICATE KEY UPDATE bonus=VALUES(bonus), quota=VALUES(quota), is_deleted=0"
  206. }
  207. return
  208. }
  209. func delResourcesStr(awardID int64, arg *model.AwardResource) (delWhere string) {
  210. if len(arg.QA) == 0 {
  211. return fmt.Sprintf("award_id = %d AND resource_type IN (%d,%d)", awardID, _awardResourceTypeQ, _awardResourceTypeA)
  212. }
  213. idx := make([]int64, 0)
  214. for i := range arg.QA {
  215. idx = append(idx, int64(i+1))
  216. }
  217. return fmt.Sprintf("award_id = %d AND resource_type IN (%d,%d) AND resource_index NOT IN (%s)",
  218. awardID, _awardResourceTypeQ, _awardResourceTypeA, xstr.JoinInts(idx))
  219. }
  220. func saveResourcesStr(awardID int64, arg *model.AwardResource) (fields, values string) {
  221. if arg == nil {
  222. return
  223. }
  224. vs := make([]string, 0)
  225. vs = append(vs, fmt.Sprintf("(%d,%d,1,'%s')", awardID, _awardResourceTypeRule, arg.Rule))
  226. vs = append(vs, fmt.Sprintf("(%d,%d,1,'%s')", awardID, _awardResourceTypeDetail, arg.Detail))
  227. if len(arg.QA) > 0 {
  228. for i, qa := range arg.QA {
  229. vs = append(vs, fmt.Sprintf("(%d,%d,%d,'%s')", awardID, _awardResourceTypeQ, i+1, qa.Q))
  230. vs = append(vs, fmt.Sprintf("(%d,%d,%d,'%s')", awardID, _awardResourceTypeA, i+1, qa.A))
  231. }
  232. }
  233. if len(vs) > 0 {
  234. fields = "award_id,resource_type,resource_index,content"
  235. values = strings.Join(vs, ",") + " ON DUPLICATE KEY UPDATE content=VALUES(content), is_deleted=0"
  236. }
  237. return
  238. }
  239. // UpdateAward .
  240. func (s *Service) UpdateAward(c context.Context, arg *model.SaveAwardArg) (err error) {
  241. // 1.
  242. if !(arg.DisplayStatus == 1 || arg.DisplayStatus == 2) || arg.AwardID == 0 {
  243. return ecode.Error(ecode.RequestErr, "illegal param")
  244. }
  245. awardID := arg.AwardID
  246. award, err := s.dao.Award(c, awardID)
  247. if err != nil {
  248. return
  249. }
  250. if award == nil {
  251. err = ecode.Error(ecode.RequestErr, "illegal award_id")
  252. return
  253. }
  254. //
  255. permission := awardEditPerms(award)
  256. if !permission[awardEditable] {
  257. err = ecode.Error(ecode.RequestErr, "award no longer editable")
  258. return
  259. }
  260. // sum
  261. totalQuota, totalBonus := 0, 0
  262. if len(arg.Prizes) > 0 {
  263. for _, v := range arg.Prizes {
  264. totalQuota += v.Quota
  265. totalBonus += v.Bonus * v.Quota
  266. }
  267. }
  268. newAward := &model.Award{
  269. AwardName: arg.AwardName,
  270. CycleStart: util.ToDayStart(time.Unix(arg.CycleStart, 0)),
  271. CycleEnd: util.ToDayEnd(time.Unix(arg.CycleEnd, 0)),
  272. AnnounceDate: time.Unix(arg.AnnounceDate, 0),
  273. OpenTime: util.ToDayNoon(time.Unix(arg.AnnounceDate, 0)),
  274. DisplayStatus: arg.DisplayStatus,
  275. TotalQuota: totalQuota,
  276. TotalBonus: totalBonus,
  277. }
  278. if permission[awardInfoEditable] && arg.DisplayStatus == 2 {
  279. if !newAward.CycleStart.Equal(award.CycleStart) || !newAward.CycleEnd.Equal(award.CycleEnd) {
  280. var ok bool
  281. ok, err = s.validateAwardCycle(c, awardID, newAward.CycleStart, newAward.CycleEnd)
  282. if err != nil {
  283. return
  284. }
  285. if !ok {
  286. err = ecode.Error(ecode.RequestErr, "评选周期重叠")
  287. return
  288. }
  289. }
  290. }
  291. err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) {
  292. // lock
  293. award, err = dao.SelectAwardForUpdate(tx, awardID)
  294. if err != nil {
  295. return
  296. }
  297. if award == nil {
  298. return ecode.Error(ecode.RequestErr, "award not found")
  299. }
  300. //// award info
  301. if permission[awardInfoEditable] {
  302. updateAwardStr := fmt.Sprintf(`award_name='%s', cycle_start='%s', cycle_end='%s',
  303. announce_date='%s', open_time='%s', display_status=%d, total_quota=%d, total_bonus=%d`,
  304. newAward.AwardName,
  305. newAward.CycleStart.Format("2006-01-02 15:04:05"),
  306. newAward.CycleEnd.Format("2006-01-02 15:04:05"),
  307. newAward.AnnounceDate.Format("2006-01-02"),
  308. newAward.OpenTime.Format("2006-01-02 15:04:05"),
  309. newAward.DisplayStatus, newAward.TotalQuota, newAward.TotalBonus)
  310. _, err = dao.UpdateAward(tx, awardID, updateAwardStr)
  311. if err != nil {
  312. return
  313. }
  314. }
  315. //// divisions
  316. if permission[awardDivisionEditable] {
  317. switch {
  318. case len(arg.Divisions) == 0:
  319. _, err = dao.DelDivisionAll(tx, awardID)
  320. if err != nil {
  321. return
  322. }
  323. default:
  324. // del
  325. argDivisionIDs := make([]int64, 0)
  326. for i, v := range arg.Divisions {
  327. v.DivisionID = int64(i + 1)
  328. argDivisionIDs = append(argDivisionIDs, v.DivisionID)
  329. }
  330. _, err = dao.DelDivisionsExclude(tx, awardID, argDivisionIDs)
  331. if err != nil {
  332. return
  333. }
  334. // save
  335. fields, values := saveDivisionStr(awardID, arg.Divisions)
  336. _, err = dao.SaveDivisions(tx, fields, values)
  337. if err != nil {
  338. return
  339. }
  340. }
  341. }
  342. //// prizes
  343. if permission[awardPrizeEditable] {
  344. switch {
  345. case len(arg.Prizes) == 0:
  346. _, err = dao.DelPrizeAll(tx, awardID)
  347. if err != nil {
  348. return
  349. }
  350. default:
  351. // del
  352. argPrizeIDs := make([]int64, 0)
  353. for i, v := range arg.Prizes {
  354. v.PrizeID = int64(i + 1)
  355. argPrizeIDs = append(argPrizeIDs, v.PrizeID)
  356. }
  357. _, err = dao.DelPrizesExclude(tx, awardID, argPrizeIDs)
  358. if err != nil {
  359. return
  360. }
  361. fields, values := savePrizesStr(awardID, arg.Prizes)
  362. _, err = dao.SavePrizes(tx, fields, values)
  363. if err != nil {
  364. return
  365. }
  366. }
  367. }
  368. //// resources
  369. if permission[awardResourceEditable] {
  370. switch {
  371. case arg.Resources == nil:
  372. _, err = dao.DelResources(tx, fmt.Sprintf("award_id = %d", awardID))
  373. if err != nil {
  374. return
  375. }
  376. default:
  377. delWhere := delResourcesStr(awardID, arg.Resources)
  378. _, err = dao.DelResources(tx, delWhere)
  379. if err != nil {
  380. return
  381. }
  382. fields, values := saveResourcesStr(awardID, arg.Resources)
  383. _, err = dao.SaveResource(tx, fields, values)
  384. if err != nil {
  385. return
  386. }
  387. }
  388. }
  389. return nil
  390. })
  391. return err
  392. }
  393. // ListAward .
  394. func (s *Service) ListAward(c context.Context, from, limit int) (total int64, data []*model.AwardListModel, err error) {
  395. data = make([]*model.AwardListModel, 0)
  396. var (
  397. awardToWinnerC map[int64]int
  398. awards []*model.Award
  399. divisions []*model.AwardDivision
  400. )
  401. err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) {
  402. total, err = dao.CountAward(tx)
  403. if err != nil {
  404. return
  405. }
  406. if total == 0 {
  407. return
  408. }
  409. awards, err = dao.ListAward(tx, from, limit)
  410. if err != nil {
  411. return
  412. }
  413. if len(awards) == 0 {
  414. return
  415. }
  416. awardIDs := make([]int64, 0)
  417. for _, v := range awards {
  418. awardIDs = append(awardIDs, v.AwardID)
  419. }
  420. divisions, err = dao.ListAwardsDivision(tx, fmt.Sprintf("award_id IN (%s)", xstr.JoinInts(awardIDs)))
  421. if err != nil {
  422. return
  423. }
  424. awardToWinnerC, err = dao.GroupCountAwardWinner(tx, fmt.Sprintf("award_id IN (%s)", xstr.JoinInts(awardIDs)))
  425. if err != nil {
  426. return
  427. }
  428. return nil
  429. })
  430. if err != nil || total == 0 || len(awards) == 0 {
  431. return
  432. }
  433. // divisions group by award_id
  434. var (
  435. tagIDToName map[int64]string
  436. awardToDivisions = make(map[int64][]*model.AwardDivision)
  437. )
  438. tagIDToName, err = resource.VideoCategoryIDToName(c)
  439. if err != nil {
  440. return
  441. }
  442. for _, division := range divisions {
  443. if _, ok := awardToDivisions[division.AwardID]; !ok {
  444. awardToDivisions[division.AwardID] = make([]*model.AwardDivision, 0)
  445. }
  446. awardToDivisions[division.AwardID] = append(awardToDivisions[division.AwardID], division)
  447. }
  448. for _, award := range awards {
  449. v := &model.AwardListModel{
  450. ID: award.ID,
  451. AwardID: award.AwardID,
  452. AwardName: award.AwardName,
  453. CycleStart: award.CycleStart.Unix(),
  454. CycleEnd: award.CycleEnd.Unix(),
  455. TotalQuota: award.TotalQuota,
  456. TotalBonus: award.TotalBonus,
  457. AnnounceDate: award.AnnounceDate.Unix(),
  458. OpenStatus: award.OpenStatus,
  459. OpenTime: award.OpenTime.Unix(),
  460. CTime: award.CTime.Unix(),
  461. CreatedBy: award.CreatedBy,
  462. SelectionStatus: 1,
  463. Tags: make([]string, 0),
  464. DivisionNames: make([]string, 0),
  465. }
  466. // status
  467. if count, ok := awardToWinnerC[v.AwardID]; ok && count == v.TotalQuota {
  468. v.SelectionStatus = 2
  469. }
  470. tagIDs := make([]int64, 0)
  471. for _, division := range awardToDivisions[v.AwardID] {
  472. tagIDs = append(tagIDs, division.TagID)
  473. v.DivisionNames = append(v.DivisionNames, division.DivisionName)
  474. }
  475. for _, tagID := range tagIDs {
  476. v.Tags = append(v.Tags, tagIDToName[tagID])
  477. }
  478. data = append(data, v)
  479. }
  480. return
  481. }
  482. // DetailAward .
  483. func (s *Service) DetailAward(c context.Context, awardID int64) (data *model.AwardDetail, err error) {
  484. data = &model.AwardDetail{}
  485. var (
  486. winners = 0
  487. typeIdxContent map[int]map[int]string
  488. )
  489. err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) {
  490. data.Award, err = dao.Award(tx, awardID)
  491. if err != nil {
  492. return
  493. }
  494. if data.Award == nil {
  495. err = ecode.Errorf(ecode.RequestErr, "award not found, awardID{%d}", awardID)
  496. return
  497. }
  498. data.Divisions, err = dao.ListDivision(tx, awardID)
  499. if err != nil {
  500. return
  501. }
  502. data.Prizes, err = dao.ListPrize(tx, awardID)
  503. if err != nil {
  504. return
  505. }
  506. typeIdxContent, err = dao.ListResource(tx, awardID)
  507. if err != nil {
  508. return
  509. }
  510. total, err := dao.CountAwardWinner(tx, awardID, "")
  511. if err != nil {
  512. return
  513. }
  514. winners = int(total)
  515. return nil
  516. })
  517. if err != nil {
  518. return
  519. }
  520. data.Award.SelectionStatus = 1
  521. if data.Award.TotalQuota == winners {
  522. data.Award.SelectionStatus = 2
  523. }
  524. // tags
  525. if len(data.Divisions) > 0 {
  526. var tagNames map[int64]string
  527. tagNames, err = resource.VideoCategoryIDToName(c)
  528. if err != nil {
  529. return
  530. }
  531. for _, division := range data.Divisions {
  532. if tagName, ok := tagNames[division.TagID]; ok {
  533. division.Tag = tagName
  534. }
  535. }
  536. }
  537. data.Resources = &model.AwardResource{
  538. Rule: typeIdxContent[1][1],
  539. Detail: typeIdxContent[3][1],
  540. QA: make([]*model.AwardQA, 0),
  541. }
  542. questions, answers := typeIdxContent[5], typeIdxContent[6]
  543. if len(questions) > 0 && len(answers) > 0 {
  544. for idx, question := range questions {
  545. data.Resources.QA = append(data.Resources.QA, &model.AwardQA{Index: idx, Q: question, A: answers[idx]})
  546. }
  547. }
  548. sort.Slice(data.Resources.QA, func(i, j int) bool {
  549. return data.Resources.QA[i].Index < data.Resources.QA[j].Index
  550. })
  551. data.Award.GenStr()
  552. return
  553. }
  554. // ListAwardWinner .
  555. func (s *Service) ListAwardWinner(c context.Context, arg *model.QueryAwardWinnerArg) (total int64, res []*model.AwardWinner, err error) {
  556. res = make([]*model.AwardWinner, 0)
  557. if pass := s.validateQueryAwardWinner(c, arg); !pass {
  558. return
  559. }
  560. where := s.queryAwardWinnerWhere(arg)
  561. var (
  562. winnerInfo map[int64]*model.AwardWinner // <mid, *winner>
  563. prizeInfo map[int64]*model.AwardPrize // <prize_id, *prize>
  564. divisionInfo map[int64]*model.AwardDivision // <division_id, *division>
  565. mids = make([]int64, 0)
  566. )
  567. err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) {
  568. total, err = dao.CountAwardWinner(tx, arg.AwardID, where)
  569. if err != nil {
  570. return
  571. }
  572. if total == 0 {
  573. return
  574. }
  575. winnerInfo, err = dao.QueryAwardWinner(tx, arg.AwardID, fmt.Sprintf("%s ORDER BY id DESC LIMIT %d,%d", where, arg.From, arg.Limit))
  576. if err != nil {
  577. return
  578. }
  579. if len(winnerInfo) > 0 {
  580. // divisions
  581. divisionInfo, err = dao.DivisionInfo(tx, arg.AwardID)
  582. if err != nil {
  583. return
  584. }
  585. // prizes
  586. prizeInfo, err = dao.PrizeInfo(tx, arg.AwardID)
  587. if err != nil {
  588. return
  589. }
  590. }
  591. return nil
  592. })
  593. if err != nil || total == 0 || len(winnerInfo) == 0 {
  594. return
  595. }
  596. categories, err := resource.VideoCategoryIDToName(c)
  597. if err != nil {
  598. return
  599. }
  600. for mid := range winnerInfo {
  601. mids = append(mids, mid)
  602. }
  603. upNames, err := resource.NamesByMIDs(c, mids)
  604. if err != nil {
  605. return
  606. }
  607. for mid, info := range winnerInfo {
  608. if division, ok := divisionInfo[info.DivisionID]; ok {
  609. info.DivisionName = division.DivisionName
  610. }
  611. if prize, ok := prizeInfo[info.PrizeID]; ok {
  612. info.Bonus = prize.Bonus
  613. }
  614. // tag
  615. if data, ok := categories[info.TagID]; ok {
  616. info.Tag = data
  617. }
  618. // nickname
  619. if nickname, ok := upNames[mid]; ok {
  620. info.Nickname = nickname
  621. }
  622. }
  623. res = make([]*model.AwardWinner, 0)
  624. for _, v := range winnerInfo {
  625. res = append(res, v)
  626. }
  627. return
  628. }
  629. // ExportAwardWinner .
  630. func (s *Service) ExportAwardWinner(c context.Context, arg *model.QueryAwardWinnerArg) (res []byte, err error) {
  631. records, err := s.listAwardWinnerAll(c, arg)
  632. if err != nil {
  633. return
  634. }
  635. data := make([][]string, 0, len(records)+1)
  636. data = append(data, model.AwardWinnerExportFields())
  637. for _, v := range records {
  638. data = append(data, v.ExportStrings())
  639. }
  640. if res, err = FormatCSV(data); err != nil {
  641. log.Error("FormatCSV error(%v)", err)
  642. }
  643. return
  644. }
  645. func (s *Service) listAwardWinnerAll(c context.Context, arg *model.QueryAwardWinnerArg) (records []*model.AwardWinner, err error) {
  646. records = make([]*model.AwardWinner, 0)
  647. if pass := s.validateQueryAwardWinner(c, arg); !pass {
  648. return
  649. }
  650. where := s.queryAwardWinnerWhere(arg)
  651. var (
  652. winnerInfo map[int64]*model.AwardWinner // <mid, *winner>
  653. prizeInfo map[int64]*model.AwardPrize // <prize_id, *prize>
  654. divisionInfo map[int64]*model.AwardDivision // <division_id, *division>
  655. mids = make([]int64, 0)
  656. )
  657. err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) {
  658. winnerInfo, err = dao.QueryAwardWinner(tx, arg.AwardID, fmt.Sprintf("%s ORDER BY id DESC", where))
  659. if err != nil {
  660. return
  661. }
  662. if len(winnerInfo) > 0 {
  663. // divisions
  664. divisionInfo, err = dao.DivisionInfo(tx, arg.AwardID)
  665. if err != nil {
  666. return
  667. }
  668. // prizes
  669. prizeInfo, err = dao.PrizeInfo(tx, arg.AwardID)
  670. if err != nil {
  671. return
  672. }
  673. }
  674. return nil
  675. })
  676. if err != nil {
  677. return
  678. }
  679. if len(winnerInfo) == 0 {
  680. return
  681. }
  682. categories, err := resource.VideoCategoryIDToName(c)
  683. if err != nil {
  684. return
  685. }
  686. for mid := range winnerInfo {
  687. mids = append(mids, mid)
  688. }
  689. upNames, err := resource.NamesByMIDs(c, mids)
  690. if err != nil {
  691. return
  692. }
  693. for mid, info := range winnerInfo {
  694. if division, ok := divisionInfo[info.DivisionID]; ok {
  695. info.DivisionName = division.DivisionName
  696. }
  697. if prize, ok := prizeInfo[info.PrizeID]; ok {
  698. info.Bonus = prize.Bonus
  699. }
  700. // tag
  701. if data, ok := categories[info.TagID]; ok {
  702. info.Tag = data
  703. }
  704. // nickname
  705. if nickname, ok := upNames[mid]; ok {
  706. info.Nickname = nickname
  707. }
  708. }
  709. for _, v := range winnerInfo {
  710. records = append(records, v)
  711. }
  712. return
  713. }
  714. func (s *Service) validateQueryAwardWinner(c context.Context, arg *model.QueryAwardWinnerArg) (pass bool) {
  715. if arg.Nickname != "" {
  716. mid, err := resource.MidByNickname(c, arg.Nickname)
  717. if err != nil || mid == 0 {
  718. return
  719. }
  720. if arg.MID == 0 {
  721. arg.MID = mid
  722. }
  723. if arg.MID != mid {
  724. log.Error("illegal mid(%d) and nickname(%s) pair", arg.MID, arg.Nickname)
  725. return
  726. }
  727. }
  728. return true
  729. }
  730. func (s *Service) queryAwardWinnerWhere(arg *model.QueryAwardWinnerArg) string {
  731. str := ""
  732. if arg.MID > 0 {
  733. str += fmt.Sprintf(" AND mid=%d", arg.MID)
  734. }
  735. if arg.TagID > 0 {
  736. str += fmt.Sprintf(" AND tag_id=%d", arg.TagID)
  737. }
  738. return str
  739. }
  740. // ReplaceAwardWinner .
  741. func (s *Service) ReplaceAwardWinner(c context.Context, awardID, prevMID, mid int64) (err error) {
  742. records, err := s.dao.ListAwardRecord(c, awardID, fmt.Sprintf("AND (mid=%d OR mid=%d)", prevMID, mid))
  743. if err != nil {
  744. return
  745. }
  746. midsM := make(map[int64]bool)
  747. for _, v := range records {
  748. midsM[v.MID] = true
  749. }
  750. if !midsM[prevMID] {
  751. return ecode.Errorf(ecode.RequestErr, "mid(%d) not in award(%d)", prevMID, awardID)
  752. }
  753. if !midsM[mid] {
  754. return ecode.Errorf(ecode.RequestErr, "mid(%d) not in award(%d)", mid, awardID)
  755. }
  756. err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) {
  757. // lock award
  758. award, err := dao.SelectAwardForUpdate(tx, awardID)
  759. if err != nil {
  760. return
  761. }
  762. if award == nil {
  763. return ecode.Error(ecode.RequestErr, "award not found")
  764. }
  765. if award.OpenStatus != 1 {
  766. return ecode.Error(ecode.RequestErr, "illegal operation")
  767. }
  768. // winner info
  769. res, err := dao.QueryAwardWinner(tx, awardID, fmt.Sprintf("AND (mid=%d OR mid=%d)", prevMID, mid))
  770. if err != nil {
  771. return
  772. }
  773. prevWinner, ok := res[prevMID]
  774. if !ok {
  775. return ecode.Error(ecode.RequestErr, "invalid old winner")
  776. }
  777. if _, ok = res[mid]; ok {
  778. return ecode.Error(ecode.RequestErr, "invalid new winner")
  779. }
  780. // replace
  781. rows, err := dao.DelWinner(tx, awardID, fmt.Sprintf(" AND mid=%d", prevMID))
  782. if err != nil {
  783. return
  784. }
  785. if rows != 1 {
  786. return ecode.Error(ecode.ServerErr, "failed to del old winner")
  787. }
  788. fields, values := saveWinnerStr(map[int64]*model.AwardWinner{
  789. awardID: {
  790. AwardID: awardID,
  791. MID: mid,
  792. DivisionID: prevWinner.DivisionID,
  793. PrizeID: prevWinner.PrizeID,
  794. TagID: prevWinner.TagID,
  795. },
  796. })
  797. rows, err = dao.SaveWinners(tx, fields, values)
  798. if err != nil {
  799. return
  800. }
  801. if rows != 1 {
  802. return ecode.Error(ecode.ServerErr, "failed to add new winner")
  803. }
  804. return
  805. })
  806. return
  807. }
  808. // SaveAwardResult .
  809. func (s *Service) SaveAwardResult(c context.Context, arg *model.AwardResult) (err error) {
  810. var (
  811. awardID = arg.AwardID
  812. winnersM = make(map[int64]*model.AwardWinner)
  813. prizeWinnerC = make(map[int64]int)
  814. divisionInfo map[int64]*model.AwardDivision
  815. )
  816. divisionInfo, err = s.dao.AwardDivisionInfo(c, awardID)
  817. if err != nil {
  818. return
  819. }
  820. for divisionI, division := range arg.Divisions {
  821. divisionID := int64(divisionI + 1)
  822. for prizeI, prize := range division.Prizes {
  823. prizeID := int64(prizeI + 1)
  824. prizeWinnerC[prizeID] += len(prize.MIDs)
  825. for _, mid := range prize.MIDs {
  826. if _, ok := winnersM[mid]; ok {
  827. return ecode.Error(ecode.RequestErr, "UID重复,请重新录入")
  828. }
  829. winnersM[mid] = &model.AwardWinner{
  830. MID: mid,
  831. AwardID: awardID,
  832. DivisionID: divisionID,
  833. PrizeID: prizeID,
  834. TagID: divisionInfo[divisionID].TagID,
  835. }
  836. }
  837. }
  838. }
  839. mids := make([]int64, 0, len(winnersM))
  840. for k := range winnersM {
  841. mids = append(mids, k)
  842. }
  843. if len(winnersM) == 0 {
  844. return ecode.Error(ecode.RequestErr, "奖项人数不符,保存失败")
  845. }
  846. // 是否已报名专项奖
  847. {
  848. var winnerRecords []*model.AwardRecord
  849. winnerRecords, err = s.dao.ListAwardRecord(c, awardID, fmt.Sprintf("AND mid IN (%s)", xstr.JoinInts(mids)))
  850. if err != nil {
  851. return
  852. }
  853. if len(winnersM) != len(winnerRecords) {
  854. var (
  855. awardRecordM = make(map[int64]bool)
  856. unSignedMIDs []int64
  857. )
  858. for _, rcr := range winnerRecords {
  859. awardRecordM[rcr.MID] = true
  860. }
  861. for _, mid := range mids {
  862. if !awardRecordM[mid] {
  863. unSignedMIDs = append(unSignedMIDs, mid)
  864. }
  865. }
  866. return ecode.Errorf(ecode.RequestErr, "%s 未报名专项奖,保存失败", xstr.JoinInts(unSignedMIDs))
  867. }
  868. }
  869. // 是否已签约激励
  870. {
  871. var signedUPs map[int64]struct{}
  872. signedUPs, err = s.dao.GetUpInfoByState(c, "up_info_video", mids, 3)
  873. if err != nil {
  874. return
  875. }
  876. if len(mids) != len(signedUPs) {
  877. var unSignedMIDs []int64
  878. for _, mid := range mids {
  879. if _, ok := signedUPs[mid]; !ok {
  880. unSignedMIDs = append(unSignedMIDs, mid)
  881. }
  882. }
  883. return ecode.Errorf(ecode.RequestErr, "%s 非签约状态,保存失败", xstr.JoinInts(unSignedMIDs))
  884. }
  885. }
  886. // save winners
  887. updateAwardStr := fmt.Sprintf("open_time = '%s'", time.Unix(arg.OpenTime, 0).Format("2006-01-02 15:04:05"))
  888. fields, values := saveWinnerStr(winnersM)
  889. err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) {
  890. award, err := dao.SelectAwardForUpdate(tx, awardID)
  891. if err != nil {
  892. return
  893. }
  894. if award == nil {
  895. return ecode.Errorf(ecode.RequestErr, "award not found, awardID{%d}", awardID)
  896. }
  897. if award.OpenStatus != 1 {
  898. return ecode.Error(ecode.RequestErr, "已发奖,不能再修改名单")
  899. }
  900. if award.TotalQuota != len(mids) {
  901. return ecode.Error(ecode.RequestErr, "奖项人数不符,保存失败")
  902. }
  903. prizeInfo, err := dao.PrizeInfo(tx, awardID)
  904. if err != nil {
  905. return
  906. }
  907. for prizeID, info := range prizeInfo {
  908. if prizeWinnerC[prizeID] != info.Quota {
  909. return ecode.Error(ecode.RequestErr, "奖项人数不符,保存失败")
  910. }
  911. }
  912. _, err = dao.UpdateAward(tx, awardID, updateAwardStr)
  913. if err != nil {
  914. return
  915. }
  916. _, err = dao.DelWinnerAll(tx, awardID)
  917. if err != nil {
  918. return
  919. }
  920. _, err = dao.SaveWinners(tx, fields, values)
  921. if err != nil {
  922. return
  923. }
  924. return nil
  925. })
  926. return
  927. }
  928. // AwardResult .
  929. func (s *Service) AwardResult(c context.Context, awardID int64) (res *model.AwardResult, err error) {
  930. var (
  931. award *model.Award
  932. winners []*model.AwardWinner
  933. prizeInfo map[int64]*model.AwardPrize
  934. divisionInfo map[int64]*model.AwardDivision
  935. data = make(map[int64]map[int64][]int64)
  936. )
  937. err = s.dao.DoInTx(c, func(tx *sql.Tx) (err error) {
  938. award, err = dao.Award(tx, awardID)
  939. if err != nil {
  940. return
  941. }
  942. if award == nil {
  943. err = ecode.Errorf(ecode.RequestErr, "award not found, awardID{%d}", awardID)
  944. return
  945. }
  946. winners, err = dao.AwardWinnerAll(tx, awardID)
  947. if err != nil {
  948. return
  949. }
  950. // divisions
  951. divisionInfo, err = dao.DivisionInfo(tx, awardID)
  952. if err != nil {
  953. return
  954. }
  955. // prizes
  956. prizeInfo, err = dao.PrizeInfo(tx, awardID)
  957. if err != nil {
  958. return
  959. }
  960. return nil
  961. })
  962. if err != nil {
  963. return
  964. }
  965. // init
  966. for divisionID := range divisionInfo {
  967. data[divisionID] = make(map[int64][]int64)
  968. for prizeID := range prizeInfo {
  969. data[divisionID][prizeID] = make([]int64, 0)
  970. }
  971. }
  972. // mids
  973. for _, v := range winners {
  974. data[v.DivisionID][v.PrizeID] = append(data[v.DivisionID][v.PrizeID], v.MID)
  975. }
  976. // res
  977. res = &model.AwardResult{
  978. AwardID: awardID,
  979. OpenTime: award.OpenTime.Unix(),
  980. AnnounceDate: award.AnnounceDate.Unix(),
  981. CycleEnd: award.CycleEnd.Unix(),
  982. Divisions: make([]*model.AwardDivisionResult, 0),
  983. }
  984. for divisionID, division := range divisionInfo {
  985. dv := &model.AwardDivisionResult{
  986. DivisionID: divisionID,
  987. DivisionName: division.DivisionName,
  988. Prizes: make([]*model.AwardPrizeResult, 0),
  989. }
  990. for prizeID := range prizeInfo {
  991. mids := data[divisionID][prizeID]
  992. dv.Prizes = append(dv.Prizes, &model.AwardPrizeResult{MIDs: mids, PrizeID: prizeID})
  993. }
  994. sort.Slice(dv.Prizes, func(i, j int) bool {
  995. return dv.Prizes[i].PrizeID < dv.Prizes[j].PrizeID
  996. })
  997. res.Divisions = append(res.Divisions, dv)
  998. }
  999. sort.Slice(res.Divisions, func(i, j int) bool {
  1000. return res.Divisions[i].DivisionID < res.Divisions[j].DivisionID
  1001. })
  1002. return
  1003. }