03_team_achievement.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package quota
  2. import (
  3. "app/commons/core"
  4. "app/commons/model/entity"
  5. "fmt"
  6. "github.com/shopspring/decimal"
  7. "strings"
  8. "time"
  9. )
  10. // todo:团队业绩计算
  11. // 获取指标信息
  12. // 内存中计算完成 一一修改到数据库中
  13. func (s *Service) resetTeamTodayAchievement() error {
  14. err := s.DB().Model(&entity.UserQuota{}).
  15. Where("1=1").
  16. Updates(map[string]interface{}{
  17. "invite_count": 0,
  18. "team_count": 0,
  19. "team_achievement": 0,
  20. "large_region_achievement": 0,
  21. "few_team_achievement": 0,
  22. }).Error
  23. if err != nil {
  24. return err
  25. }
  26. return nil
  27. }
  28. func (s *Service) teamAchievementHandler() error {
  29. // 更新用户缓存 -- 保证PATH为最新
  30. if err := s.RefreshUserMap(); err != nil {
  31. return err
  32. }
  33. userQuotas, err := s.BatchUserQuota(s.DB().Where("1=1"))
  34. if err != nil {
  35. return err
  36. }
  37. userQuotaMap := make(map[int64]*entity.UserQuota)
  38. for _, item := range userQuotas {
  39. item.InviteCount = 0
  40. item.TeamCount = 0
  41. item.TeamAchievement = decimal.Zero
  42. item.LargeRegionUserId = 0
  43. item.LargeRegionAchievement = decimal.Zero
  44. item.FewTeamAchievement = decimal.Zero
  45. userQuotaMap[item.UserId] = item
  46. }
  47. type LargeRegionTeam struct {
  48. LargeRegionUserId int64 `json:"largeRegionUserId" gorm:"default:0;comment:大区用户ID"`
  49. LargeRegionAchievement decimal.Decimal `json:"largeRegionAchievement" gorm:"type:decimal(25,8);default:0;comment:大区业绩"`
  50. }
  51. // 计算数据
  52. for _, quota := range userQuotas {
  53. // 通过USER_ID
  54. // 获取用户信息
  55. user, err := s.UserInfoFromCache(quota.UserId)
  56. if err != nil {
  57. continue
  58. }
  59. // 大区业绩信息 -- 当前
  60. largeRegionTeam := LargeRegionTeam{
  61. LargeRegionUserId: user.Id,
  62. LargeRegionAchievement: quota.TeamAchievement.Add(quota.PersonAchievement),
  63. }
  64. for i, pid := range user.ParentIds {
  65. parentUserQuota, ok := userQuotaMap[pid]
  66. if !ok {
  67. break
  68. }
  69. if i == 0 {
  70. parentUserQuota.InviteCount += 1 // 直推人数
  71. }
  72. parentUserQuota.TeamCount += 1 // 团队人数
  73. parentUserQuota.TeamAchievement = parentUserQuota.TeamAchievement.Add(quota.PersonAchievement) // 团队业绩
  74. // 替换当期大区业绩 -- 如果当前区业绩大于 当期指标最大业绩 则替换
  75. if parentUserQuota.LargeRegionAchievement.LessThanOrEqual(largeRegionTeam.LargeRegionAchievement) {
  76. parentUserQuota.LargeRegionAchievement = largeRegionTeam.LargeRegionAchievement
  77. parentUserQuota.LargeRegionUserId = largeRegionTeam.LargeRegionUserId
  78. }
  79. // 小区业绩 = 总业绩 - 大区业绩
  80. parentUserQuota.FewTeamAchievement = parentUserQuota.TeamAchievement.Sub(parentUserQuota.LargeRegionAchievement)
  81. // 更新当前团队业绩信息 -- 假设为大区
  82. largeRegionTeam = LargeRegionTeam{
  83. LargeRegionUserId: parentUserQuota.UserId,
  84. LargeRegionAchievement: parentUserQuota.TeamAchievement.Add(parentUserQuota.PersonAchievement),
  85. }
  86. }
  87. }
  88. // 使用临时表
  89. err = s.batchUpdateQuotas(userQuotas)
  90. if err != nil {
  91. core.JobLog.Errorf("批量更新失败:%s", err)
  92. return err
  93. }
  94. return nil
  95. }
  96. // 批量更新方法
  97. func (s *Service) batchUpdateQuotas(updates []*entity.UserQuota) error {
  98. // 1. 确保删除已存在的临时表(避免冲突)temp_user_quota_updates
  99. var err error
  100. tempTableName := fmt.Sprintf("user_quota_team_ac_updates_%d", time.Now().Unix())
  101. defer func() {
  102. if err := s.DB().Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", tempTableName)).Error; err != nil {
  103. core.JobLog.Errorf("删除临时表失败: %v", err)
  104. }
  105. }()
  106. createSQL := fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s (
  107. user_id VARCHAR(32),
  108. invite_delta INT,
  109. team_delta INT,
  110. large_region_user_id INT,
  111. large_region_achievement DECIMAL(25,8),
  112. few_team_achievement DECIMAL(25,8),
  113. team_achievement DECIMAL(25,8)
  114. )ENGINE=InnoDB`, tempTableName)
  115. if err := s.DB().Exec(createSQL).Error; err != nil {
  116. return fmt.Errorf("创建临时表失败: %v", err)
  117. }
  118. // 2. 批量插入数据到临时表
  119. batchSize := 1000 // 每批处理1000条
  120. for i := 0; i < len(updates); i += batchSize {
  121. end := i + batchSize
  122. if end > len(updates) {
  123. end = len(updates)
  124. }
  125. batch := updates[i:end]
  126. var valueStrings []string
  127. var valueArgs []interface{}
  128. for _, item := range batch {
  129. valueStrings = append(valueStrings, "(?, ?, ?, ?, ?, ?, ?)")
  130. valueArgs = append(valueArgs,
  131. item.UserId,
  132. item.InviteCount,
  133. item.TeamCount,
  134. item.LargeRegionUserId,
  135. item.LargeRegionAchievement,
  136. item.FewTeamAchievement,
  137. item.TeamAchievement,
  138. )
  139. }
  140. stmt := fmt.Sprintf(
  141. "INSERT INTO %s "+
  142. "(user_id, invite_delta, team_delta, "+
  143. "large_region_user_id,large_region_achievement,few_team_achievement, team_achievement)"+
  144. "VALUES %s", tempTableName,
  145. strings.Join(valueStrings, ","))
  146. if err := s.DB().Exec(stmt, valueArgs...).Error; err != nil {
  147. return fmt.Errorf("批量插入临时表失败: %v", err)
  148. }
  149. }
  150. // 3. 执行JOIN更新
  151. err = s.DB().Exec(fmt.Sprintf(`
  152. UPDATE %s q
  153. JOIN %s t ON q.user_id = t.user_id
  154. SET
  155. q.invite_count = t.invite_delta,
  156. q.team_count = t.team_delta,
  157. q.large_region_user_id = t.large_region_user_id,
  158. q.large_region_achievement = t.large_region_achievement,
  159. q.few_team_achievement = t.few_team_achievement,
  160. q.team_achievement = t.team_achievement
  161. `, entity.NewUserQuota().TableName(), tempTableName)).Error
  162. if err != nil {
  163. return fmt.Errorf("执行批量更新失败: %v", err)
  164. }
  165. return nil
  166. }