Browse Source

Merge branch 'master' into feature/v1.5.11

lianbingjie 1 year ago
parent
commit
c830ce4f9d

+ 12 - 0
clueSync/config.go

@@ -26,6 +26,8 @@ type (
 		MarketSaleTime     int64   `json:"marketSaleTime"`
 		AllocationTime     string  `json:"allocationTime"`
 		AllocationRatio    float64 `json:"allocationRatio"`
+		ActiveTime         string  `json:"activeTime"`
+		RebindTime         string  `json:"rebindTime"`
 	}
 	DB struct {
 		CornExp1      int64  `json:"cornexp1"`
@@ -87,6 +89,16 @@ type (
 			MaxIdle     int    `json:"maxidle"`
 			MaxLeftTime int    `json:"maxleft"`
 		} `json:"baseService"`
+		BiService struct {
+			Host        string `json:"host"`
+			Port        int    `json:"port"`
+			Database    string `json:"database"`
+			User        string `json:"user"`
+			Password    string `json:"password"`
+			PollSize    int    `json:"poolsize"`
+			MaxIdle     int    `json:"maxidle"`
+			MaxLeftTime int    `json:"maxleft"`
+		} `json:"biService"`
 		ThirdParty struct {
 			Host        string `json:"host"`
 			Port        int    `json:"port"`

+ 23 - 1
clueSync/config.json

@@ -1 +1,23 @@
-{"lastOrderId":258784,"lastOrderClueId":"2024-05-25 02:23:21","lastUserId":"2024-07-11 13:38:02","lastXcxUserId":"2024-07-10 16:30:03","lastId":"668e2be1d1f99a10cd6416a9","lastOrderTime":"2024-07-10 18:10:33","lastUserTime":"2024-07-10 17:55:03","lastSubscribeId":"668e3ec29a9f357bd3e3da06","lastMessageTime":"2024-07-09 17:24:47","lastkcTime":"","lastEverythingTime":"","lastEventRegTime":"","lastReadClueTime":"","bigSaleTime":1718241923,"bigOrderTime":"2024-06-12 17:01:39","marketSaleTime":1708160200,"allocationTime":"2024-07-01 14:59:37","allocationRatio":2}
+{
+  "lastOrderId": 258784,
+  "lastOrderClueId": "2024-05-25 02:23:21",
+  "lastUserId": "2024-05-20 15:40:02",
+  "lastId": "668c9fdbd1f99a10cd641691",
+  "lastOrderTime": "2023-04-25 00:00:00",
+  "lastUserTime": "2024-07-09 11:54:02",
+  "lastSubscribeId": "645470af172d9e8dcc5c507a",
+  "lastMessageTime": "2024-06-20 17:54:18",
+  "lastkcTime": "",
+  "lastEverythingTime": "",
+  "lastEventRegTime": "",
+  "lastReadClueTime": "",
+  "bigSaleTime": 1718241923,
+  "bigOrderTime": "2024-06-12 17:01:39",
+  "marketSaleTime": 1708160200,
+  "allocationTime": "2024-07-01 14:59:37",
+  "allocationRatio": 2,
+  "lastXcxUserId": "2024-07-09 14:59:37",
+  "activeTime": "2024-07-01 14:59:37",
+  "rebindTime": "2024-07-01 14:59:37"
+}
+

+ 10 - 0
clueSync/db.json

@@ -59,6 +59,16 @@
     "maxidle": 40,
     "maxleft": 40
   },
+  "biService": {
+    "host": "192.168.3.14",
+    "port": 4000,
+    "database": "bi_service",
+    "user": "root",
+    "password": "=PDT49#80Z!RVv52_z",
+    "poolsize": 20,
+    "maxidle": 40,
+    "maxleft": 40
+  },
   "thirdParty": {
     "host": "192.168.3.14",
     "port": 4000,

+ 13 - 4
clueSync/job.go

@@ -90,6 +90,17 @@ func FormatData(data map[string]interface{}, item string) (bool, bool) {
 			}
 
 		}
+	} else if item == "allocation" || item == "rebind" {
+		userId = mongodb.BsonIdToSId(data["mogUserId"])
+		userInfo := TiDb.FindOne("dwd_f_userbase_baseinfo", map[string]interface{}{
+			"userid": userId,
+		}, "", "")
+		if userInfo != nil && len(*userInfo) > 0 {
+			phone = common.ObjToString((*userInfo)["phone"])
+			uId = common.ObjToString((*userInfo)["uid"])
+			source = common.ObjToString((*userInfo)["source"])
+			belong_to = common.ObjToString((*userInfo)["belong_to"])
+		}
 	} else if item == "saleLeads" { //留资
 		userId = common.ObjToString(data["userid"])
 		if !mongodb.IsObjectIdHex(userId) {
@@ -99,7 +110,6 @@ func FormatData(data map[string]interface{}, item string) (bool, bool) {
 				userId = common.ObjToString((*userMapping)["userid"])
 			}
 		}
-
 		cluename = common.ObjToString(data["company"])
 		phone = common.ObjToString(data["phone"])
 		role = common.ObjToString(data["companyType"])
@@ -424,6 +434,7 @@ func FormatData(data map[string]interface{}, item string) (bool, bool) {
 }
 
 func SaveClue(item, userId, uId, top_cluetype, sub_cluetype, topname, subname, cluename, name, saleName, phone, position, department, departments, industry, follow_project_area, role, seatNumber string, positionId int64, source, sourceCode, remark string, keyword []string, belong_to string, isGroup, isCommerce int, isFreeze bool, demand string) bool {
+	log.Println("线索修改前", item, userId, uId, top_cluetype, sub_cluetype, topname, subname, cluename, name, saleName, phone, position, department, departments, industry, follow_project_area, role, seatNumber, positionId, source, sourceCode, remark)
 	nowTime := time.Now().Format("2006-01-02 15:04:05")
 	nowTimes := time.Unix(time.Now().Unix()+3600*12, 0).Format("2006-01-02 15:04:05")
 	clueId, uodateId1, uodateId2, uodateId3, uodateId4, uodateId5, uodateId6 := int64(0), int64(0), int64(0), int64(0), int64(0), int64(0), int64(0)
@@ -794,7 +805,6 @@ func WorkUpdateClue(data map[string]interface{}, saleData []map[string]interface
 			clueUpdateData["comeinsource_open"] = nil
 			clueUpdateData["level_open"] = nil
 			clueUpdateData["clue_level"] = nil
-
 		}
 	} else if is_assign == 1 && positionId != old_position_id {
 		clueUpdateData["seatNumber"] = seatNumber
@@ -875,7 +885,6 @@ func WorkUpdateClue(data map[string]interface{}, saleData []map[string]interface
 		//变更记录
 		if (trailstatus == "00" || old_position_id == 0 || (pIsOk && old_cluename != cluename && cluename != "")) && is_assign == 1 {
 			if trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400 {
-
 			} else if old_position_id == 0 {
 				updateId1 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
 					"clue_id":      clueId,
@@ -1227,8 +1236,8 @@ func WorkUpdateClue(data map[string]interface{}, saleData []map[string]interface
 	}
 }
 func UpdateClue(data map[string]interface{}, saleData []map[string]interface{}, item, userId, uId, top_cluetype, sub_cluetype, topname, subname, cluename, name, saleName, phone, position, department, departments, industry, follow_project_area, role, seatNumber, level string, positionId int64, source, sourceCode, remark string, keyword []string, belong_to string, isGroup, isCommerce int, pIsOk bool) bool {
+	log.Println("线索修改前", data, item, userId, uId, top_cluetype, sub_cluetype, topname, subname, cluename, name, saleName, phone, position, department, departments, industry, follow_project_area, role, seatNumber, level, positionId, source, sourceCode, remark)
 	name = strings.ReplaceAll(name, " ", "")
-	log.Println("线索修改前", data)
 	nowTime := time.Now().Format("2006-01-02 15:04:05")
 	nowTimes := time.Unix(time.Now().Unix()+3600*12, 0).Format("2006-01-02 15:04:05")
 	trailstatus := common.ObjToString(data["trailstatus"]) //data都为原线索数据

+ 131 - 22
clueSync/jobutil.go

@@ -734,28 +734,46 @@ func userbase() {
 						log.Println("userbase uid 注册时间 ", registedates)
 						if time.Now().Unix()-registedates.Unix() > int64(db.RegTimes)*86400 {
 							if count == 0 {
-								// TiDb.Insert("dwd_f_crm_open_sea", map[string]interface{}{
-								// 	"clue_id":      clueId,
-								// 	"comeintime":   nowTime,
-								// 	"comeinsource": 2,
-								// })
-								clueId := TiDb.Insert("dwd_f_crm_clue_info", map[string]interface{}{
-									"userid":            userId,
-									"uid":               uId,
-									"is_assign":         0,
-									"comeintime":        nowTime,
-									"createtime":        nowTime,
-									"updatetime":        nowTime,
-									"cluename":          phone,
-									"top_cluetype":      "532",
-									"sub_cluetype":      "475",
-									"trailstatus":       "01",
-									"name":              name,
-									"phone":             phone,
-									"comeintime_open":   nowTime,
-									"comeinsource_open": 1,
-									"FREEZE_TIME":       nowTime,
-								})
+								clueId := int64(0)
+								sql := fmt.Sprintf(`select * from freeClubSign where mogUserId="%s" and sub_again_date > "%s" `, userId, selectTimeEnd)
+								data := BiService.SelectBySql(sql)
+								if len(*data) > 0 && userId != "" {
+									clueId = TiDb.Insert("dwd_f_crm_clue_info", map[string]interface{}{
+										"userid":            userId,
+										"uid":               uId,
+										"is_assign":         0,
+										"comeintime":        nowTime,
+										"createtime":        nowTime,
+										"updatetime":        nowTime,
+										"cluename":          phone,
+										"top_cluetype":      "532",
+										"sub_cluetype":      "670",
+										"trailstatus":       "01",
+										"name":              name,
+										"phone":             phone,
+										"comeintime_open":   nowTime,
+										"comeinsource_open": 1,
+										"FREEZE_TIME":       nowTime,
+									})
+								} else {
+									clueId = TiDb.Insert("dwd_f_crm_clue_info", map[string]interface{}{
+										"userid":            userId,
+										"uid":               uId,
+										"is_assign":         0,
+										"comeintime":        nowTime,
+										"createtime":        nowTime,
+										"updatetime":        nowTime,
+										"cluename":          phone,
+										"top_cluetype":      "532",
+										"sub_cluetype":      "475",
+										"trailstatus":       "01",
+										"name":              name,
+										"phone":             phone,
+										"comeintime_open":   nowTime,
+										"comeinsource_open": 1,
+										"FREEZE_TIME":       nowTime,
+									})
+								}
 								if clueId > 0 {
 									TiDb.Insert("dwd_f_userbase_contacts", map[string]interface{}{
 										"status":      1,
@@ -948,6 +966,32 @@ func getClueType(item string, data map[string]interface{}, sourceCode string, so
 				}
 			}
 		}
+	} else if item == "allocation" {
+		pcode = "532"
+		code = "671"
+		level = "C"
+		pcodeData := TiDb.FindOne("dwd_d_crm_cluetype_code", map[string]interface{}{"code": pcode}, "", "")
+		if pcodeData != nil && len(*pcodeData) > 0 {
+			topname = common.ObjToString((*pcodeData)["name"])
+		}
+		pcodeData = TiDb.FindOne("dwd_d_crm_cluetype_code", map[string]interface{}{"code": code}, "", "")
+		if pcodeData != nil && len(*pcodeData) > 0 {
+			subname = common.ObjToString((*pcodeData)["name"])
+		}
+	} else if item == "rebind" {
+		pcode = "532"
+		code = "670"
+		level = "C"
+		pcodeData := TiDb.FindOne("dwd_d_crm_cluetype_code", map[string]interface{}{"code": pcode}, "", "")
+		if pcodeData != nil && len(*pcodeData) > 0 {
+
+			topname = common.ObjToString((*pcodeData)["name"])
+
+		}
+		pcodeData = TiDb.FindOne("dwd_d_crm_cluetype_code", map[string]interface{}{"code": code}, "", "")
+		if pcodeData != nil && len(*pcodeData) > 0 {
+			subname = common.ObjToString((*pcodeData)["name"])
+		}
 	} else {
 		if sourceCode != "" {
 			codeData := TiDb.FindOne("dwd_d_crm_cluetype_code", map[string]interface{}{"source": sourceCode}, "", "")
@@ -1238,3 +1282,68 @@ func getSeatNumberPositionId(seatNumber string) (positionId int64) {
 	}
 	return
 }
+
+// 重新关注用户处理
+func rebind() {
+	log.Println("重新关注用户处理开始")
+	//判断节假日
+	runOk := getRunOk()
+	if !runOk {
+		log.Println("不是工作日,任务暂停")
+		return
+	}
+	rebindTimeEnd := cfg.RebindTime
+	sql := fmt.Sprintf(`select * from freeClubSign where sub_again_date > "%s" order by  sub_again_date asc`, rebindTimeEnd)
+	data := BiService.SelectBySql(sql)
+	if data != nil && *data != nil && len(*data) > 0 {
+		for _, v := range *data {
+			rebindTimeEnd = common.ObjToString(v["sub_again_date"])
+			registedates, _ := time.Parse(date.Date_Full_Layout, gconv.String(v["register_time"]))
+			if time.Now().Unix()-registedates.Unix() > int64(db.RegTimes)*86400 {
+				ok1, ok2 := FormatData(v, "rebind")
+				if !ok1 {
+					log.Println("线索卡点", "allocation", v, rebindTimeEnd)
+				} else {
+					if !ok2 {
+						log.Println("用户分配已达上限", "allocation", v, rebindTimeEnd)
+					}
+				}
+			}
+		}
+		cfg.RebindTime = rebindTimeEnd
+		common.WriteSysConfig(&cfg)
+	}
+	log.Println("重新关注用户处理结束")
+}
+
+// 活跃用户处理
+func activeUsers() {
+	log.Println("活跃用户处理开始")
+	//判断节假日
+	runOk := getRunOk()
+	if !runOk {
+		log.Println("不是工作日,任务暂停")
+		return
+	}
+	//活跃用户查询
+	activeTimeEnd := cfg.ActiveTime
+	sql := fmt.Sprintf(`select * from freeClubSign where act_again_date > "%s" order by  act_again_date asc`, activeTimeEnd)
+	data := BiService.SelectBySql(sql)
+	if data != nil && *data != nil && len(*data) > 0 {
+		for _, v := range *data {
+			activeTimeEnd = common.ObjToString(v["act_again_date"])
+			ok1, ok2 := FormatData(v, "allocation")
+			log.Println(v, "allocation", ok1, ok2)
+			if !ok1 {
+				log.Println("线索卡点", "allocation", v, activeTimeEnd)
+			} else {
+				if !ok2 {
+					log.Println("用户分配已达上限", "allocation", v, activeTimeEnd)
+				}
+			}
+		}
+		cfg.ActiveTime = activeTimeEnd
+		common.WriteSysConfig(&cfg)
+	}
+	log.Println("活跃用户处理结束")
+}

+ 1 - 1
clueSync/kc.go

@@ -289,7 +289,7 @@ func kcJob(data map[string]interface{}) int {
 }
 
 func cAutoDraw(entId int) (positionId int64, name string) {
-	query := `SELECT name,position_id FROM dwd_d_crm_department_level_succbi WHERE bi_pcode = (SELECT bi_code FROM dwd_d_crm_department_level_succbi WHERE name = "客户成功组") and resign = 0`
+	query := `SELECT name,position_id FROM dwd_d_crm_department_level_succbi WHERE bi_pcode = (SELECT bi_code FROM dwd_d_crm_department_level_succbi WHERE name = "客户成功组" and resign=0) and resign = 0`
 	data := TiDb.SelectBySql(query)
 	if data != nil && len(*data) > 0 {
 		if entId > 0 {

+ 21 - 5
clueSync/main.go

@@ -24,6 +24,7 @@ var (
 	ThirdParty         *mysql.Mysql
 	Jyactivities       *mysql.Mysql
 	Base               *mysql.Mysql
+	BiService          *mysql.Mysql
 	Es                 elastic.Es
 	Mgo                *mongodb.MongodbSim
 	MgoLog             *mongodb.MongodbSim
@@ -110,6 +111,15 @@ func main() {
 		MaxIdleConns: db.BaseService.MaxIdle,
 	}
 	Base.Init()
+	BiService = &mysql.Mysql{
+		Address:      db.BiService.Host + ":" + fmt.Sprint(db.BiService.Port),
+		UserName:     db.BiService.User,
+		PassWord:     db.BiService.Password,
+		DBName:       db.BiService.Database,
+		MaxOpenConns: db.BiService.PollSize,
+		MaxIdleConns: db.BiService.MaxIdle,
+	}
+	BiService.Init()
 	Es = elastic.NewEs(db.Es.Version, db.Es.Address, db.Es.DbSize, db.Es.UserName, db.Es.Password)
 	redis.InitRedis(db.RedisServer)
 	Mgo = mongodb.NewMgo(db.Mgo.Address, db.Mgo.DbName, db.Mgo.DbSize)
@@ -117,26 +127,30 @@ func main() {
 	MgoQyxy = mongodb.NewMgoWithUser(db.MgoQyxy.Address, db.MgoQyxy.DbName, db.MgoQyxy.User, db.MgoQyxy.Password, db.MgoQyxy.DbSize)
 	InitArea()
 	InitProduct(db.ProductArr)
+	//activeUsers() //取关重新关注处理
 	if *mode == 1 {
 		//30分钟一次
-		go p.VarTimeTask.RunInTimeSection("30分钟定时任务", startTime, endTime, db.CornExp1, func(dayFirst bool) {
+		go p.VarTimeTask.RunInTimeLoop("30分钟定时任务", "", "", db.CornExp1, true, true, nil, func() {
 			orders()      //未支付订单
 			messageSync() //聊天记录进线索
 			userbase()    //新绑定手机号进线索
 		})
 		//5分钟一次
+
 		go p.VarTimeTask.RunInTimeSection("5分钟定时任务1", db.CornExp2Start, db.CornExp2End, db.CornExp2, func(dayFirst bool) {
 			users()          //新注册用户进线索
 			saleLeads()      //留资进线索
 			eventReg()       //渠道
 			bigCustomer()    //大客户线索
 			marketCustomer() //市场部线索
+			rebind()         //取关重新关注处理
 		})
 		//每天8点30
 		c := cron.New()
 		c.AddFunc(db.CornExp3, func() {
-			users()     //新注册用户进线索
-			saleLeads() //留资进线索
+			users()       //新注册用户进线索
+			saleLeads()   //留资进线索
+			activeUsers() //活跃用户处理
 		})
 		c.Start()
 		// 一天一次
@@ -148,7 +162,8 @@ func main() {
 		d.Start()
 		// 5分钟一次
 		go ordersClue() //后台订单进线索
-		go p.VarTimeTask.RunInTimeSection("5分钟定时任务2", startTime, endTime, db.CornExp5, func(dayFirst bool) {
+		go p.VarTimeTask.RunInTimeLoop("5分钟定时任务2", "", "", db.CornExp5, true, true, nil, func() {
+			//go p.VarTimeTask.RunInTimeSection("5分钟定时任务2", startTime, endTime, db.CornExp5, func(dayFirst bool) {
 			everythingSync()   //渠道
 			ordersClue()       //后台订单进线索
 			kcSync()           //移交客成
@@ -160,7 +175,8 @@ func main() {
 			rderAcceptance()   //工单生成
 		})
 		//5分钟一次
-		go p.VarTimeTask.RunInTimeSection("5分钟定时任务3", startTime, endTime, db.CornExp6, func(dayFirst bool) {
+		go p.VarTimeTask.RunInTimeLoop("5分钟定时任务3", "", "", db.CornExp6, true, true, nil, func() {
+			//go p.VarTimeTask.RunInTimeSection("5分钟定时任务3", startTime, endTime, db.CornExp6, func(dayFirst bool) {
 			subscribeAddSync() //订阅增量
 			rderAcceptance()   //工单生成
 		})

+ 20 - 4
doFreeClueSign/config.yaml

@@ -1,22 +1,38 @@
 mongodb:
-  default:
+  default: #qfw
     address: "192.168.3.149:27180"
     size: 5
     dbName: qfw
     replSet: ""
     userName: ""
     password: ""
-  log:
-    address: "192.168.3.206:27090"
+  log: #日志库
+    address: "192.168.3.149:27190"
     size: 5
     dbName: "qfw"
     replSet: ""
     userName: "admin"
     password: "123456"
 
+logger:
+  level: "all"
+  path: "logs" # 日志文件路径。默认为空,表示关闭,仅输出到终端
+  file: "{Y-m-d}.log" # 日志文件格式。默认为"{Y-m-d}.log"
+
 database:
   default:
     link: "mysql:root:=PDT49#80Z!RVv52_z@tcp(192.168.3.14:4000)/debris_product"
     debug: true
+  bi_service:
+    link: "mysql:root:=PDT49#80Z!RVv52_z@tcp(192.168.3.14:4000)/bi_service"
+    debug: true
+  subjectdb: #正式环境库名为Jianyu_subjectdb
+    link: "mysql:readuser:jyTi_R202403@tcp(192.168.3.71:4003)/jianyu_subjectdb_test"
+    debug: true
+  useranaly:
+    link: "mysql:root:=PDT49#80Z!RVv52_z@tcp(192.168.3.14:4000)/useranaly"
+    debug: true
 
-runCron: "# 0 2 * * *" #每天凌晨2点执行
+cron:
+  activityUser: "*/10 * * * * *" #更新新活跃用户
+  bindPhoneAndSubAgain: "*/10 * * * * *" #再次关注&绑定手机号用户

+ 5 - 2
doFreeClueSign/go.mod

@@ -4,6 +4,7 @@ go 1.20
 
 require (
 	app.yhyue.com/moapp/jybase v0.0.0-20240626030750-115a3c0929fb
+	github.com/gogf/gf/contrib/drivers/mysql/v2 v2.7.2
 	github.com/gogf/gf/v2 v2.7.2
 )
 
@@ -13,8 +14,9 @@ require (
 	github.com/emirpasic/gods v1.18.1 // indirect
 	github.com/fatih/color v1.16.0 // indirect
 	github.com/fsnotify/fsnotify v1.7.0 // indirect
-	github.com/go-logr/logr v1.2.3 // indirect
+	github.com/go-logr/logr v1.2.4 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/go-sql-driver/mysql v1.7.1 // indirect
 	github.com/go-stack/stack v1.8.0 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
 	github.com/gorilla/websocket v1.5.1 // indirect
@@ -23,9 +25,10 @@ require (
 	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
-	github.com/mattn/go-runewidth v0.0.9 // indirect
+	github.com/mattn/go-runewidth v0.0.15 // indirect
 	github.com/olekukonko/tablewriter v0.0.5 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
+	github.com/rivo/uniseg v0.4.4 // indirect
 	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
 	github.com/xdg-go/scram v1.0.2 // indirect
 	github.com/xdg-go/stringprep v1.0.2 // indirect

+ 11 - 3
doFreeClueSign/go.sum

@@ -63,15 +63,19 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
-github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
+github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogf/gf/contrib/drivers/mysql/v2 v2.7.2 h1:GpE2JuHVoNJD4lNP1omC1+TKXNCSvXr5oil1bNULYd0=
+github.com/gogf/gf/contrib/drivers/mysql/v2 v2.7.2/go.mod h1:0h3UmNAmA8hnjvTyozZelSWWxiAjGDQttzZqMhkCkJo=
 github.com/gogf/gf/v2 v2.7.2 h1:uZDfyblasI12lZUtFd1mfxsIr8b14cd/F88DJUTCSDM=
 github.com/gogf/gf/v2 v2.7.2/go.mod h1:EBXneAg/wes86rfeh68XC0a2JBNQylmT7Sp6/8Axk88=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -153,8 +157,9 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
 github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -190,6 +195,9 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=

+ 83 - 0
doFreeClueSign/job/job.go

@@ -0,0 +1,83 @@
+package job
+
+import (
+	"context"
+	"doFreeClueSign/public"
+	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/util/gconv"
+	"time"
+)
+
+// LoadActivityUser 加载新活跃用户
+func (jm *JobManager) LoadActivityUser() {
+	var (
+		ctx = context.TODO()
+	)
+	start, _ := time.ParseInLocation(time.DateTime, jm.lastRun.NewActivity, time.Local)
+	val, ed := public.GetNewActiveUser(start)
+	if len(val) > 0 {
+		for i, msg := range val {
+			if i%10 == 0 {
+				g.Log().Infof(ctx, "JobManager.LoadActivityUser %d/%d", i, len(val))
+			}
+			if err := jm.FilterPayUserAndSaveDb(ctx, msg); err != nil {
+				g.Log().Errorf(ctx, "JobManager.LoadActivityUser.FilterPayUserAndSaveDb %v", gconv.String(msg))
+			}
+		}
+	}
+	//更新
+	jm.lastRun.NewActivity = ed.Format(time.DateTime)
+	if err := jm.SaveLastRun(); err != nil {
+		g.Log().Errorf(ctx, "LoadActivityUser error %v", err)
+	}
+}
+
+// LoadBindPhoneUser 加载绑定手机号用户
+func (jm *JobManager) LoadBindPhoneUser() {
+	var (
+		runNow = time.Now()
+		ctx    = context.TODO()
+	)
+	start, _ := time.ParseInLocation(time.DateTime, jm.lastRun.BindPhone, time.Local)
+	val := public.GetBidPhoneUser(start, runNow)
+	if len(val) > 0 {
+		for i, msg := range val {
+			if i%10 == 0 {
+				g.Log().Infof(ctx, "JobManager.LoadBindPhoneUser %d/%d", i, len(val))
+			}
+			if err := jm.FilterPayUserAndSaveDb(ctx, msg); err != nil {
+				g.Log().Errorf(ctx, "JobManager.LoadBindPhoneUser.FilterPayUserAndSaveDb %v", gconv.String(msg))
+			}
+		}
+	}
+	//更新
+	jm.lastRun.BindPhone = runNow.Format(time.DateTime)
+	if err := jm.SaveLastRun(); err != nil {
+		g.Log().Errorf(ctx, "LoadBindPhoneUser error %v", err)
+	}
+}
+
+// LoadAgainSubUser 加载再次关注用户
+func (jm *JobManager) LoadAgainSubUser() {
+	var (
+		runNow = time.Now()
+		ctx    = context.TODO()
+	)
+	start, _ := time.ParseInLocation(time.DateTime, jm.lastRun.AgainSub, time.Local)
+	val := public.GetAgainSubUser(start, runNow)
+	if len(val) > 0 {
+		for i, msg := range val {
+			if i%10 == 0 {
+				g.Log().Infof(ctx, "JobManager.LoadAgainSubUser %d/%d", i, len(val))
+			}
+			if err := jm.FilterPayUserAndSaveDb(ctx, msg); err != nil {
+				g.Log().Errorf(ctx, "JobManager.LoadAgainSubUser.FilterPayUserAndSaveDb %v", gconv.String(msg))
+			}
+		}
+	}
+	//更新
+	jm.lastRun.AgainSub = runNow.Format(time.DateTime)
+	if err := jm.SaveLastRun(); err != nil {
+		g.Log().Errorf(ctx, "LoadAgainSubUser error %v", err)
+	}
+}

+ 176 - 0
doFreeClueSign/job/mamager.go

@@ -0,0 +1,176 @@
+package job
+
+import (
+	"context"
+	"doFreeClueSign/db"
+	"doFreeClueSign/public"
+	"fmt"
+	"github.com/gogf/gf/v2/container/gmap"
+	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/os/gcron"
+	"github.com/gogf/gf/v2/os/gctx"
+	"github.com/gogf/gf/v2/os/gfile"
+	"github.com/gogf/gf/v2/util/gconv"
+	"time"
+)
+
+type JobManager struct {
+	payUser  *gmap.Map //付费账户
+	register *gmap.Map
+	lastRun  *struct {
+		BindPhone   string `json:"bindPhone"`
+		AgainSub    string `json:"againSub"`
+		NewActivity string `json:"newActivity"`
+	}
+}
+
+var (
+	activityUserJobRunning         bool
+	bindPhoneAndSubAgainJobRunning bool
+)
+
+func InitJobManager() *JobManager {
+	var (
+		err                         error
+		ctx                         = gctx.New()
+		bindPhoneAndSubAgainCronStr = g.Cfg().MustGet(ctx, "cron.bindPhoneAndSubAgain").String()
+		activityUserCronStr         = g.Cfg().MustGet(ctx, "cron.activityUser").String()
+	)
+
+	job := &JobManager{
+		payUser:  gmap.New(true),
+		register: gmap.New(true),
+	}
+	job.LoadLastRun()
+
+	if bindPhoneAndSubAgainCronStr != "" {
+		_, err = gcron.Add(ctx, bindPhoneAndSubAgainCronStr, func(ctx context.Context) {
+			g.Log().Infof(ctx, "bindPhoneAndSubAgain start %v", bindPhoneAndSubAgainJobRunning)
+			if bindPhoneAndSubAgainJobRunning {
+				return
+			}
+			bindPhoneAndSubAgainJobRunning = true
+			defer func() {
+				bindPhoneAndSubAgainJobRunning = false
+			}()
+
+			job.LoadPayUser()
+			job.LoadAgainSubUser()
+			//job.LoadBindPhoneUser()
+		}, "bindPhoneAndSubAgain")
+		if err != nil {
+			panic(err)
+		}
+		gcron.Start("bindPhoneAndSubAgain")
+	}
+
+	if activityUserCronStr != "" {
+		_, err = gcron.Add(ctx, activityUserCronStr, func(ctx context.Context) {
+			g.Log().Infof(ctx, "activityUser start %v", activityUserJobRunning)
+			if activityUserJobRunning {
+				return
+			}
+			activityUserJobRunning = true
+			defer func() {
+				activityUserJobRunning = false
+			}()
+
+			job.LoadPayUser()
+			job.LoadActivityUser()
+
+		}, "activityUser")
+		if err != nil {
+			panic(err)
+		}
+		gcron.Start("activityUser")
+	}
+
+	return job
+}
+
+func (jm *JobManager) LoadLastRun() {
+	err := gconv.Struct(gfile.GetContents("runSign.json"), &jm.lastRun)
+	if err != nil {
+		g.Log().Errorf(context.TODO(), "加载上次运行配置日常")
+	}
+	now := time.Now().Format(time.DateTime)
+	if jm.lastRun.BindPhone == "" {
+		jm.lastRun.BindPhone = now
+	}
+	if jm.lastRun.AgainSub == "" {
+		jm.lastRun.AgainSub = now
+	}
+	if jm.lastRun.NewActivity == "" {
+		jm.lastRun.NewActivity = now
+	}
+	return
+}
+
+func (jm *JobManager) SaveLastRun() error {
+	return gfile.PutContents("runSign.json", gconv.String(jm.lastRun))
+}
+
+func (jm *JobManager) LoadPayUser() {
+	g.Log().Infof(context.TODO(), "加载付费用户")
+	newMap := gmap.New(true)
+	for i, v := range public.GetPayUser() {
+		newMap.Set(i, v)
+	}
+	jm.payUser = newMap
+}
+
+func (jm *JobManager) FilterPayUserAndSaveDb(ctx context.Context, value interface{}) error {
+	var (
+		sql           = `INSERT INTO freeClubSign `
+		val           []interface{}
+		now           = time.Now().Format(time.DateTime)
+		operationTime string
+	)
+	if msg, ok := value.(*public.AgainSubUserMsg); ok {
+		if jm.payUser.Contains(msg.MgoUserID) {
+			return nil
+		}
+		operationTime = time.Unix(msg.TimeStamp, 0).Format(time.DateTime)
+		sql += `(mogUserId,register_time,sub_again_date,create_time)VALUES (?,?,?,?)ON DUPLICATE KEY UPDATE sub_again_date=?`
+		val = append(val, msg.MgoUserID, jm.GetAndCacheRegisterDate(msg.MgoUserID), operationTime, now, operationTime)
+	} else if msg, ok := value.(*public.BindMsg); ok {
+		if jm.payUser.Contains(msg.MgoUserID) {
+			return nil
+		}
+		operationTime = time.Unix(msg.TimeStamp, 0).Format(time.DateTime)
+		sql += `(mogUserId,register_time,bind_phone_date,create_time)VALUES (?,?,?,?,?)ON DUPLICATE KEY UPDATE bind_phone_date=?`
+		val = append(val, msg.MgoUserID, jm.GetAndCacheRegisterDate(msg.MgoUserID), msg.Phone, operationTime, now, msg.Phone, operationTime)
+	} else if msg, ok := value.(*public.NewActiveMsg); ok {
+		if jm.payUser.Contains(msg.MgoUserID) {
+			return nil
+		}
+		operationTime = time.Unix(msg.TimeStamp, 0).Format(time.DateTime)
+		registerTime := jm.GetAndCacheRegisterDate(msg.MgoUserID)
+		if registerTime > time.Unix(msg.TimeStamp, 0).AddDate(0, 0, -30).Format(time.DateTime) {
+			return nil
+		}
+		sql += `(mogUserId,register_time,act_again_date,create_time)VALUES (?,?,?,?)ON DUPLICATE KEY UPDATE act_again_date=?`
+		val = append(val, msg.MgoUserID, registerTime, operationTime, now, operationTime)
+	} else {
+		return fmt.Errorf("未知类型")
+	}
+	_, err := g.DB("bi_service").Exec(context.TODO(), sql, val...)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// GetAndCacheRegisterDate 获取缓存用户注册时间
+func (jm *JobManager) GetAndCacheRegisterDate(mgoUserId string) string {
+	if registerDate := gconv.String(jm.register.Get(mgoUserId)); registerDate != "" {
+		return registerDate
+	}
+	rMap, _ := db.MG.DB().FindById("user", mgoUserId, `{"l_registedate":1}`)
+	if rMap == nil || len(*rMap) == 0 {
+		return ""
+	}
+	date := time.Unix(gconv.Int64((*rMap)["l_registedate"]), 0).Format(time.DateTime)
+	jm.register.Set(mgoUserId, date)
+	return date
+}

+ 3 - 16
doFreeClueSign/main.go

@@ -1,24 +1,11 @@
 package main
 
 import (
-	"context"
-	"github.com/gogf/gf/v2/frame/g"
-	"github.com/gogf/gf/v2/os/gcron"
-	"github.com/gogf/gf/v2/os/gctx"
+	"doFreeClueSign/job"
+	_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
 )
 
 func main() {
-	var (
-		err     error
-		ctx     = gctx.New()
-		cronStr = g.Cfg().MustGet(ctx, "runCron").String()
-	)
-	_, err = gcron.Add(ctx, cronStr, func(ctx context.Context) {
-		g.Log().Print(ctx, "Every second")
-
-	}, "doFreeClueSign")
-	if err != nil {
-		panic(err)
-	}
+	job.InitJobManager()
 	select {}
 }

+ 43 - 3
doFreeClueSign/public/getAgainSubUser.go

@@ -1,6 +1,12 @@
 package public
 
-import "time"
+import (
+	"app.yhyue.com/moapp/jybase/mongodb"
+	"doFreeClueSign/db"
+	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/util/gconv"
+	"time"
+)
 
 type AgainSubUserMsg struct {
 	MgoUserID string
@@ -8,6 +14,40 @@ type AgainSubUserMsg struct {
 }
 
 // GetAgainSubUser 再次关注用户列表
-func GetAgainSubUser(st, ed time.Time) []*AgainSubUserMsg {
-	return nil
+func GetAgainSubUser(st, ed time.Time) (rData []*AgainSubUserMsg) {
+	sess := db.MG.DB().GetMgoConn()
+	if sess != nil {
+		defer db.MG.DB().DestoryMongoConn(sess)
+	}
+	g.Dump("GetAgainSubUser-start", g.Map{"s_event": "subscribe", "l_date": g.Map{"$gte": st.Unix(), "$lt": ed.Unix()}})
+	it := sess.DB("qfw").C("jy_subscribe").Find(g.Map{"s_event": "subscribe", "l_date": g.Map{"$gte": st.Unix(), "$lt": ed.Unix()}}).
+		Select(g.Map{"s_m_openid": 1, "l_date": 1}).Iter()
+	for _temp := make(map[string]interface{}); it.Next(&_temp); {
+		var (
+			s_m_openid = gconv.String(_temp["s_m_openid"])
+			timeStamp  = gconv.Int64(_temp["l_date"])
+		)
+		//是否有取关记录
+		if count := db.MG.DB().Count("jy_subscribe", g.Map{"s_m_openid": s_m_openid, "s_event": "unsubscribe", "l_date": g.Map{"$lt": st.Unix()}}); count == 0 {
+			continue
+		}
+		if mgoUserID := getUserIdByOpenid(s_m_openid); mgoUserID != "" {
+			rData = append(rData, &AgainSubUserMsg{
+				MgoUserID: mgoUserID,
+				TimeStamp: timeStamp,
+			})
+		}
+		_temp = make(map[string]interface{})
+	}
+	g.Dump("GetAgainSubUser-finish")
+	return rData
+}
+
+func getUserIdByOpenid(openId string) (userId string) {
+	res, _ := db.MG.DB().FindOne("user", g.Map{"s_m_openid": openId})
+	if res == nil || len(*res) == 0 {
+		return
+	}
+	userId = mongodb.BsonIdToSId((*res)["_id"])
+	return
 }

+ 44 - 3
doFreeClueSign/public/getBindPhoneUser.go

@@ -1,6 +1,11 @@
 package public
 
-import "time"
+import (
+	"doFreeClueSign/db"
+	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/util/gconv"
+	"time"
+)
 
 type BindMsg struct {
 	MgoUserID string
@@ -9,6 +14,42 @@ type BindMsg struct {
 }
 
 // GetBidPhoneUser 获取绑定手机号
-func GetBidPhoneUser(st, ed time.Time) []*BindMsg {
-	return nil
+func GetBidPhoneUser(st, ed time.Time) (rData []*BindMsg) {
+	sess := db.MG.DB("log").GetMgoConn()
+	if sess != nil {
+		defer db.MG.DB("log").DestoryMongoConn(sess)
+	}
+	it := sess.DB("qfw").C("nsq_logs").Find(g.Map{"body.e_body.types": "bindPhone", "createtime": g.Map{"$gte": st.Unix(), "$lt": ed.Unix()}}).
+		Select(g.Map{"body.e_userid": 1, "createtime": 1}).Iter()
+	for _temp := make(map[string]interface{}); it.Next(&_temp); {
+		var (
+			userId    = gconv.String(gconv.Map(_temp["body"])["e_userid"])
+			timeStamp = gconv.Int64(_temp["createtime"])
+		)
+		if userId == "" {
+			continue
+		}
+		phone := getPhoneByUserId(userId)
+		rData = append(rData, &BindMsg{
+			MgoUserID: userId,
+			TimeStamp: timeStamp,
+			Phone:     phone,
+		})
+		_temp = make(map[string]interface{})
+	}
+	return
+}
+
+func getPhoneByUserId(userId string) (phone string) {
+	res, _ := db.MG.DB().FindById("user", userId, `{"s_phone":1,"s_m_phone":1}`)
+	if res == nil || len(*res) == 0 {
+		return
+	}
+	if phone = gconv.String((*res)["s_phone"]); phone != "" {
+		return
+	}
+	if phone = gconv.String((*res)["s_m_phone"]); phone != "" {
+		return
+	}
+	return
 }

+ 57 - 3
doFreeClueSign/public/getNewActiveUser.go

@@ -1,12 +1,66 @@
 package public
 
-import "time"
+import (
+	"context"
+	"fmt"
+	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/util/gconv"
+	"sync"
+	"time"
+)
 
 type NewActiveMsg struct {
 	MgoUserID string
 	TimeStamp int64 //活跃时间
 }
 
-func GetNewActiveUser(st, ed time.Time) []*NewActiveMsg {
-	return nil
+func GetNewActiveUser(st time.Time) ([]*NewActiveMsg, time.Time) {
+	var (
+		mgoIds []string
+		ctx    = context.Background()
+	)
+	//统计昨天的所有注册用户 过滤掉
+	end := st.AddDate(0, 0, 1)
+	ed := time.Date(end.Year(), end.Month(), end.Day(), 0, 0, 0, 0, st.Location())
+	stYear, stMonth, stDay := st.Date()
+	nst := st.AddDate(0, -1, 0)
+	_, nstMonth, nstDay := nst.Date()
+	//昨天所有活跃用户
+	res, err := g.DB("useranaly").Query(ctx, fmt.Sprintf(`SELECT DISTINCT user_mongoid FROM user_countbyhour
+WHERE CONCAT(month, '-', day) = '%s'`, fmt.Sprintf("%d-%d", int(stMonth), stDay)))
+	//res, err := g.DB().Query(ctx, fmt.Sprintf(`SELECT DISTINCT user_mongoid FROM user_countbyhour WHERE %s `, sql))
+	if err == nil && !res.IsEmpty() {
+		for _, m := range res.List() {
+			mongoid := gconv.String(m["user_mongoid"])
+			mgoIds = append(mgoIds, mongoid)
+		}
+	}
+	var (
+		lock sync.Mutex
+		data []*NewActiveMsg
+	)
+	pool := make(chan bool, 5)
+	wait := &sync.WaitGroup{}
+	for _, id := range mgoIds {
+		pool <- true
+		wait.Add(1)
+		go func(mId string) {
+			defer func() {
+				wait.Done()
+				<-pool
+			}()
+			count, _ := g.DB("useranaly").GetCount(ctx, fmt.Sprintf(`SELECT count(1) FROM user_countbyhour
+WHERE user_mongoid = '%s' and CONCAT(month, '-', day) >= '%s' AND  CONCAT(month, '-', day) < '%s';`, mId, fmt.Sprintf("%d-%d", int(nstMonth), nstDay), fmt.Sprintf("%d-%d", int(stMonth), stDay)))
+			if count == 0 { //统计昨天之前30天不活跃用户
+				lock.Lock()
+				data = append(data, &NewActiveMsg{
+					MgoUserID: mId,
+					TimeStamp: time.Date(stYear, stMonth, stDay, 0, 0, 0, 0, time.Local).Unix(),
+				})
+				lock.Unlock()
+			}
+		}(id)
+	}
+	wait.Wait()
+	return data, ed
 }

+ 11 - 28
doFreeClueSign/public/getPayUser.go

@@ -1,39 +1,22 @@
 package public
 
 import (
-	"doFreeClueSign/db"
+	"context"
+	"github.com/gogf/gf/v2/frame/g"
 	"github.com/gogf/gf/v2/util/gconv"
+	"time"
 )
 
 func GetPayUser() map[string]bool {
-	var pay = map[string]bool{}
-
-	//todo 取mongo user付费用户
-	query := gconv.Map(`{"$or":[{"i_vip_status":{"$gt":0}},{"i_member_status":{"$gt":0}}]}`)
-	res, _ := db.MG.DB().Find("user", query, nil, `{"s_phone":1,"s_m_phone":1}`, false, -1, -1)
-	if res != nil && len(*res) > 0 {
-		for _, m := range *res {
-			var (
-				s_phone   = gconv.String(m["s_phone"])
-				s_m_phone = gconv.String(m["s_m_phone"])
-				phone     string
-			)
-
-			if s_phone != "" {
-				phone = s_phone
-			} else if s_m_phone != "" {
-				phone = s_m_phone
-			}
-
-			if phone == "" {
-				continue
-			}
-			pay[phone] = true
+	var (
+		pay = make(map[string]bool)
+		ctx = context.Background()
+	)
+	res, err := g.DB("subjectdb").Query(ctx, `SELECT id,userid FROM dwd_f_data_equity_info WHERE endtime>?`, time.Now().Format(time.DateTime))
+	if err == nil && !res.IsEmpty() {
+		for _, m := range res.List() {
+			pay[gconv.String(m["userid"])] = true
 		}
 	}
-	//todo 企业子账号
-
-	//todo 企业身份下购买
-
 	return pay
 }

+ 1 - 0
doFreeClueSign/runSign.json

@@ -0,0 +1 @@
+{"bindPhone":"2024-07-26 15:15:11","againSub":"2024-07-26 15:15:11","newActivity":"2024-07-26 15:15:11"}