sendincome.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. package service
  2. import (
  3. "context"
  4. "encoding/csv"
  5. "fmt"
  6. "io"
  7. "os"
  8. "sort"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "go-common/app/job/main/growup/model"
  13. "go-common/library/log"
  14. )
  15. const (
  16. _income = "%d年%d月%d日收入统计"
  17. )
  18. func (s *Service) execIncome(c context.Context, date time.Time) (body string, err error) {
  19. upInfo, err := s.getUpIncome(c, date)
  20. if err != nil {
  21. log.Error("s.execIncome s.getUpIncome error(%v)", err)
  22. return
  23. }
  24. avInfo, err := s.getAvIncome(c, date)
  25. if err != nil {
  26. log.Error("s.execIncome s.getAvIncome error(%v)", err)
  27. return
  28. }
  29. totalIncome, err := s.getTotalIncome(c)
  30. if err != nil {
  31. log.Error("s.execIncome s.getTotalIncome error(%v)", err)
  32. return
  33. }
  34. var income, avgUpIncome, avgAVIncome, upCnt int64
  35. for _, up := range upInfo {
  36. income += up.Income
  37. upCnt++
  38. }
  39. if upCnt > 0 {
  40. avgUpIncome = income / upCnt // avg up income
  41. }
  42. if len(avInfo) > 0 {
  43. avgAVIncome = income / int64(len(avInfo)) // avg av income
  44. }
  45. midAVIncome := getMIDAVIncome(avInfo)
  46. midUpIncome := getMIDUpIncome(upInfo)
  47. data := [][]string{
  48. {fmt.Sprintf(_income, date.Year(), date.Month(), date.Day())},
  49. {"日期", "新增收入(元)", "累计收入(元)", "获得收入UP数", "UP平均收入(元)", "UP收入中位数(元)", "获得收入稿件数", "稿件平均收入(元)", "稿件收入中位数(元)"},
  50. {fmt.Sprintf("%d-%d-%d", date.Year(), date.Month(), date.Day()), strconv.FormatFloat(float64(income)/100, 'f', 2, 32), strconv.FormatFloat(float64(totalIncome)/100, 'f', 2, 32), strconv.FormatInt(upCnt, 10), strconv.FormatFloat(float64(avgUpIncome)/100, 'f', 2, 32), strconv.FormatFloat(float64(midUpIncome)/100, 'f', 2, 32), strconv.Itoa(len(avInfo)), strconv.FormatFloat(float64(avgAVIncome)/100, 'f', 2, 32), strconv.FormatFloat(float64(midAVIncome)/100, 'f', 2, 32)},
  51. }
  52. f, err := os.Create("upincome.csv")
  53. if err != nil {
  54. log.Error("growup-job create upincome.csv error(%v)", err)
  55. return
  56. }
  57. defer f.Close()
  58. w := csv.NewWriter(f)
  59. w.WriteAll(data)
  60. w.Flush()
  61. rfile, err := os.Open("upincome.csv")
  62. if err != nil {
  63. log.Error("growup-job open upincome.csv error(%v)", err)
  64. return
  65. }
  66. defer rfile.Close()
  67. r := csv.NewReader(rfile)
  68. for {
  69. var strs []string
  70. strs, err = r.Read()
  71. if err == io.EOF {
  72. break
  73. }
  74. body += fmt.Sprintf("<tr><td>%s</td></tr>", strings.Join(strs, "</td><td>"))
  75. }
  76. err = os.Remove("upincome.csv")
  77. if err != nil {
  78. log.Error("growup-job s.execIncome remove upincome.csv error(%v)", err)
  79. }
  80. return
  81. }
  82. func (s *Service) getTotalIncome(c context.Context) (totalIncome int64, err error) {
  83. var (
  84. totalInfos, infos []*model.MIDInfo
  85. from, limit int64
  86. )
  87. limit = 2000
  88. for {
  89. infos, err = s.dao.GetUpTotalIncome(c, from, limit)
  90. if err != nil {
  91. log.Error("s.getTotalIncome email.GetUpTotalIncome error(%v)", err)
  92. return
  93. }
  94. totalInfos = append(totalInfos, infos...)
  95. if int64(len(infos)) < limit {
  96. break
  97. }
  98. from = infos[len(infos)-1].ID
  99. }
  100. for _, v := range totalInfos {
  101. if v.IsDeleted == 0 {
  102. totalIncome += v.TotalIncome
  103. }
  104. }
  105. return
  106. }
  107. func (s *Service) getUpIncome(c context.Context, date time.Time) (totalInfos []*model.MIDInfo, err error) {
  108. var (
  109. infos []*model.MIDInfo
  110. from, limit int64
  111. )
  112. limit = 2000
  113. for {
  114. infos, err = s.dao.GetUpIncome(c, date, from, limit)
  115. if err != nil {
  116. log.Error("s.getUpIncome dao.GetUpIncome error(%v)", err)
  117. return
  118. }
  119. totalInfos = append(totalInfos, infos...)
  120. if int64(len(infos)) < limit {
  121. break
  122. }
  123. from = infos[len(infos)-1].ID
  124. }
  125. return
  126. }
  127. func (s *Service) getAvIncome(c context.Context, date time.Time) (totalInfos []*model.IncomeInfo, err error) {
  128. var (
  129. infos []*model.IncomeInfo
  130. from, limit int64
  131. )
  132. limit = 3000
  133. for {
  134. infos, err = s.dao.GetAvIncome(c, date, from, limit)
  135. if err != nil {
  136. log.Error("s.getAvIncome dao.GetAvIncome error(%v)", err)
  137. return
  138. }
  139. for _, i := range infos {
  140. if i.Income > 0 {
  141. totalInfos = append(totalInfos, i)
  142. }
  143. }
  144. if int64(len(infos)) < limit {
  145. break
  146. }
  147. from = infos[len(infos)-1].ID
  148. }
  149. return
  150. }
  151. func getMIDAVIncome(avs []*model.IncomeInfo) (income int64) {
  152. var cnt = len(avs)
  153. if cnt <= 0 {
  154. return
  155. }
  156. if cnt == 1 {
  157. income = avs[0].Income
  158. return
  159. }
  160. sort.SliceStable(avs, func(i, j int) bool {
  161. return avs[i].Income < avs[j].Income
  162. })
  163. if cnt%2 == 0 {
  164. income = (avs[cnt/2].Income + avs[cnt/2-1].Income) / 2
  165. } else {
  166. income = avs[cnt/2].Income
  167. }
  168. return
  169. }
  170. func getMIDUpIncome(ups []*model.MIDInfo) (income int64) {
  171. var cnt = len(ups)
  172. if cnt == 0 {
  173. return
  174. }
  175. if cnt == 1 {
  176. income = ups[0].Income
  177. return
  178. }
  179. sort.SliceStable(ups, func(i, j int) bool {
  180. return ups[i].Income < ups[j].Income
  181. })
  182. if cnt%2 == 0 {
  183. income = (ups[cnt/2].Income + ups[cnt/2-1].Income) / 2
  184. } else {
  185. income = ups[cnt/2].Income
  186. }
  187. return
  188. }