ordermonitor.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. package task
  2. import (
  3. "app.yhyue.com/moapp/jybase/common"
  4. "app.yhyue.com/moapp/jybase/date"
  5. "app.yhyue.com/moapp/jybase/go-logger/logger"
  6. "app.yhyue.com/moapp/jybase/redis"
  7. "app.yhyue.com/moapp/message/config"
  8. "app.yhyue.com/moapp/message/db"
  9. "app.yhyue.com/moapp/message/handler/activity"
  10. "context"
  11. "encoding/json"
  12. "fmt"
  13. "github.com/gogf/gf/v2/os/gcfg"
  14. "github.com/gogf/gf/v2/os/gcron"
  15. "github.com/gogf/gf/v2/os/gctx"
  16. "github.com/gogf/gf/v2/os/gtime"
  17. "strings"
  18. "time"
  19. )
  20. const (
  21. TableWinnerInfo2210 = "winner_info_22_10"
  22. Mold1 = "1" // 中奖类型 1:小米智能音响
  23. Mold2 = "2" // 中奖类型 2:ipad
  24. ActivityMode1 = 1 // 双十一
  25. ActivityMode2 = 2 // 双十二
  26. )
  27. var (
  28. flag = false // 是否已经查询到
  29. monitorConfig config.OrderMonitorConfig
  30. ruleWinNumFlag []map[int]struct{}
  31. )
  32. func init() {
  33. // 获取配置信息
  34. monitorConfig = config.OrderMonitorConfig{
  35. DateSpecial: date.FormatDate(&gtime.NewFromStrLayout(gcfg.Instance().MustGet(gctx.New(), "orderMonitor.dateSpecial").String(), "2006-01-02T15:04:05Z").Time, date.Date_Short_Layout),
  36. OpenCron: gcfg.Instance().MustGet(gctx.New(), "orderMonitor.openCron").String(),
  37. SelectCron: gcfg.Instance().MustGet(gctx.New(), "orderMonitor.selectCron").String(),
  38. WinNumberDaily: gcfg.Instance().MustGet(gctx.New(), "orderMonitor.winNumberDaily").Int(),
  39. WinNumbersSpecial: gcfg.Instance().MustGet(gctx.New(), "orderMonitor.winNumbersSpecial").Int(),
  40. Switch: gcfg.Instance().MustGet(gctx.New(), "orderMonitor.switch").Bool(),
  41. ActivityMode: gcfg.Instance().MustGet(gctx.New(), "orderMonitor.activityMode").Int(),
  42. }
  43. rules, _ := gcfg.Instance().MustGet(gctx.New(), "orderMonitor.rules").MarshalJSON()
  44. err := json.Unmarshal(rules, &monitorConfig.Rules)
  45. if err != nil {
  46. panic("加载活动规则配置失败")
  47. }
  48. }
  49. // SelectOrderTask 订单监控
  50. func SelectOrderTask() {
  51. if !monitorConfig.Switch {
  52. logger.Info("订单监控开关未打开,不再启动定时任务")
  53. return
  54. }
  55. // 活动已结束 不再启动定时任务
  56. if time.Now().After(activity.MembershipDay.Ed) {
  57. logger.Info("活动时间已结束,不再启动定时任务")
  58. return
  59. }
  60. var (
  61. err error
  62. ctx = gctx.New()
  63. )
  64. // 订单查询任务
  65. switch monitorConfig.ActivityMode {
  66. case ActivityMode1: // 双十一活动的模式 每天的第多少名
  67. _, err = gcron.Add(ctx, monitorConfig.SelectCron, monitor, "selectJob")
  68. logger.Info("add selectJob 1")
  69. case ActivityMode2: // 活动期间的第多少名
  70. // 初始化待查询的获奖顺序
  71. for i := 0; i < len(monitorConfig.Rules); i++ {
  72. rule := monitorConfig.Rules[i]
  73. tmp := map[int]struct{}{}
  74. for j := 0; j < len(rule.WinNum); j++ {
  75. tmp[rule.WinNum[j]] = struct{}{}
  76. }
  77. ruleWinNumFlag = append(ruleWinNumFlag, tmp)
  78. }
  79. logger.Info("初始化待查询的获奖顺序到内存")
  80. _, err = gcron.Add(ctx, monitorConfig.SelectCron, monitorMode2, "selectJob")
  81. logger.Info("add selectJob 2")
  82. }
  83. if err != nil {
  84. logger.Error("定时任务selectJob添加失败", err)
  85. return
  86. }
  87. if time.Now().Before(activity.MembershipDay.T2) { // 活动未开始
  88. gcron.Stop("selectJob") // 停掉订单查询任务 等后边的定时任务开启
  89. logger.Info("活动还未开始,暂停查询任务 selectJob stop")
  90. }
  91. // 开启定时开启任务
  92. _, err = gcron.Add(ctx, monitorConfig.OpenCron, func(ctx context.Context) {
  93. now := time.Now()
  94. if now.After(activity.MembershipDay.Ed) { // 活动已结束 移除掉任务
  95. logger.Info("活动结束,移除任务")
  96. gcron.Remove("openCronJob")
  97. gcron.Remove("selectJob")
  98. return
  99. }
  100. // 活动时间范围内 开启订单查询的定时任务
  101. _, inTime, _ := activity.MembershipDay.InActivity()
  102. if inTime {
  103. if gcron.Search("selectJob").Status() == gcron.StatusStopped {
  104. flag = false // 重置
  105. gcron.Start("selectJob")
  106. logger.Info("开启 selectJob 任务")
  107. }
  108. }
  109. }, "openCronJob")
  110. if err != nil {
  111. logger.Error("定时任务openCronJob失败", err)
  112. }
  113. logger.Info("openCronJob 启动成功")
  114. }
  115. // 订单监控 双十一 查询活动期间的每天的第多少名
  116. func monitor(ctx context.Context) {
  117. logger.Info("开始本轮订单查询")
  118. _, inTime, _ := activity.MembershipDay.InActivity()
  119. if inTime {
  120. // 如果需要查第111个 日期范围内 特殊日期
  121. if date.NowFormat(date.Date_Short_Layout) == monitorConfig.DateSpecial {
  122. logger.Info(fmt.Sprintf("开始查询第%v个人员", monitorConfig.WinNumbersSpecial))
  123. rs111 := selectOrder(monitorConfig.WinNumbersSpecial)
  124. if rs111 != nil {
  125. logger.Info(fmt.Sprintf("查询到第%v个人员", monitorConfig.WinNumbersSpecial))
  126. saveData := map[string]interface{}{
  127. "phone": rs111["user_phone"],
  128. "userid": rs111["user_id"],
  129. "winnerdate": rs111["pay_time"],
  130. "mold": Mold2,
  131. "createdate": date.NowFormat(date.Date_Full_Layout),
  132. }
  133. if existWinnerInfo() {
  134. logger.Info("当日已存在中奖信息")
  135. flag = true
  136. } else {
  137. if saveWinnerInfo(saveData) {
  138. flag = true
  139. logger.Info("中奖信息保存成功:", saveData)
  140. } else {
  141. logger.Error("中奖信息保存失败:", saveData)
  142. }
  143. }
  144. }
  145. } else {
  146. rs := selectOrder(monitorConfig.WinNumberDaily)
  147. if rs != nil { // 查到了
  148. logger.Info(fmt.Sprintf("查询到第%d个人员", monitorConfig.WinNumberDaily))
  149. data := map[string]interface{}{
  150. "phone": rs["user_phone"],
  151. "userid": rs["user_id"],
  152. "winnerdate": rs["pay_time"],
  153. "mold": Mold1,
  154. "createdate": date.NowFormat(date.Date_Full_Layout),
  155. }
  156. if existWinnerInfo() {
  157. logger.Info("当日已存在中奖信息")
  158. flag = true
  159. } else {
  160. if saveWinnerInfo(data) {
  161. flag = true
  162. logger.Info("中奖信息保存成功:", data)
  163. } else {
  164. logger.Error("中奖信息保存失败:", data)
  165. }
  166. }
  167. }
  168. }
  169. if flag {
  170. logger.Info("今日已查询到 暂停任务")
  171. gcron.Stop("selectJob")
  172. logger.Info("selectJob stop")
  173. }
  174. }
  175. }
  176. // 双十二活动 查询活动期间的第多少名
  177. func monitorMode2(ctx context.Context) {
  178. logger.Info("开始本轮订单查询")
  179. if time.Now().Before(activity.MembershipDay.T2) { // 活动未开始
  180. logger.Info("当前时间不在活动时间范围内")
  181. return
  182. }
  183. needSelect := false // 任务是否需要继续
  184. // 遍历活动抽奖规则
  185. for i := 0; i < len(monitorConfig.Rules); i++ {
  186. rules := monitorConfig.Rules[i]
  187. if len(ruleWinNumFlag[i]) == 0 { // 没有需要查询的中奖顺序
  188. continue
  189. }
  190. // 遍历中奖顺序
  191. for _, num := range rules.WinNum {
  192. if _, ok := ruleWinNumFlag[i][num]; !ok { // 不在待查询的map中
  193. continue
  194. }
  195. rs := selectOrder2(num, rules.Products, rules.PriceLimit, rules.PriceStart, rules.PriceEnd, date.FormatDate(&activity.MembershipDay.T2, date.Date_Full_Layout), date.FormatDate(&activity.MembershipDay.Ed, date.Date_Full_Layout))
  196. if len(rs) == 0 {
  197. break // 如果没有查询到 等待下一轮任务再查询
  198. }
  199. logger.Info(num, "查到")
  200. data := map[string]interface{}{
  201. "phone": rs["user_phone"],
  202. "userid": rs["user_id"],
  203. "winnerdate": rs["pay_time"],
  204. "mold": rules.Mold,
  205. "createdate": date.NowFormat(date.Date_Full_Layout),
  206. "ordercode": rs["order_code"],
  207. }
  208. if existOrderWinnerInfo(common.ObjToString(rs["order_code"])) {
  209. // 从待查找的key中删除
  210. delete(ruleWinNumFlag[i], num)
  211. logger.Info("该订单中奖信息重复保存", data)
  212. } else {
  213. // 存库
  214. if saveWinnerInfo(data) {
  215. logger.Info("保存成功", data)
  216. delete(ruleWinNumFlag[i], num) // 从待查找的key中删除
  217. } else {
  218. logger.Info("保存失败", data)
  219. }
  220. }
  221. }
  222. if len(ruleWinNumFlag[i]) > 0 {
  223. logger.Info(ruleWinNumFlag[i])
  224. needSelect = true // 存在未查询到的 定时任务不用关闭
  225. }
  226. }
  227. if time.Now().After(activity.MembershipDay.Ed) { // 活动已结束
  228. logger.Info("活动已结束")
  229. needSelect = false
  230. }
  231. if !needSelect { // 不用再找了 结束任务
  232. gcron.Remove("selectJob")
  233. gcron.Remove("openCronJob")
  234. logger.Info("结束了")
  235. }
  236. }
  237. // 查订单表
  238. func selectOrder(num int) map[string]interface{} {
  239. sql := `SELECT
  240. order_code,
  241. user_phone,
  242. user_id,
  243. pay_time
  244. FROM
  245. dataexport_order
  246. WHERE order_status = 1 and
  247. product_type IN (
  248. "VIP订阅",
  249. "大会员",
  250. "数据流量包"
  251. )
  252. AND is_backstage_order = 0 and pay_time is not null
  253. AND TO_DAYS(pay_time) = to_days(now())
  254. ORDER BY
  255. pay_time
  256. LIMIT ?,1
  257. `
  258. rs := db.Mysql.SelectBySql(sql, num-1)
  259. if rs != nil && len(*rs) == 1 {
  260. return (*rs)[0]
  261. }
  262. logger.Info("未查到", rs)
  263. return nil
  264. }
  265. // 查询活动期间指定支付顺序的订单
  266. func selectOrder2(num int, productType []string, priceLimit bool, priceStart, priceEnd int, startTime, endTime string) map[string]interface{} {
  267. var products []string
  268. var values []interface{}
  269. productTypeStr := "" // 产品类型
  270. priceLimitStr := "" // 价格限制
  271. values = append(values, startTime, endTime)
  272. // 拼接产品类型
  273. if len(productType) > 0 {
  274. for i := 0; i < len(productType); i++ {
  275. products = append(products, "?")
  276. values = append(values, productType[i])
  277. }
  278. productTypeStr = fmt.Sprintf(" and product_type IN (%s) ", strings.Join(products, ","))
  279. }
  280. // 拼接价格限制
  281. if priceLimit {
  282. if priceStart != 0 {
  283. priceLimitStr = " and pay_money>=? "
  284. values = append(values, priceStart)
  285. }
  286. if priceEnd != 0 {
  287. priceLimitStr += " and pay_money<=? "
  288. values = append(values, priceEnd)
  289. }
  290. }
  291. values = append(values, num-1)
  292. sql := `SELECT
  293. order_code,
  294. user_phone,
  295. user_id,
  296. pay_time
  297. FROM
  298. dataexport_order
  299. WHERE order_status = 1 and pay_time >=? and pay_time<?` + productTypeStr +
  300. priceLimitStr + ` AND is_backstage_order = 0 and pay_time is not null
  301. ORDER BY pay_time LIMIT ?,1`
  302. rs := db.Mysql.SelectBySql(sql, values...)
  303. if rs != nil && len(*rs) == 1 {
  304. return (*rs)[0]
  305. }
  306. logger.Info(num, "未查到", rs)
  307. return nil
  308. }
  309. // 保存中奖人员信息
  310. func saveWinnerInfo(data map[string]interface{}) bool {
  311. // 清缓存
  312. redis.Del(activity.BidderPlanRedis, activity.WinnerInfoKey)
  313. logger.Info("save winner info ")
  314. return db.Mysql.Insert(TableWinnerInfo2210, data) > 0
  315. }
  316. // 当天是否已经保存过中奖信息
  317. func existWinnerInfo() bool {
  318. logger.Info("select winner info ")
  319. return db.Mysql.CountBySql("SELECT count(id) as count FROM jianyu.winner_info_22_10 where TO_DAYS(createdate) = TO_DAYS(NOW());") > 0
  320. }
  321. // 中奖订单号是否已经保存过
  322. func existOrderWinnerInfo(orderCode string) bool {
  323. logger.Info("select order winner info ")
  324. return db.Mysql.CountBySql("SELECT count(id) as count FROM jianyu.winner_info_22_10 where ordercode = ?", orderCode) > 0
  325. }