activity.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. package service
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "sort"
  7. "strconv"
  8. "time"
  9. "go-common/app/admin/main/growup/model"
  10. "go-common/library/database/sql"
  11. "go-common/library/log"
  12. xtime "go-common/library/time"
  13. )
  14. const (
  15. _activityNotStart = iota
  16. _activityStart
  17. _activityEnd
  18. )
  19. // AddActivity add creative activity
  20. func (s *Service) AddActivity(c context.Context, ac *model.CActivity, creator string) (err error) {
  21. ac.Creator = creator
  22. _, err = s.dao.GetActivityByName(c, ac.Name)
  23. if err == sql.ErrNoRows {
  24. err = s.insertActivity(c, ac, "", true)
  25. return
  26. }
  27. if err != nil {
  28. log.Error("s.dao.GetActivityByName error(%v)", err)
  29. return
  30. }
  31. err = fmt.Errorf("activity has exist")
  32. return
  33. }
  34. func actQueyStmt(name, sort string) string {
  35. query := ""
  36. if name != "" {
  37. query = fmt.Sprintf("WHERE name = '%s'", name)
  38. }
  39. if sort != "" {
  40. query += " ORDER BY "
  41. query += sort
  42. }
  43. return query
  44. }
  45. // ListActivity list activity by query
  46. func (s *Service) ListActivity(c context.Context, name string, from, limit int, sort string) (acs []*model.CActivity, total int, err error) {
  47. query := actQueyStmt(name, sort)
  48. total, err = s.dao.ActivityCount(c, query)
  49. if err != nil {
  50. log.Error("s.dao.ActivityCount error(%v)", err)
  51. return
  52. }
  53. acs, err = s.dao.GetActivities(c, query, from, limit)
  54. if err != nil {
  55. log.Error("s.dao.GetActivities error(%v)", err)
  56. return
  57. }
  58. if len(acs) == 0 {
  59. return
  60. }
  61. ids := make([]int64, len(acs))
  62. for i := 0; i < len(acs); i++ {
  63. ids[i] = acs[i].ID
  64. }
  65. bonus, err := s.getActivityBonus(c, ids)
  66. if err != nil {
  67. log.Error("s.getActivityBonus error(%v)", err)
  68. return
  69. }
  70. now := xtime.Time(time.Now().Unix())
  71. for _, ac := range acs {
  72. if now < ac.SignUpStart {
  73. ac.State = _activityNotStart
  74. } else if now >= ac.SignUpStart && now <= ac.BonusTime {
  75. ac.State = _activityStart
  76. } else if now > ac.BonusTime {
  77. ac.State = _activityEnd
  78. }
  79. ac.BonusMoney = bonus[ac.ID]
  80. ac.Enrolment, err = s.dao.UpActivityStateCount(c, ac.ID, []int64{1, 2, 3})
  81. if err != nil {
  82. log.Error("s.dao.UpActivityStateCount error(%v)", err)
  83. return
  84. }
  85. ac.WinNum, err = s.dao.UpActivityStateCount(c, ac.ID, []int64{2, 3})
  86. if err != nil {
  87. log.Error("s.dao.UpActivityStateCount error(%v)", err)
  88. return
  89. }
  90. }
  91. return
  92. }
  93. func checkSignUp(oldAc, newAc *model.CActivity) bool {
  94. if oldAc.SignedStart != newAc.SignedStart ||
  95. oldAc.SignedEnd != newAc.SignedEnd ||
  96. oldAc.SignUp != newAc.SignUp ||
  97. oldAc.SignUpStart != newAc.SignUpStart {
  98. return false
  99. }
  100. return true
  101. }
  102. func checkWin(oldAc, newAc *model.CActivity) bool {
  103. if oldAc.Object != newAc.Object ||
  104. oldAc.UploadStart != newAc.UploadStart ||
  105. oldAc.UploadEnd != newAc.UploadEnd ||
  106. oldAc.WinType != newAc.WinType ||
  107. oldAc.RequireItems != newAc.RequireItems ||
  108. oldAc.RequireValue != newAc.RequireValue ||
  109. oldAc.StatisticsStart != newAc.StatisticsStart {
  110. return false
  111. }
  112. return true
  113. }
  114. func checkBonus(oldAc, newAc *model.CActivity) bool {
  115. if oldAc.BonusType != newAc.BonusType ||
  116. oldAc.BonusTime != newAc.BonusTime {
  117. return false
  118. }
  119. return true
  120. }
  121. func checkProgress(oldAc, newAc *model.CActivity) bool {
  122. if oldAc.ProgressFrequency != newAc.ProgressFrequency ||
  123. oldAc.UpdatePage != newAc.UpdatePage ||
  124. oldAc.ProgressStart != newAc.ProgressStart ||
  125. oldAc.ProgressSync != newAc.ProgressSync {
  126. return false
  127. }
  128. return true
  129. }
  130. func checkOpenBonus(oldAc, newAc *model.CActivity) bool {
  131. if oldAc.BonusQuery != newAc.BonusQuery ||
  132. oldAc.BonusQuerStart != newAc.BonusQuerStart {
  133. return false
  134. }
  135. return true
  136. }
  137. // UpdateActivity update creative activity
  138. func (s *Service) UpdateActivity(c context.Context, newAc *model.CActivity) (err error) {
  139. acs, _, err := s.ListActivity(c, newAc.Name, 0, 1, "")
  140. if err != nil {
  141. log.Error("s.ListActivity error(%v)", err)
  142. return
  143. }
  144. if len(acs) == 0 {
  145. err = fmt.Errorf("activity(%s) not exist", newAc.Name)
  146. return
  147. }
  148. old := acs[0]
  149. // 报名标准
  150. signUpStr := "signed_start=VALUES(signed_start),signed_end=VALUES(signed_end),sign_up=VALUES(sign_up),sign_up_start=VALUES(sign_up_start)"
  151. // 中奖标准
  152. winStr := "object=VALUES(object),upload_start=VALUES(upload_start),upload_end=VALUES(upload_end),win_type=VALUES(win_type),require_items=VALUES(require_items),require_value=VALUES(require_value),statistics_start=VALUES(statistics_start),statistics_end=VALUES(statistics_end)"
  153. // 奖金设置
  154. bonusStr := "bonus_type=VALUES(bonus_type),bonus_time=VALUES(bonus_time)"
  155. // 进展同步
  156. progressStr := "progress_frequency=VALUES(progress_frequency),update_page=VALUES(update_page),progress_start=VALUES(progress_start),progress_end=VALUES(progress_end),progress_sync=VALUES(progress_sync)"
  157. // 开奖查询
  158. openBonusStr := "bonus_query=VALUES(bonus_query),bonus_query_start=VALUES(bonus_query_start),bonus_query_end=VALUES(bonus_query_end)"
  159. // others
  160. otherStr := "background=VALUES(background),win_desc=VALUES(win_desc),unwin_desc=VALUES(unwin_desc),details=VALUES(details)"
  161. var (
  162. update = ""
  163. updateBonus = false
  164. now = xtime.Time(time.Now().Unix())
  165. )
  166. switch {
  167. case now < old.SignUpStart:
  168. // 报名未时间开始
  169. update = fmt.Sprintf("%s,%s,%s,%s,%s,%s,sign_up_end=VALUES(sign_up_end)", signUpStr, winStr, bonusStr, progressStr, openBonusStr, otherStr)
  170. updateBonus = true
  171. case now >= old.SignUpStart && now <= old.SignUpEnd && now < old.ProgressStart:
  172. // 报名已开始未结束,进展同步未开始
  173. if !checkSignUp(old, newAc) || !checkWin(old, newAc) || !checkBonus(old, newAc) {
  174. err = fmt.Errorf("报名已开始,无法修改报名、中奖、奖金相关内容,请检查修改项")
  175. return
  176. }
  177. update = fmt.Sprintf("sign_up_end=VALUES(sign_up_end),%s,%s,%s", progressStr, openBonusStr, otherStr)
  178. case now > old.SignUpEnd && now >= old.ProgressStart && now <= old.ProgressEnd:
  179. // 报名已结束,进展同步开始未结束
  180. if !checkSignUp(old, newAc) || !checkWin(old, newAc) || !checkBonus(old, newAc) || !checkProgress(old, newAc) {
  181. err = fmt.Errorf("报名已结束,进展同步开始未结束,无法修改报名、中奖、奖金、进展相关内容,请检查修改项")
  182. return
  183. }
  184. update = fmt.Sprintf("progress_end=VALUES(progress_end),%s,%s", openBonusStr, otherStr)
  185. case now > old.ProgressEnd && now < old.BonusQueryEnd:
  186. // 进展同步已结束,开奖查询未结束
  187. if !checkSignUp(old, newAc) || !checkWin(old, newAc) || !checkBonus(old, newAc) || !checkProgress(old, newAc) || !checkOpenBonus(old, newAc) || old.ProgressEnd != newAc.ProgressEnd {
  188. err = fmt.Errorf("进展同步已结束,开奖查询未结束,无法修改报名、中奖、奖金、进展、开奖相关内容,请检查修改项")
  189. return
  190. }
  191. update = fmt.Sprintf("bonus_query_end=VALUES(bonus_query_end),%s", otherStr)
  192. default:
  193. err = fmt.Errorf("不符合任何修改时间段,没有任何修改")
  194. return
  195. }
  196. update = fmt.Sprintf("ON DUPLICATE KEY UPDATE %s", update)
  197. err = s.insertActivity(c, newAc, update, updateBonus)
  198. return
  199. }
  200. func (s *Service) getActivityBonus(c context.Context, ids []int64) (bm map[int64][]int64, err error) {
  201. bm = make(map[int64][]int64)
  202. bonus, err := s.dao.GetActivityBonus(c, ids)
  203. if err != nil {
  204. return
  205. }
  206. sort.Slice(bonus, func(i, j int) bool {
  207. return bonus[i].Rank < bonus[j].Rank
  208. })
  209. for i := 0; i < len(bonus); i++ {
  210. id := bonus[i].ID
  211. if _, ok := bm[id]; !ok {
  212. bm[id] = make([]int64, 0)
  213. }
  214. bm[id] = append(bm[id], bonus[i].Money)
  215. }
  216. return
  217. }
  218. func (s *Service) insertActivity(c context.Context, ac *model.CActivity, updateVal string, updateBonus bool) (err error) {
  219. tx, err := s.dao.BeginTran(c)
  220. if err != nil {
  221. log.Error("s.dao.BeginTran error(%v)", err)
  222. return
  223. }
  224. // insert activity
  225. if _, err = s.dao.TxInsertActivity(tx, ac, updateVal); err != nil {
  226. log.Error("s.dao.TxInsertActivity error(%v)", err)
  227. return
  228. }
  229. id, err := s.dao.TxGetActivityByName(tx, ac.Name)
  230. if err != nil {
  231. log.Error("s.dao.GetActivityByName error(%v)", err)
  232. return
  233. }
  234. // is update bonus
  235. if updateBonus && len(ac.BonusMoney) > 0 {
  236. bonus := make([]*model.BonusRank, 0)
  237. if ac.WinType == 1 {
  238. bonus = append(bonus, &model.BonusRank{ID: id, Rank: 0, Money: ac.BonusMoney[0]})
  239. } else if ac.WinType == 2 {
  240. for i := 0; i < len(ac.BonusMoney); i++ {
  241. bonus = append(bonus, &model.BonusRank{ID: id, Rank: i + 1, Money: ac.BonusMoney[i]})
  242. }
  243. }
  244. // insert bonus money
  245. if err = s.txInsertActivityBonus(tx, bonus); err != nil {
  246. log.Error("s.TxInsertBonusRank error(%v)", err)
  247. return
  248. }
  249. }
  250. if err = tx.Commit(); err != nil {
  251. log.Error("tx.Commit error")
  252. }
  253. return
  254. }
  255. func (s *Service) txInsertActivityBonus(tx *sql.Tx, bonus []*model.BonusRank) (err error) {
  256. var buf bytes.Buffer
  257. for _, row := range bonus {
  258. buf.WriteString("(")
  259. buf.WriteString(strconv.FormatInt(row.ID, 10))
  260. buf.WriteByte(',')
  261. buf.WriteString(strconv.Itoa(row.Rank))
  262. buf.WriteByte(',')
  263. buf.WriteString(strconv.FormatInt(row.Money, 10))
  264. buf.WriteString(")")
  265. buf.WriteByte(',')
  266. }
  267. if buf.Len() > 0 {
  268. buf.Truncate(buf.Len() - 1)
  269. }
  270. vals := buf.String()
  271. buf.Reset()
  272. _, err = s.dao.TxInsertActivityBonusBatch(tx, vals)
  273. return
  274. }
  275. // ListActivitySignUp list activity who sign up
  276. func (s *Service) ListActivitySignUp(c context.Context, activityID int64, from, limit int) (ups []*model.UpActivity, total int, err error) {
  277. total, err = s.dao.UpActivityStateCount(c, activityID, []int64{1, 2, 3})
  278. if err != nil {
  279. log.Error("s.dao.UpActivityStateCount error(%v)", err)
  280. return
  281. }
  282. ups, err = s.dao.ListUpActivity(c, activityID, from, limit)
  283. if err != nil {
  284. log.Error("s.dao.ListUpActivity error(%v)", err)
  285. }
  286. return
  287. }
  288. // ListActivityWinners list activity winners
  289. func (s *Service) ListActivityWinners(c context.Context, activityID, mid int64, from, limit int) (ups []*model.UpActivity, total int, err error) {
  290. total, err = s.dao.UpActivityStateCount(c, activityID, []int64{2, 3})
  291. if err != nil {
  292. log.Error("s.dao.UpActivityStateCount error(%v)", err)
  293. return
  294. }
  295. ups, err = s.dao.ListUpActivitySuccess(c, activityID, mid, from, limit)
  296. if err != nil {
  297. log.Error("s.dao.ListUpActivity error(%v)", err)
  298. return
  299. }
  300. if mid != 0 {
  301. total = len(ups)
  302. }
  303. return
  304. }
  305. // ActivityAward activity award
  306. func (s *Service) ActivityAward(c context.Context, activityID int64, activityName string, date, statisticsEnd xtime.Time, creator string) (err error) {
  307. if xtime.Time(time.Now().Unix()) <= statisticsEnd {
  308. err = fmt.Errorf("统计阶段未结束,不能发奖")
  309. return
  310. }
  311. ups, err := s.listUpActivity(c, activityID)
  312. if err != nil {
  313. log.Error("s.listUpActivity error(%v)", err)
  314. return
  315. }
  316. if len(ups) == 0 {
  317. return
  318. }
  319. rankMID := make(map[int][]int64)
  320. rankMoney := make(map[int]int64)
  321. for _, up := range ups {
  322. if up.State != 2 {
  323. continue
  324. }
  325. rank := up.Rank
  326. rankMoney[rank] = up.Bonus
  327. if _, ok := rankMID[rank]; !ok {
  328. rankMID[rank] = make([]int64, 0)
  329. }
  330. rankMID[rank] = append(rankMID[rank], up.MID)
  331. }
  332. // insert to tag
  333. tx, err := s.dao.BeginTran(c)
  334. if err != nil {
  335. log.Error("s.dao.BeginTran error(%v)", err)
  336. return
  337. }
  338. for rank, money := range rankMoney {
  339. mids, ok := rankMID[rank]
  340. if !ok || len(mids) == 0 {
  341. continue
  342. }
  343. tagName := fmt.Sprintf("act-%s-%d", activityName, rank)
  344. err = s.addActivityUpTag(tx, money, creator, tagName, mids, date)
  345. if err != nil {
  346. log.Error("s.addActivityUpTag error(%v)", err)
  347. return
  348. }
  349. // update mids state
  350. if _, err = s.dao.TxUpdateUpActivityState(tx, activityID, mids, 2, 3); err != nil {
  351. tx.Rollback()
  352. log.Error("s.dao.TxUpdateUpActivityState error(%v)", err)
  353. return
  354. }
  355. }
  356. if err = tx.Commit(); err != nil {
  357. log.Error("tx.Commit error(%v)", err)
  358. }
  359. return
  360. }
  361. func (s *Service) addActivityUpTag(tx *sql.Tx, money int64, creator, tagName string, mids []int64, date xtime.Time) (err error) {
  362. tag := &model.TagInfo{
  363. Tag: tagName,
  364. Creator: creator,
  365. Dimension: 1,
  366. StartTime: date,
  367. EndTime: date,
  368. AdjustType: 1,
  369. Ratio: int(money),
  370. UploadStartTime: date,
  371. UploadEndTime: date,
  372. }
  373. if _, err = s.dao.TxInsertTag(tx, tag); err != nil {
  374. tx.Rollback()
  375. log.Error("s.dao.TxInsertTag error(%v)", err)
  376. return
  377. }
  378. tagID, err := s.dao.TxGetTagInfoByName(tx, tagName, 1, 0, 0)
  379. if err != nil {
  380. tx.Rollback()
  381. log.Error("s.dao.TxGetTagInfoByName error(%v)", err)
  382. return
  383. }
  384. for _, mid := range mids {
  385. _, err = s.dao.TxInsertTagUpInfo(tx, tagID, mid, 0)
  386. if err != nil {
  387. tx.Rollback()
  388. log.Error("s.dao.TxInsertTagUpInfo error(%v)", err)
  389. return
  390. }
  391. }
  392. return
  393. }
  394. func (s *Service) listUpActivity(c context.Context, activityID int64) (ups []*model.UpActivity, err error) {
  395. from, limit := 0, 2000
  396. ups = make([]*model.UpActivity, 0)
  397. for {
  398. var up []*model.UpActivity
  399. up, err = s.dao.ListUpActivity(c, activityID, from, limit)
  400. if err != nil {
  401. return
  402. }
  403. ups = append(ups, up...)
  404. if len(up) < limit {
  405. break
  406. }
  407. from += limit
  408. }
  409. return
  410. }