瀏覽代碼

Merge branch 'master' into feature/v1.5.13

yuelujie 11 月之前
父節點
當前提交
29101fa189

+ 6 - 5
clueSync/autoTask.go

@@ -301,16 +301,17 @@ func autoExitSea() {
 			}
 		}
 	}
-	datas := TiDb.Find("dwd_f_crm_clue_info", map[string]interface{}{"trailstatus": "00", "is_assign": 1}, "", "", -1, -1)
+	datas := TiDb.SelectBySql("select  * from  dwd_f_crm_clue_info where   (trailstatus='09' or   trailstatus='00') and   is_assign=1")
 	if datas != nil && len(*datas) > 0 {
 		for _, v := range *datas {
+			trailstatus := gconv.String(v["trailstatus"])
 			clueId := common.Int64All(v["id"])
 			positionId := common.Int64All(v["position_id"])
 			seatNumber := common.ObjToString(v["seatNumber"])
 			nowTime := time.Now().Format(date.Date_Full_Layout)
 			// is_assign := common.IntAll(v["is_assign"])
 			if TiDb.ExecTx("自动退海", func(tx *sql.Tx) bool {
-				recordId := TiDb.UpdateOrDeleteBySqlByTx(tx, `UPDATE dwd_f_crm_clue_info SET is_assign=0,position_id=null,seatNumber=null,updatetime = ?,comeintime_open = ?,comeinsource_open=8,level_open=4,next_trail_time=null,is_task=null,tasktime=null,taskstatus=null,comeinsource_private=null,tasksource=null WHERE id = ?`, nowTime, nowTime, clueId) //,content=null,start_trail_time=null
+				recordId := TiDb.UpdateOrDeleteBySqlByTx(tx, `UPDATE dwd_f_crm_clue_info SET is_assign=0,position_id=null,seatNumber=null,updatetime = ?,comeintime_open = ?,comeinsource_open=?,level_open=4,next_trail_time=null,is_task=null,tasktime=null,taskstatus=null,comeinsource_private=null,tasksource=null WHERE id = ?`, nowTime, nowTime, common.If(trailstatus == "00", 8, 11), clueId) //,content=null,start_trail_time=null
 				recordId1 := TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
 					"clue_id":      clueId,
 					"position_id":  positionId,
@@ -327,7 +328,7 @@ func autoExitSea() {
 					"position_id":  positionId,
 					"change_field": "trailstatus",
 					"change_type":  "基本信息变更",
-					"old_value":    "无意向客户",
+					"old_value":    common.If(trailstatus == "00", "无意向客户", "拒绝客户"),
 					"new_value":    "流失",
 					"createtime":   nowTime,
 					"BCPCID":       common.GetRandom(32),
@@ -337,7 +338,7 @@ func autoExitSea() {
 					"clue_id":     clueId,
 					"position_id": positionId,
 					"change_type": "退出任务车",
-					"new_value":   "无意向客户自动退回公海",
+					"new_value":   common.If(trailstatus == "00", "无意向客户自动退回公海", "拒绝客户自动退回公海"),
 					"createtime":  nowTime,
 					"BCPCID":      common.GetRandom(32),
 					"operator_id": -1,
@@ -346,7 +347,7 @@ func autoExitSea() {
 					"clue_id":     clueId,
 					"position_id": positionId,
 					"change_type": "退回公海",
-					"new_value":   "无意向客户自动退回公海",
+					"new_value":   common.If(trailstatus == "00", "无意向客户自动退回公海", "拒绝客户自动退回公海"),
 					"createtime":  nowTime,
 					"BCPCID":      common.GetRandom(32),
 					"operator_id": -1,

+ 1 - 1
clueSync/config.json

@@ -1 +1 @@
-{"lastOrderId":258784,"lastOrderClueId":"2024-05-25 02:23:21","lastUserId":"2024-05-20 15:40:02","lastXcxUserId":"2024-07-09 14:59:37","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,"advisoryCommitteeTime":1724136683,"allocationTime":"2024-07-01 14:59:37","allocationRatio":2,"activeTime":"2024-07-01 14:59:37","rebindTime":"2024-07-01 14:59:37"}
+{"lastOrderId":258784,"lastOrderClueId":"2024-05-25 02:23:21","lastUserId":"2024-05-20 15:40:02","lastXcxUserId":"2024-07-09 14:59:37","lastId":"66cd4d3ae83797f8bf5e7ca2","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,"advisoryCommitteeTime":1724136683,"allocationTime":"2024-07-01 14:59:37","allocationRatio":2,"activeTime":"2024-07-01 14:59:37","rebindTime":"2024-08-27 16:10:27"}

+ 69 - 37
clueSync/job.go

@@ -269,7 +269,6 @@ func FormatData(data map[string]interface{}, item string) (bool, bool) {
 			if batch_import != "" && item == "users" { //有导入批次号还是新用户,不执行
 				return true, true
 			}
-			//oks = UpdateClue(*uCount, saleData, item, userId, uId, top_cluetype, sub_cluetype, topname, subname, cluename, name, saleName, phone, position, department, departments, industry, follow_project_area, role, seatNumber, level, position_id, source, sourceCode, remark, keyword, belong_to, isGroup, isCommerce, pIsOk, "")
 			oks = UpdateClue(*uCount, saleData, item, userId, uId, top_cluetype, sub_cluetype, topname, subname, cluename, name, saleName, phone, position, department, departments, industry, follow_project_area, role, seatNumber, level, position_id, source, sourceCode, remark, keyword, belong_to, isGroup, isCommerce, pIsOk)
 		} else { //不存在走新增
 			oks = SaveClue(item, userId, uId, top_cluetype, sub_cluetype, topname, subname, cluename, name, saleName, phone, position, department, departments, industry, follow_project_area, role, seatNumber, position_id, source, sourceCode, remark, keyword, belong_to, isGroup, isCommerce, isFreeze, "")
@@ -822,7 +821,7 @@ func WorkUpdateClue(data map[string]interface{}, saleData []map[string]interface
 		clueUpdateData["level_open"] = nil
 		clueUpdateData["clue_level"] = nil
 	}
-	if trailstatus != "08" && is_assign == 0 { //在公海的成交客户
+	if is_assign == 0 { //在公海的成交客户
 		if trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400 {
 		} else {
 			clueUpdateData["trailstatus"] = "01"
@@ -834,7 +833,7 @@ func WorkUpdateClue(data map[string]interface{}, saleData []map[string]interface
 		clueUpdateData["trailstatus_time"] = nowTime
 	}
 	is_ok := false
-	if (trailstatus != "08" && recordCount <= 0) || is_assign == 0 {
+	if recordCount <= 0 || is_assign == 0 {
 		if trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400 {
 		} else {
 			if item == "eventReg" {
@@ -883,6 +882,7 @@ func WorkUpdateClue(data map[string]interface{}, saleData []map[string]interface
 		//线索
 		ok = TiDb.UpdateByTx(tx, "dwd_f_crm_clue_info", map[string]interface{}{"uid": uId}, clueUpdateData)
 		//变更记录
+
 		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 {
@@ -968,7 +968,7 @@ func WorkUpdateClue(data map[string]interface{}, saleData []map[string]interface
 					})
 				}
 			}
-		} else if trailstatus != "08" && is_assign == 0 {
+		} else if is_assign == 0 {
 			if trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400 {
 			} else {
 				updateId1 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
@@ -1007,7 +1007,7 @@ func WorkUpdateClue(data map[string]interface{}, saleData []map[string]interface
 					"operator_id":  -1,
 				})
 			}
-		} else if trailstatus != "08" && is_assign == -1 {
+		} else if is_assign == -1 {
 			updateId1 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
 				"clue_id":      clueId,
 				"position_id":  positionId,
@@ -1043,21 +1043,11 @@ func WorkUpdateClue(data map[string]interface{}, saleData []map[string]interface
 				"operator_id":  -1,
 			})
 		}
-		if (trailstatus != "08" && recordCount <= 0) || is_assign == 0 {
+		if recordCount <= 0 || is_assign == 0 {
 			if trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400 {
 			} else {
-				if old_sub_cluetype != sub_cluetype && !is_ok {
-					if is_transfer != 1 {
-						updateId5 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
-							"clue_id":     clueId,
-							"position_id": common.If(trailstatus == "00" || is_assign == 0 || is_assign == -1, positionId, common.If(is_assign == 1, positionId, common.Int64All(data["position_id"]))),
-							"change_type": "加入任务车",
-							"new_value":   "线索来源自动更新" + "-" + topname + "-" + subname,
-							"createtime":  nowTime,
-							"BCPCID":      common.GetRandom(32),
-							"operator_id": -1,
-						})
-					} else {
+				if is_transfer == 1 {
+					if old_sub_cluetype != sub_cluetype && !is_ok {
 						cdata := TiDb.FindOne("dwd_f_csm_customer_info", map[string]interface{}{"clue_id": clueId}, "", "")
 						if cdata != nil && len(*cdata) > 0 {
 							kcpositionId := common.Int64All((*cdata)["position_id"])
@@ -1091,9 +1081,20 @@ func WorkUpdateClue(data map[string]interface{}, saleData []map[string]interface
 							})
 						}
 					}
+				} else if !is_ok {
+					updateId5 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
+						"clue_id":     clueId,
+						"position_id": common.If(trailstatus == "00" || is_assign == 0 || is_assign == -1, positionId, common.Int64All(data["position_id"])),
+						"change_type": "加入任务车",
+						"new_value":   gconv.String(common.If(gconv.Int64(data["position_id"]) == 0, "线索自动分配", "线索来源自动更新")) + "-" + topname + "-" + subname,
+						"createtime":  nowTime,
+						"BCPCID":      common.GetRandom(32),
+						"operator_id": -1,
+					})
 				}
 			}
 		}
+
 		if old_top_cluetype != "" {
 			pcodeData := TiDb.FindOne("dwd_d_crm_cluetype_code", map[string]interface{}{"code": old_top_cluetype}, "", "")
 			if pcodeData != nil && len(*pcodeData) > 0 {
@@ -1363,8 +1364,13 @@ func UpdateClue(data map[string]interface{}, saleData []map[string]interface{},
 			}
 		}
 	}
-	if trailstatus == "00" || old_position_id == 0 || is_assign != 1 || (pIsOk && old_cluename != cluename && cluename != "") {
+	if trailstatus == "00" || trailstatus == "09" || old_position_id == 0 || is_assign != 1 || (pIsOk && old_cluename != cluename && cluename != "") {
 		if trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400 {
+			//无意向几天以内不参与分配
+		} else if trailstatus == "09" && (topname != "付费产品落地页主动留资" && topname != "受理系统") {
+			//线索状态为“拒绝沟通客户”,则仅针对线索来源一级分类为“付费产品落地页主动留资”和“受理系统”产生的线索进行线索分配,其他类线上线索只做线索更新但不再自动分配。
+			positionId = 0
+			seatNumber = ""
 		} else {
 			clueUpdateData["seatNumber"] = seatNumber
 			clueUpdateData["position_id"] = positionId
@@ -1387,8 +1393,12 @@ func UpdateClue(data map[string]interface{}, saleData []map[string]interface{},
 		clueUpdateData["level_open"] = nil
 		clueUpdateData["clue_level"] = nil
 	}
-	if trailstatus != "08" && is_assign == 0 { //在公海的成交客户
+	if is_assign == 0 { //在公海的成交客户
 		if trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400 {
+		} else if trailstatus == "09" && (topname != "付费产品落地页主动留资" && topname != "受理系统") {
+			//线索状态为“拒绝沟通客户”,则仅针对线索来源一级分类为“付费产品落地页主动留资”和“受理系统”产生的线索进行线索分配,其他类线上线索只做线索更新但不再自动分配。
+			positionId = 0
+			seatNumber = ""
 		} else {
 			clueUpdateData["trailstatus"] = "01"
 			clueUpdateData["trailstatus_time"] = nowTime
@@ -1399,8 +1409,12 @@ func UpdateClue(data map[string]interface{}, saleData []map[string]interface{},
 		clueUpdateData["trailstatus_time"] = nowTime
 	}
 	is_ok := false
-	if (trailstatus != "08" && recordCount <= 0) || is_assign == 0 {
+	if recordCount <= 0 || is_assign == 0 {
 		if trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400 {
+		} else if trailstatus == "09" && (topname != "付费产品落地页主动留资" && topname != "受理系统") {
+			//线索状态为“拒绝沟通客户”,则仅针对线索来源一级分类为“付费产品落地页主动留资”和“受理系统”产生的线索进行线索分配,其他类线上线索只做线索更新但不再自动分配。
+			positionId = 0
+			seatNumber = ""
 		} else {
 			if item == "eventReg" {
 				eData := TiDb.Find("dwd_f_crm_clue_change_record", map[string]interface{}{"clue_id": clueId, "change_type": "加入任务车"}, "", "", -1, -1)
@@ -1450,6 +1464,9 @@ func UpdateClue(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 trailstatus == "09" && (topname != "付费产品落地页主动留资" && topname != "受理系统") {
+				positionId = 0
+				seatNumber = ""
 			} else if old_position_id == 0 {
 				updateId1 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
 					"clue_id":      clueId,
@@ -1533,8 +1550,11 @@ func UpdateClue(data map[string]interface{}, saleData []map[string]interface{},
 					})
 				}
 			}
-		} else if trailstatus != "08" && is_assign == 0 {
+		} else if is_assign == 0 {
 			if trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400 {
+			} else if trailstatus == "09" && (topname != "付费产品落地页主动留资" && topname != "受理系统") {
+				positionId = 0
+				seatNumber = ""
 			} else {
 				updateId1 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
 					"clue_id":      clueId,
@@ -1572,7 +1592,7 @@ func UpdateClue(data map[string]interface{}, saleData []map[string]interface{},
 					"operator_id":  -1,
 				})
 			}
-		} else if trailstatus != "08" && is_assign == -1 {
+		} else if is_assign == -1 {
 			updateId1 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
 				"clue_id":      clueId,
 				"position_id":  positionId,
@@ -1596,21 +1616,14 @@ func UpdateClue(data map[string]interface{}, saleData []map[string]interface{},
 				"operator_id":  -1,
 			})
 		}
-		if (trailstatus != "08" && recordCount <= 0) || is_assign == 0 {
+		if recordCount <= 0 || is_assign == 0 {
 			if trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400 {
+			} else if trailstatus == "09" && (topname != "付费产品落地页主动留资" && topname != "受理系统") {
+				positionId = 0
+				seatNumber = ""
 			} else {
-				if old_sub_cluetype != sub_cluetype && !is_ok {
-					if is_transfer != 1 {
-						updateId5 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
-							"clue_id":     clueId,
-							"position_id": common.If(trailstatus == "00" || is_assign == 0 || is_assign == -1, positionId, common.Int64All(data["position_id"])),
-							"change_type": "加入任务车",
-							"new_value":   gconv.String(common.If(gconv.Int64(data["position_id"]) == 0, "线索自动分配", "线索来源自动更新")) + "-" + topname + "-" + subname,
-							"createtime":  nowTime,
-							"BCPCID":      common.GetRandom(32),
-							"operator_id": -1,
-						})
-					} else {
+				if is_transfer == 1 {
+					if old_sub_cluetype != sub_cluetype && !is_ok {
 						cdata := TiDb.FindOne("dwd_f_csm_customer_info", map[string]interface{}{"clue_id": clueId}, "", "")
 						if cdata != nil && len(*cdata) > 0 {
 							kcpositionId := common.Int64All((*cdata)["position_id"])
@@ -1644,6 +1657,16 @@ func UpdateClue(data map[string]interface{}, saleData []map[string]interface{},
 							})
 						}
 					}
+				} else if !is_ok {
+					updateId5 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
+						"clue_id":     clueId,
+						"position_id": common.If(trailstatus == "00" || is_assign == 0 || is_assign == -1, positionId, common.Int64All(data["position_id"])),
+						"change_type": "加入任务车",
+						"new_value":   gconv.String(common.If(gconv.Int64(data["position_id"]) == 0, "线索自动分配", "线索来源自动更新")) + "-" + topname + "-" + subname,
+						"createtime":  nowTime,
+						"BCPCID":      common.GetRandom(32),
+						"operator_id": -1,
+					})
 				}
 			}
 		}
@@ -1700,7 +1723,16 @@ func UpdateClue(data map[string]interface{}, saleData []map[string]interface{},
 				})
 			}
 			if old_role != role && role != "" {
-				updateId9 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{"clue_id": clueId, "position_id": common.If(trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400, -1, common.If(trailstatus == "00" || is_assign == 0, positionId, common.Int64All(data["position_id"]))), "change_field": "role", "change_type": "基本信息变更", "old_value": common.If(old_role != "", old_role, "/"), "new_value": common.If(role != "", role, "/"), "createtime": nowTime, "BCPCID": BCPCID, "operator_id": -1})
+				updateId9 = TiDb.InsertByTx(tx, "dwd_f_crm_clue_change_record", map[string]interface{}{
+					"clue_id":      clueId,
+					"position_id":  common.If(trailstatus == "00" && trailstatusTime != "" && time.Now().Unix()-trailstatusTimes.Unix() < 86400, -1, common.If(trailstatus == "00" || is_assign == 0, positionId, common.Int64All(data["position_id"]))),
+					"change_field": "role",
+					"change_type":  "基本信息变更",
+					"old_value":    common.If(old_role != "", old_role, "/"),
+					"new_value":    common.If(role != "", role, "/"),
+					"createtime":   nowTime,
+					"BCPCID":       BCPCID,
+					"operator_id":  -1})
 			}
 			if old_follow_project_area != follow_project_area && follow_project_area != "" {
 				old_area, old_area_arr := "", []string{}

+ 13 - 4
clueSync/jobutil.go

@@ -969,7 +969,7 @@ func getClueType(item string, data map[string]interface{}, sourceCode string, so
 	} else if item == "allocation" {
 		pcode = "532"
 		code = "671"
-		level = "C"
+		level = "D"
 		pcodeData := TiDb.FindOne("dwd_d_crm_cluetype_code", map[string]interface{}{"code": pcode}, "", "")
 		if pcodeData != nil && len(*pcodeData) > 0 {
 			topname = common.ObjToString((*pcodeData)["name"])
@@ -981,7 +981,7 @@ func getClueType(item string, data map[string]interface{}, sourceCode string, so
 	} else if item == "rebind" {
 		pcode = "532"
 		code = "670"
-		level = "C"
+		level = "D"
 		pcodeData := TiDb.FindOne("dwd_d_crm_cluetype_code", map[string]interface{}{"code": pcode}, "", "")
 		if pcodeData != nil && len(*pcodeData) > 0 {
 
@@ -1040,8 +1040,10 @@ func autoDraw(mode, cluename, phone string, isGroup, isCommerce int) (positionId
 						positionid := gconv.Int64(m["position_id"])
 						for _, v := range *pdata {
 							resign := common.IntAll(v["resign"])
+							assign_type := common.IntAll(v["assign_type"])
+							role_id := common.IntAll(v["role_id"])
 							if positionid == common.Int64All(v["position_id"]) {
-								if resign == 0 {
+								if resign == 0 && (assign_type == 1 || role_id == 8) {
 									if !FindUpperLimit(gconv.String(positionid), mode, true) {
 										personMap[positionid] = true
 										m["saleName"] = common.ObjToString(v["name"])
@@ -1159,8 +1161,10 @@ func autoDraw(mode, cluename, phone string, isGroup, isCommerce int) (positionId
 					seatNumber = common.ObjToString((*cdata)[0]["seatNumber"])
 					for _, v := range *pdata {
 						resign := common.IntAll(v["resign"])
+						assign_type := common.IntAll(v["assign_type"])
+						role_id := common.IntAll(v["role_id"])
 						if positionId == common.Int64All(v["position_id"]) {
-							if resign == 0 {
+							if resign == 0 && (assign_type == 1 || role_id == 8) {
 								if FindUpperLimit(gconv.String(positionId), mode, true) {
 									isFreeze = true
 									positionId = 0
@@ -1179,11 +1183,16 @@ func autoDraw(mode, cluename, phone string, isGroup, isCommerce int) (positionId
 			}
 		}
 	}
+	positionId = 0
+	seatNumber = ""
+	saleName = ""
 	query := `select * from dwd_f_crm_personnel_management where assign_type = 1 and`
 	if mode == "A" {
 		query += ` assign_level like "%A%"`
 	} else if mode == "B" {
 		query += ` assign_level like "%B%"`
+	} else if mode == "D" {
+		query += ` assign_level like "%D%"`
 	} else {
 		query += ` assign_level like "%C%"`
 	}

+ 1 - 0
clueSync/main.go

@@ -154,6 +154,7 @@ func main() {
 			marketCustomer()    //市场部线索
 			AdvisoryCommittee() //咨询组线索
 			rebind()            //取关重新关注处理
+			activeUsers()       //活跃用户处理
 		})
 		//每天8点30
 		c := cron.New()

+ 27 - 10
telemarketingEtl/config.yaml

@@ -1,40 +1,47 @@
 tidb:
   jianyuSubjectdb:
-    dbName: Jianyu_subjectdb
-    address: 192.168.3.217:4000
+    dbName: jianyu_subjectdb_test
+    address: 192.168.3.149:4000
     userName: root
-    password: '=PDT49#80Z!RVv52_z'
+    password: 'Tibi#20211222'
+    maxOpenConns: 80
+    maxIdleConns: 5
+  callAccount:
+    dbName: Call_Accounting
+    address: 192.168.3.149:4000
+    userName: root
+    password: 'Tibi#20211222'
     maxOpenConns: 80
     maxIdleConns: 5
 mysql:
   main:
     dbName: jianyu
-    address: 192.168.3.149:3306
+    address: 192.168.3.14:4000
     userName: root
-    password: 'Topnet123'
+    password: '=PDT49#80Z!RVv52_z'
     maxOpenConns: 80
     maxIdleConns: 5
 mongo:
   main:
     dbName: qfw
     size: 50
-    address: 192.168.3.206:27080
+    address: 192.168.3.149:27180
   log:
     dbName: qfw
     size: 50
-    address: 192.168.3.206:27090
+    address: 192.168.3.149:27190
     userName: admin
     password: 123456
   ent:
     dbName: mixdata
     size: 50
-    address: 192.168.3.206:27002
+    address: 192.168.3.149:27102
     collection: qyxy
     collectionChange: qyxy_change
     userName: jyDevGroup
     password: jy@DevGroup
   bidding:
-    address: 192.168.3.206:27002
+    address: 192.168.3.149:27102
     size: 50
     dbName: qfw_data
     collection: bidding
@@ -94,12 +101,22 @@ openSeaTask: '0 0 0 * * *'
 deleteOpenSeaTask: '0 0 0 * * *'
 #自动退回公海
 returnOpenSeaTask: '0 0 0 * * *'
+#定时任务 近30天最多访问
+countMaxVisitTask: '0 0 0 * * *'
+#定时任务 最近7天外呼次数
+countCallsTask: '0 0 * * * *'
+#定时任务 最近连续未接听次数
+missedCallsTask: '0 0 * * * *'
+#定时任务 近3天招标采购搜索次数/近3天点击标讯三级页次数
+jyListAndDetailTask: '0 0 * * * *'
+#定时任务 会员是否到期
+vipExpireTask: '0 0 0 * * *'
 #查看
 eventInfoTime: 5
 #搜索
 searchInfoTime: 5
 #每日
-visitInfoTime: 5
+visitInfoTime: 1000
 #定时
 openSeaTime: 5
 #退出

+ 13 - 0
telemarketingEtl/config/config.go

@@ -13,6 +13,7 @@ import (
 
 var (
 	JianyuSubjectdb *mysql.Mysql
+	VoicedRecordDb  *mysql.Mysql // 通话
 	JianyuMaindb    *mysql.Mysql
 	Mgo             mg.MongodbSim
 	MgoLog          mg.MongodbSim
@@ -49,6 +50,18 @@ func init() {
 		}
 		JianyuMaindb.Init()
 	}
+	if g.Cfg().MustGet(ctx, "tidb.callAccount.dbName").String() != "" {
+		log.Println("初始化tidb")
+		VoicedRecordDb = &mysql.Mysql{
+			Address:      g.Cfg().MustGet(ctx, "tidb.callAccount.address").String(),
+			UserName:     g.Cfg().MustGet(ctx, "tidb.callAccount.userName").String(),
+			PassWord:     g.Cfg().MustGet(ctx, "tidb.callAccount.password").String(),
+			DBName:       g.Cfg().MustGet(ctx, "tidb.callAccount.dbName").String(),
+			MaxOpenConns: g.Cfg().MustGet(ctx, "tidb.callAccount.maxOpenConns").Int(),
+			MaxIdleConns: g.Cfg().MustGet(ctx, "tidb.callAccount.maxIdleConns").Int(),
+		}
+		VoicedRecordDb.Init()
+	}
 	//
 	if g.Cfg().MustGet(ctx, "mongo.main.dbName").String() != "" {
 		log.Println("初始化 mongodb main")

+ 277 - 0
telemarketingEtl/entity/Voiced.go

@@ -0,0 +1,277 @@
+package entity
+
+import (
+	"app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/date"
+	"go.mongodb.org/mongo-driver/bson"
+	"log"
+	"strings"
+	"sync"
+	"telemarketingEtl/config"
+	"time"
+)
+
+type Called struct {
+	phone     []string
+	frequency int
+}
+
+type Voiced struct {
+	vDate  string
+	missed int // 未接通次数
+}
+
+var (
+	CurrentDate           string
+	currentDateMx         sync.Mutex
+	firstLoad, firstLoad1 = true, true
+	mUser                 = make(map[string]*Called) // 用户
+	userPhone             = make(map[string]string)  // 手机号-用户uid
+	userPhoneMx           sync.Mutex
+	callPhone             []string                   // 所有被叫手机号
+	missedPhone           = make(map[string]*Voiced) // 所有被叫未接通手机号
+)
+
+// 最近7天外呼次数
+func CountCalled() {
+	// 判断当日第一次执行
+	currentDateMx.Lock()
+	if CurrentDate != date.NowFormat(date.Date_Short_Layout) {
+		firstLoad = true
+		CurrentDate = date.NowFormat(date.Date_Short_Layout)
+	} else {
+		firstLoad = false
+	}
+	currentDateMx.Unlock()
+
+	getUser()
+	log.Println("CountCalled 所有用户及手机号加载结束...")
+	getRecord()
+	log.Println("CountCalled 通话记录加载结束...")
+
+	for _, s := range callPhone {
+		uid := userPhone[s]
+		mUser[uid].frequency += 1
+	}
+	log.Println("CountCalled 通话次数匹配结束...")
+	for k, v := range mUser {
+		if v.frequency > 0 {
+			if b := config.JianyuSubjectdb.Update("dwd_f_crm_attribute_label", bson.M{"uid": k}, bson.M{"outbound_count": v.frequency}); !b {
+				config.JianyuSubjectdb.Insert("dwd_f_crm_attribute_label", map[string]interface{}{
+					"uid":            k,
+					"members_info":   "昨日未浏览",
+					"updatetime":     time.Now(),
+					"outbound_count": v.frequency,
+				})
+			}
+		}
+	}
+
+}
+
+func getUser() {
+	var (
+		count = 0
+	)
+	userPhoneMx.Lock()
+	defer userPhoneMx.Unlock()
+	//sql := "SELECT userId, uid, phone FROM dwd_f_userbase_baseinfo"
+	sql := "SELECT baseinfo_id, phone FROM dwd_f_userbase_contacts"
+	rows, err := config.JianyuSubjectdb.DB.Query(sql)
+	if err != nil {
+		log.Println("CountCalled---", err)
+	}
+	columns, err := rows.Columns()
+	for rows.Next() {
+		scanArgs := make([]interface{}, len(columns))
+		values := make([]interface{}, len(columns))
+		ret := make(map[string]interface{})
+		for k := range values {
+			scanArgs[k] = &values[k]
+		}
+		err = rows.Scan(scanArgs...)
+		if err != nil {
+			log.Println("CountCalled---", err)
+			break
+		}
+		for i, col := range values {
+			if v, ok := col.([]uint8); ok {
+				ret[columns[i]] = string(v)
+			} else {
+				ret[columns[i]] = col
+			}
+		}
+		count++
+		if count%2000 == 0 {
+			log.Println("CountCalled current-------", count)
+		}
+		uid := common.ObjToString(ret["baseinfo_id"])
+		phone := common.ObjToString(ret["phone"])
+		userPhone[phone] = uid
+		if mUser[uid] != nil {
+			mUser[uid].phone = append(mUser[uid].phone, phone)
+		} else {
+			mUser[uid] = &Called{
+				phone:     []string{phone},
+				frequency: 0,
+			}
+		}
+	}
+	_ = rows.Close()
+}
+
+func getRecord() {
+	var (
+		sql      string
+		countSql string
+		count    int
+		total    int64
+	)
+	if firstLoad {
+		// 当日首次执行	1、全部归0 outbound_count
+		config.JianyuSubjectdb.ExecBySql("UPDATE dwd_f_crm_attribute_label SET outbound_count = 0")
+		sql = "SELECT createTime, CallNo, CalledNo FROM voice_record WHERE DATE(createTime) BETWEEN DATE(NOW() - INTERVAL 7 DAY) AND DATE(NOW()) ORDER BY createTime ASC"
+		countSql = "SELECT COUNT(id) FROM voice_record WHERE DATE(createTime) BETWEEN DATE(NOW() - INTERVAL 7 DAY) AND DATE(NOW())"
+	} else {
+		aTime := time.Now().Add(-1 * time.Hour)
+		sql = "SELECT createTime, CallNo, CalledNo FROM voice_record WHERE createTime >= " + aTime.Format(time.DateTime) + " ORDER BY createTime ASC"
+		countSql = "SELECT COUNT(id) FROM voice_record WHERE createTime >= " + aTime.Format(time.DateTime)
+	}
+	total = config.VoicedRecordDb.CountBySql(countSql)
+	log.Println("CountCalled getRecord---", total)
+	if total <= 0 {
+		return
+	}
+
+	rows, err := config.VoicedRecordDb.DB.Query(sql)
+	if err != nil {
+		log.Println("CountCalled getRecord---", err)
+	}
+	columns, err := rows.Columns()
+	for rows.Next() {
+		scanArgs := make([]interface{}, len(columns))
+		values := make([]interface{}, len(columns))
+		ret := make(map[string]interface{})
+		for k := range values {
+			scanArgs[k] = &values[k]
+		}
+		err = rows.Scan(scanArgs...)
+		if err != nil {
+			log.Println("CountCalled getRecord---", err)
+			break
+		}
+		for i, col := range values {
+			if v, ok := col.([]uint8); ok {
+				ret[columns[i]] = string(v)
+			} else {
+				ret[columns[i]] = col
+			}
+		}
+		count++
+		if count%2000 == 0 {
+			log.Println("getRecord current-------", count)
+		}
+		phone := common.ObjToString(ret["CalledNo"])
+		callPhone = append(callPhone, phone)
+	}
+	_ = rows.Close()
+}
+
+// 因为同一个用户有多个手机号的情况,所以无法通过手机号直接修改
+func MissedCalls() {
+	getMissedCalls()
+	log.Println("MissedCalls 通话记录加载结束...")
+
+	for k, v := range missedPhone {
+		if b := config.JianyuSubjectdb.Update("dwd_f_crm_attribute_label", bson.M{"uid": k}, bson.M{"noanswer_count": v.missed}); !b {
+			config.JianyuSubjectdb.Insert("dwd_f_crm_attribute_label", map[string]interface{}{
+				"uid":            k,
+				"members_info":   "昨日未浏览",
+				"updatetime":     time.Now(),
+				"noanswer_count": v.missed,
+			})
+		}
+	}
+}
+
+func getMissedCalls() {
+	var (
+		sql      string
+		countSql string
+		count    int
+		total    int64
+	)
+	if firstLoad1 {
+		sql = "SELECT createTime, CallNo, CalledNo, State FROM voice_record ORDER BY createTime ASC"
+		countSql = "SELECT COUNT(id) FROM voice_record"
+		firstLoad1 = false
+	} else {
+		aTime := time.Now().Add(-1 * time.Hour)
+		sql = "SELECT createTime, CallNo, CalledNo, State FROM voice_record WHERE createTime >= " + aTime.Format(time.DateTime) + " ORDER BY createTime ASC"
+		countSql = "SELECT COUNT(id) FROM voice_record WHERE createTime >= " + aTime.Format(time.DateTime)
+	}
+	total = config.VoicedRecordDb.CountBySql(countSql)
+	log.Println("MissedCalls getMissedCalls---", total)
+	if total <= 0 {
+		return
+	}
+	rows, err := config.VoicedRecordDb.DB.Query(sql)
+	if err != nil {
+		log.Println("MissedCalls getMissedCalls---", err)
+	}
+	columns, err := rows.Columns()
+	for rows.Next() {
+		scanArgs := make([]interface{}, len(columns))
+		values := make([]interface{}, len(columns))
+		ret := make(map[string]interface{})
+		for k := range values {
+			scanArgs[k] = &values[k]
+		}
+		err = rows.Scan(scanArgs...)
+		if err != nil {
+			log.Println("MissedCalls getMissedCalls---", err)
+			break
+		}
+		for i, col := range values {
+			if v, ok := col.([]uint8); ok {
+				ret[columns[i]] = string(v)
+			} else {
+				ret[columns[i]] = col
+			}
+		}
+		count++
+		if count%2000 == 0 {
+			log.Println("MissedCalls getMissedCalls current-------", count)
+		}
+		phone := common.ObjToString(ret["CalledNo"])
+		vdate := strings.Split(common.ObjToString(ret["createTime"]), " ")[0]
+		ctype := common.ObjToString(ret["State"])
+		uid := userPhone[phone]
+		if ctype != "dealing" {
+			if missedPhone[uid] != nil {
+				v := missedPhone[uid]
+				v.vDate = vdate
+				v.missed += 1
+				//if VerifyDate(v.vDate, vdate) <= 1 {
+				//	v.vDate = vdate
+				//	v.missed += 1
+				//} else {
+				//	v.missed = 1
+				//	v.vDate = vdate
+				//}
+			} else {
+				missedPhone[uid] = &Voiced{
+					vDate:  vdate,
+					missed: 1,
+				}
+			}
+		} else {
+			if uid != "" && missedPhone[uid] != nil {
+				v := missedPhone[uid]
+				v.vDate = vdate
+				v.missed = 0
+			}
+		}
+	}
+	_ = rows.Close()
+}

+ 0 - 1
telemarketingEtl/entity/dwd_f_crm_open_sea.go

@@ -747,7 +747,6 @@ func RefuseRecycle() {
 	refuseHandReturn := g.Cfg().MustGet(ctx, "refuseHandReturn").Int()
 	tA := t.AddDate(0, 0, -refuseHandReturn)
 	sql := fmt.Sprintf(`select id from dwd_f_crm_clue_info where comeinsource_open=11 and is_assign = 0 and comeintime_open > "%s" ;`, tA.Format(date.Date_Full_Layout))
-
 	config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
 		ids := []interface{}{}
 		for _, v := range *l {

+ 365 - 2
telemarketingEtl/entity/dwd_f_userbase_visit_info.go

@@ -1,8 +1,12 @@
 package entity
 
 import (
+	"app.yhyue.com/moapp/jybase/common"
+	"fmt"
+	"go.mongodb.org/mongo-driver/bson"
 	"log"
 	"regexp"
+	"strings"
 	"sync"
 	"telemarketingEtl/config"
 	"telemarketingEtl/util"
@@ -70,7 +74,7 @@ func VisitInfoAdd(start, end int64) {
 						userid, uid = GetUserIdByPositionId(userid)
 					} else {
 						idmdata := config.JianyuSubjectdb.SelectBySql(`select uid from dwd_f_userbase_id_mapping where userid = "` + userid + `"`)
-						if idmdata != nil {
+						if idmdata != nil && len(*idmdata) > 0 {
 							uid = gconv.String((*idmdata)[0]["uid"])
 						}
 					}
@@ -121,7 +125,7 @@ func VisitInfoAdd(start, end int64) {
 					} else {
 						config.JianyuSubjectdb.InsertBySql(`INSERT INTO dwd_f_userbase_visit_info
 														(userid,DATE, number, platform,createtime,contentnum,portraitnum,searchnum)
-														VALUES (?,?,?,?,?,?)`, userid, craetetimeStr, 1, platform, craetetimeStr, contentnum, portraitnum, searchnum)
+														VALUES (?,?,?,?,?,?,?,?)`, userid, craetetimeStr, 1, platform, craetetimeStr, contentnum, portraitnum, searchnum)
 					}
 					if uid != "" {
 						if config.JianyuSubjectdb.CountBySql(`select count(1) from dwd_f_crm_attribute_label where uid = ?`, uid) > 0 {
@@ -141,6 +145,7 @@ func VisitInfoAdd(start, end int64) {
 				}
 				thisData = map[string]interface{}{}
 			}
+			log.Printf("%s一共完成%d条数据\n", table, count)
 			log.Println("end!")
 			// sWait.Wait()
 		}(table)
@@ -153,3 +158,361 @@ func getToday(createtime int64) (start, end string) {
 	endOfDay := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())
 	return startOfDay.Format(date.Date_Full_Layout), endOfDay.Format(date.Date_Full_Layout)
 }
+
+type UserVisit struct {
+	userId string
+	uId    string
+	vDate  string
+	days   int
+}
+
+// 近30天最大访问次数
+func CountMaxVisit() {
+
+	var (
+		count = 0
+
+		mArr  []*UserVisit
+		mData = make(map[string]*UserVisit)
+	)
+
+	sql := "SELECT x.*, y.uid FROM dwd_f_userbase_visit_info x LEFT JOIN dwd_f_userbase_baseinfo y ON x.userid = y.userid WHERE DATE(`date`) BETWEEN DATE(NOW() - INTERVAL 30 DAY) AND DATE(NOW()) ORDER BY `date` ASC"
+	rows, err := config.JianyuSubjectdb.DB.Query(sql)
+	if err != nil {
+		log.Println("CountMaxVisit---", err)
+	}
+	columns, err := rows.Columns()
+	for rows.Next() {
+		scanArgs := make([]interface{}, len(columns))
+		values := make([]interface{}, len(columns))
+		ret := make(map[string]interface{})
+		for k := range values {
+			scanArgs[k] = &values[k]
+		}
+		err = rows.Scan(scanArgs...)
+		if err != nil {
+			log.Println("CountMaxVisit---", err)
+			break
+		}
+		for i, col := range values {
+			if v, ok := col.([]uint8); ok {
+				ret[columns[i]] = string(v)
+			} else {
+				ret[columns[i]] = col
+			}
+		}
+		count++
+		if count%2000 == 0 {
+			log.Println("CountMaxVisit current-------", count)
+		}
+		userid := common.ObjToString(ret["userid"])
+		mDate := common.ObjToString(ret["date"])
+		mArr = append(mArr, &UserVisit{
+			userId: userid,
+			uId:    common.ObjToString(ret["uid"]),
+			vDate:  strings.Split(mDate, " ")[0],
+		})
+	}
+	_ = rows.Close()
+
+	for _, v := range mArr {
+		if mData[v.userId] != nil {
+			v1 := mData[v.userId]
+			if d := VerifyDate(v1.vDate, v.vDate); d == 1 {
+				v1.days++
+				mData[v.userId] = &UserVisit{
+					userId: v.userId,
+					uId:    v.uId,
+					vDate:  v.vDate,
+					days:   v1.days,
+				}
+			} else if d > 1 {
+				mData[v.userId] = &UserVisit{
+					userId: v.userId,
+					uId:    v.uId,
+					vDate:  v.vDate,
+					days:   1,
+				}
+			}
+		} else {
+			mData[v.userId] = &UserVisit{
+				userId: v.userId,
+				uId:    v.uId,
+				vDate:  v.vDate,
+				days:   1,
+			}
+		}
+	}
+
+	// 先 归0
+	config.JianyuSubjectdb.ExecBySql("UPDATE dwd_f_crm_attribute_label SET continuous_visit_day = 0 WHERE continuous_visit_day != 0")
+	for _, v := range mData {
+		if b := config.JianyuSubjectdb.Update("dwd_f_crm_attribute_label", bson.M{"uid": v.uId}, bson.M{"continuous_visit_day": v.days}); !b {
+			config.JianyuSubjectdb.Insert("dwd_f_crm_attribute_label", map[string]interface{}{
+				"uid":                  v.days,
+				"members_info":         "昨日未浏览",
+				"updatetime":           time.Now(),
+				"continuous_visit_day": v.days,
+			})
+		}
+	}
+}
+
+// @Author jianghan
+// @Description 日期相差天数
+// @Date 2024/8/22
+func VerifyDate(d1, d2 string) int {
+	if d1 == d2 {
+		return 0
+	}
+	d11, err := time.Parse(date.Date_Short_Layout, d1)
+	if err != nil {
+		fmt.Println("Error parsing d1:", err)
+		return -1
+	}
+	d21, err := time.Parse(date.Date_Short_Layout, d2)
+	if err != nil {
+		fmt.Println("Error parsing d2:", err)
+		return -1
+	}
+	days := int(d21.Sub(d11).Hours() / 24)
+	return days
+}
+
+var (
+	firstLoad2, firstLoad3 = true, true
+
+	mSearchMap = make(map[string]int)
+	mDetailMap = make(map[string]int)
+)
+
+func Count3DaysSearch() {
+	var (
+		sql      string
+		countSql string
+		count    int
+		total    int64
+	)
+
+	// 判断当日第一次执行
+	currentDateMx.Lock()
+	if CurrentDate != date.NowFormat(date.Date_Short_Layout) {
+		firstLoad2 = true
+		CurrentDate = date.NowFormat(date.Date_Short_Layout)
+	} else {
+		firstLoad2 = false
+	}
+	currentDateMx.Unlock()
+
+	if firstLoad2 {
+		// 当日首次执行	1、全部归0 search_count
+		config.JianyuSubjectdb.ExecBySql("UPDATE dwd_f_crm_attribute_label SET search_count = 0")
+		sql = "SELECT v.userid, b.uid, v.search_time FROM dwd_f_userbase_search_info v LEFT JOIN dwd_f_userbase_baseinfo b ON v.userid = b.userid WHERE DATE(v.search_time) BETWEEN DATE(NOW() - INTERVAL 3 DAY) AND DATE(NOW()) ORDER BY v.search_time ASC"
+		countSql = "SELECT COUNT(v.id) FROM dwd_f_userbase_search_info v WHERE DATE(v.search_time) BETWEEN DATE(NOW() - INTERVAL 3 DAY) AND DATE(NOW())"
+	} else {
+		aTime := time.Now().Add(-1 * time.Hour)
+		sql = "SELECT v.userid, b.uid, v.search_time FROM dwd_f_userbase_search_info v LEFT JOIN dwd_f_userbase_baseinfo b ON v.userid = b.userid WHERE v.search_time >= " + aTime.Format(time.DateTime) + " ORDER BY v.date ASC"
+		countSql = "SELECT COUNT(v.id) FROM dwd_f_userbase_search_info v WHERE v.search_time >= " + aTime.Format(time.DateTime)
+	}
+	total = config.JianyuSubjectdb.CountBySql(countSql)
+	log.Println("Count3DaysSearch total---", total)
+	if total <= 0 {
+		return
+	}
+	rows, err := config.JianyuSubjectdb.DB.Query(sql)
+	if err != nil {
+		log.Println("Count3DaysSearch---", err)
+	}
+	columns, err := rows.Columns()
+	for rows.Next() {
+		scanArgs := make([]interface{}, len(columns))
+		values := make([]interface{}, len(columns))
+		ret := make(map[string]interface{})
+		for k := range values {
+			scanArgs[k] = &values[k]
+		}
+		err = rows.Scan(scanArgs...)
+		if err != nil {
+			log.Println("CountMaxVisit---", err)
+			break
+		}
+		for i, col := range values {
+			if v, ok := col.([]uint8); ok {
+				ret[columns[i]] = string(v)
+			} else {
+				ret[columns[i]] = col
+			}
+		}
+		count++
+		if count%2000 == 0 {
+			log.Println("Count3DaysSearch current-------", count)
+		}
+		uid := common.ObjToString(ret["uid"])
+		mSearchMap[uid] += 1
+	}
+	_ = rows.Close()
+
+	for k, v := range mSearchMap {
+		if config.JianyuSubjectdb.CountBySql("SELECT COUNT(uid) FROM dwd_f_crm_attribute_label WHERE uid = ?", k) > 0 {
+			config.JianyuSubjectdb.ExecBySql("UPDATE dwd_f_crm_attribute_label SET search_count = search_count + ? WHERE uid = ?", v, k)
+		} else {
+			config.JianyuSubjectdb.Insert("dwd_f_crm_attribute_label", map[string]interface{}{
+				"uid":          k,
+				"members_info": "昨日未浏览",
+				"updatetime":   time.Now(),
+				"search_count": v,
+			})
+		}
+	}
+}
+
+func Count3DaysDetail() {
+	var (
+		sql      string
+		countSql string
+		count    int
+		total    int64
+	)
+
+	// 判断当日第一次执行
+	currentDateMx.Lock()
+	if CurrentDate != date.NowFormat(date.Date_Short_Layout) {
+		firstLoad3 = true
+		CurrentDate = date.NowFormat(date.Date_Short_Layout)
+	} else {
+		firstLoad3 = false
+	}
+	currentDateMx.Unlock()
+
+	if firstLoad3 {
+		// 当日首次执行	1、全部归0 click_detail_count
+		config.JianyuSubjectdb.ExecBySql("UPDATE dwd_f_crm_attribute_label SET click_detail_count = 0")
+		sql = "SELECT v.userid, b.uid, v.date, v.contentnum FROM dwd_f_userbase_visit_info v LEFT JOIN dwd_f_userbase_baseinfo b ON v.userid = b.userid WHERE DATE(v.date) BETWEEN DATE(NOW() - INTERVAL 3 DAY) AND DATE(NOW()) ORDER BY v.date ASC"
+		countSql = "SELECT COUNT(v.id) FROM dwd_f_userbase_visit_info v WHERE DATE(date) BETWEEN DATE(NOW() - INTERVAL 3 DAY) AND DATE(NOW())"
+	} else {
+		aTime := time.Now().Add(-1 * time.Hour)
+		sql = "SELECT v.userid, b.uid, v.date, v.contentnum FROM dwd_f_userbase_visit_info v LEFT JOIN dwd_f_userbase_baseinfo b ON v.userid = b.userid WHERE v.date >= " + aTime.Format(time.DateTime) + " ORDER BY v.date ASC"
+		countSql = "SELECT COUNT(v.id) FROM dwd_f_userbase_visit_info v WHERE v.date >= " + aTime.Format(time.DateTime)
+	}
+	total = config.JianyuSubjectdb.CountBySql(countSql)
+	log.Println("Count3DaysDetail total---", total)
+	if total <= 0 {
+		return
+	}
+	rows, err := config.JianyuSubjectdb.DB.Query(sql)
+	if err != nil {
+		log.Println("Count3DaysDetail---", err)
+	}
+	columns, err := rows.Columns()
+	for rows.Next() {
+		scanArgs := make([]interface{}, len(columns))
+		values := make([]interface{}, len(columns))
+		ret := make(map[string]interface{})
+		for k := range values {
+			scanArgs[k] = &values[k]
+		}
+		err = rows.Scan(scanArgs...)
+		if err != nil {
+			log.Println("CountMaxVisit---", err)
+			break
+		}
+		for i, col := range values {
+			if v, ok := col.([]uint8); ok {
+				ret[columns[i]] = string(v)
+			} else {
+				ret[columns[i]] = col
+			}
+		}
+		count++
+		if count%2000 == 0 {
+			log.Println("Count3DaysDetail current-------", count)
+		}
+		uid := common.ObjToString(ret["uid"])
+		num := common.IntAll(ret["contentnum"])
+		mDetailMap[uid] += num
+	}
+	_ = rows.Close()
+
+	for k, v := range mDetailMap {
+		if config.JianyuSubjectdb.CountBySql("SELECT COUNT(uid) FROM dwd_f_crm_attribute_label WHERE uid = ?", k) > 0 {
+			config.JianyuSubjectdb.ExecBySql("UPDATE dwd_f_crm_attribute_label SET click_detail_count = click_detail_count + ? WHERE uid = ?", v, k)
+		} else {
+			config.JianyuSubjectdb.Insert("dwd_f_crm_attribute_label", map[string]interface{}{
+				"uid":                k,
+				"members_info":       "昨日未浏览",
+				"updatetime":         time.Now(),
+				"click_detail_count": v,
+			})
+		}
+	}
+}
+
+func VipExpire() {
+
+	var (
+		sql      string
+		countSql string
+		total    int64
+		count    int
+	)
+
+	now := time.Now()
+	config.JianyuSubjectdb.ExecBySql("update dwd_f_crm_attribute_label set supersub = 0 where supersub = 1")
+	config.JianyuSubjectdb.ExecBySql("update dwd_f_crm_attribute_label set areasubpkg = 0 where areasubpkg = 1")
+
+	sql = fmt.Sprintf("select uid, product_type from dwd_f_data_equity_info WHERE product_type = '省份订阅包' or product_type = '超级订阅' AND endtime > %s", now.Format(date.Date_Short_Layout))
+	countSql = fmt.Sprintf("select count(id) from dwd_f_data_equity_info WHERE product_type = '省份订阅包' or product_type = '超级订阅' AND endtime > %s", now.Format(date.Date_Short_Layout))
+
+	total = config.JianyuSubjectdb.CountBySql(countSql)
+	log.Println("VipExpire total---", total)
+	if total <= 0 {
+		return
+	}
+	rows, err := config.JianyuSubjectdb.DB.Query(sql)
+	if err != nil {
+		log.Println("VipExpire---", err)
+	}
+	columns, err := rows.Columns()
+	for rows.Next() {
+		scanArgs := make([]interface{}, len(columns))
+		values := make([]interface{}, len(columns))
+		ret := make(map[string]interface{})
+		for k := range values {
+			scanArgs[k] = &values[k]
+		}
+		err = rows.Scan(scanArgs...)
+		if err != nil {
+			log.Println("VipExpire---", err)
+			break
+		}
+		for i, col := range values {
+			if v, ok := col.([]uint8); ok {
+				ret[columns[i]] = string(v)
+			} else {
+				ret[columns[i]] = col
+			}
+		}
+		count++
+		if count%2000 == 0 {
+			log.Println("VipExpire current-------", count)
+		}
+
+		uid := common.ObjToString(ret["uid"])
+		ptype := common.ObjToString(ret["product_type"])
+		if config.JianyuSubjectdb.CountBySql("SELECT COUNT(uid) FROM dwd_f_crm_attribute_label WHERE uid = ?", uid) > 0 {
+			if ptype == "省份订阅包" {
+				config.JianyuSubjectdb.ExecBySql("UPDATE dwd_f_crm_attribute_label SET areasubpkg = 1 WHERE uid = ?", uid)
+			} else {
+				config.JianyuSubjectdb.ExecBySql("UPDATE dwd_f_crm_attribute_label SET supersub = 1 WHERE uid = ?", uid)
+			}
+		} else {
+			config.JianyuSubjectdb.Insert("dwd_f_crm_attribute_label", map[string]interface{}{
+				"uid":          uid,
+				"members_info": "昨日未浏览",
+				"updatetime":   time.Now(),
+				common.ObjToString(common.If(ptype == "省份订阅包", "areasubpkg", "supersub")): 1,
+			})
+		}
+	}
+	_ = rows.Close()
+}

+ 2 - 0
telemarketingEtl/go.mod

@@ -8,6 +8,7 @@ require (
 	github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.3
 	github.com/gogf/gf/v2 v2.3.3
 	github.com/robfig/cron v1.2.0
+	github.com/robfig/cron/v3 v3.0.1
 	go.mongodb.org/mongo-driver v1.9.1
 	gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
 )
@@ -32,6 +33,7 @@ require (
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.1 // indirect
 	github.com/klauspost/compress v1.13.6 // indirect
+	github.com/lunny/csession v0.0.0-20130910075847-fe53c5de3dfd // indirect
 	github.com/magiconair/properties v1.8.6 // indirect
 	github.com/mattn/go-colorable v0.1.9 // indirect
 	github.com/mattn/go-isatty v0.0.14 // indirect

+ 5 - 0
telemarketingEtl/go.sum

@@ -312,6 +312,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lunny/csession v0.0.0-20130910075847-fe53c5de3dfd h1:DXxmBCahjva4Ox4AWOv6pR1Csv33zSj97SaLOElfIsw=
+github.com/lunny/csession v0.0.0-20130910075847-fe53c5de3dfd/go.mod h1:3w9PScemEkJoLw3OYvLWMoD8XRCmXgGwsSpT6pFpJ0g=
 github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
 github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -326,6 +328,7 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
 github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
 github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
@@ -404,6 +407,8 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
 github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
+github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
+github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=

+ 13 - 2
telemarketingEtl/main.go

@@ -6,9 +6,20 @@ import (
 )
 
 func main() {
-
+	t1 := timetask.TaskCountMaxVisit{}
+	t1.Run()
+	t2 := timetask.TaskCountCalled{}
+	t2.Run()
+	t3 := timetask.TaskMissedCalls{}
+	t3.Run()
+	t4 := timetask.TaskJyList{}
+	t4.Run()
+	t5 := timetask.TaskJyDetail{}
+	t5.Run()
+	t6 := timetask.TaskVipExpire{}
+	t6.Run()
 	//定时任务开始
-	timetask.Run()
+	//timetask.Run()
 	select {}
 
 }

二進制
telemarketingEtl/telemarketingEtl


+ 89 - 57
telemarketingEtl/timetask/task.go

@@ -1,14 +1,14 @@
 package timetask
 
 import (
-	"context"
+	"app.yhyue.com/moapp/jybase/date"
+	"github.com/robfig/cron/v3"
 	"log"
 	"telemarketingEtl/entity"
 	"time"
 
 	_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
 	"github.com/gogf/gf/v2/os/gcfg"
-	"github.com/gogf/gf/v2/os/gcron"
 	"github.com/gogf/gf/v2/os/gctx"
 )
 
@@ -41,7 +41,9 @@ func GetStartEnd() (start, end int64) {
 	return
 }
 
-func TaskEventInfo() {
+type TaskEventInfo struct{}
+
+func (t *TaskEventInfo) Run() {
 	log.Println("开始TaskEventInfo")
 	now := time.Now()
 	end := now.Unix()
@@ -52,7 +54,9 @@ func TaskEventInfo() {
 	log.Println("结束TaskEventInfo")
 }
 
-func TaskSearchInfo() {
+type TaskSearchInfo struct{}
+
+func (t *TaskSearchInfo) Run() {
 	log.Println("开始TaskSearchInfo")
 	now := time.Now()
 	end := now.Unix()
@@ -62,7 +66,9 @@ func TaskSearchInfo() {
 	entity.SearchInfoAdd(start, end)
 }
 
-func TaskVisitInfo() {
+type TaskVisitInfo struct{}
+
+func (t *TaskVisitInfo) Run() {
 	log.Println("开始TaskVisitInfo")
 	now := time.Now()
 	end := now.Unix()
@@ -72,73 +78,99 @@ func TaskVisitInfo() {
 	log.Println("结束TaskVisitInfo")
 }
 
-func TaskOpenSea() {
+type TaskOpenSea struct{}
+
+func (t *TaskOpenSea) Run() {
 	log.Println("开始TaskOpenSea")
 	entity.GetOpenSea()
 	log.Println("结束TaskOpenSea")
 }
 
+type TaskCountMaxVisit struct{}
+
+func (t *TaskCountMaxVisit) Run() {
+	log.Println("开始TaskCountMaxVisit")
+	entity.CountMaxVisit()
+	log.Println("结束TaskCountMaxVisit")
+}
+
+type TaskCountCalled struct{}
+
+func (t *TaskCountCalled) Run() {
+	log.Println("开始TaskCountCalled")
+	entity.CountCalled()
+	log.Println("结束TaskCountCalled")
+}
+
+type TaskMissedCalls struct{}
+
+func (t *TaskMissedCalls) Run() {
+	log.Println("开始TaskMissedCalls")
+	entity.MissedCalls()
+	log.Println("结束TaskMissedCalls")
+}
+
+type TaskJyList struct{}
+
+func (t *TaskJyList) Run() {
+	log.Println("开始TaskJyList")
+	entity.Count3DaysSearch()
+	log.Println("结束TaskJyList")
+}
+
+type TaskJyDetail struct{}
+
+func (t *TaskJyDetail) Run() {
+	log.Println("开始TaskJyDetail")
+	entity.Count3DaysDetail()
+	log.Println("结束TaskJyDetail")
+}
+
+type TaskVipExpire struct{}
+
+func (t *TaskVipExpire) Run() {
+	log.Println("开始TaskVipExpire")
+	entity.VipExpire()
+	log.Println("结束TaskVipExpire")
+}
+
 // 定时任务
 func Run() {
 
 	timetaskBl := gcfg.Instance().MustGet(gctx.New(), "timetaskBl", "").Bool()
 	if timetaskBl {
 		var (
-			err error
-			ctx = gctx.New()
+			c = cron.New()
 		)
 		eventInfoTask := gcfg.Instance().MustGet(gctx.New(), "eventInfoTask", "").String()
 		searchInfoTask := gcfg.Instance().MustGet(gctx.New(), "searchInfoTask", "").String()
 		visitInfoTask := gcfg.Instance().MustGet(gctx.New(), "visitInfoTask", "").String()
 		openSeaTask := gcfg.Instance().MustGet(gctx.New(), "openSeaTask", "").String()
-		// deleteOpenSeaTask := gcfg.Instance().MustGet(gctx.New(), "deleteOpenSeaTask", "").String()
-		// returnOpenSeaTask := gcfg.Instance().MustGet(gctx.New(), "returnOpenSeaTask", "").String()
-		//
-		_, err = gcron.Add(ctx, eventInfoTask, func(ctx context.Context) {
-			TaskEventInfo()
-		}, "TaskEventInfo")
-		if err != nil {
-			panic(err)
-		}
-
-		//
-		_, err = gcron.Add(ctx, searchInfoTask, func(ctx context.Context) {
-			TaskSearchInfo()
-		}, "TaskSearchInfo")
-		if err != nil {
-			panic(err)
-		}
-		//
-		_, err = gcron.Add(ctx, visitInfoTask, func(ctx context.Context) {
-			TaskVisitInfo()
-		}, "TaskVisitInfo")
-		if err != nil {
-			panic(err)
-		}
-		//
-		_, err = gcron.Add(ctx, openSeaTask, func(ctx context.Context) {
-			TaskOpenSea()
-		}, "TaskOpenSea")
-		if err != nil {
-			panic(err)
-		}
-		//
-		// _, err = gcron.Add(ctx, deleteOpenSeaTask, func(ctx context.Context) {
-		// 	log.Println("开始DeleteOpenSea")
-		// 	entity.DeleteOpenSea()
-		// 	log.Println("结束DeleteOpenSea")
-		// }, "DeleteOpenSea")
-		// if err != nil {
-		// 	panic(err)
-		// }
-		//
-		// _, err = gcron.Add(ctx, returnOpenSeaTask, func(ctx context.Context) {
-		// 	log.Println("开始ReturnOpenSea")
-		// 	entity.ReturnOpenSea()
-		// 	log.Println("结束ReturnOpenSea")
-		// }, "ReturnOpenSea")
-		// if err != nil {
-		// 	panic(err)
-		// }
+		countMaxVisitTask := gcfg.Instance().MustGet(gctx.New(), "countMaxVisitTask", "").String()
+		countCalledVoice := gcfg.Instance().MustGet(gctx.New(), "countCallsTask", "").String()
+		missedCallsTask := gcfg.Instance().MustGet(gctx.New(), "missedCallsTask", "").String()
+		jyListAndDetailTask := gcfg.Instance().MustGet(gctx.New(), "jyListAndDetailTask", "").String()
+		vipExpireTask := gcfg.Instance().MustGet(gctx.New(), "vipExpireTask", "").String()
+
+		c.AddJob(eventInfoTask, cron.NewChain(cron.DelayIfStillRunning(cron.DefaultLogger)).Then(&TaskEventInfo{}))
+		c.AddJob(searchInfoTask, cron.NewChain(cron.DelayIfStillRunning(cron.DefaultLogger)).Then(&TaskSearchInfo{}))
+		c.AddJob(visitInfoTask, cron.NewChain(cron.DelayIfStillRunning(cron.DefaultLogger)).Then(&TaskVisitInfo{}))
+		c.AddJob(openSeaTask, cron.NewChain(cron.DelayIfStillRunning(cron.DefaultLogger)).Then(&TaskOpenSea{}))
+
+		entity.CurrentDate = date.NowFormat(date.Date_Short_Layout)
+		//近30天连续访问天数
+		c.AddJob(countMaxVisitTask, cron.NewChain(cron.DelayIfStillRunning(cron.DefaultLogger)).Then(&TaskCountMaxVisit{}))
+		//最近7天外呼次数
+		c.AddJob(countCalledVoice, cron.NewChain(cron.DelayIfStillRunning(cron.DefaultLogger)).Then(&TaskCountCalled{}))
+		//最近连续未接听次数
+		c.AddJob(missedCallsTask, cron.NewChain(cron.DelayIfStillRunning(cron.DefaultLogger)).Then(&TaskMissedCalls{}))
+		//近3天招标采购搜索次数
+		c.AddJob(jyListAndDetailTask, cron.NewChain(cron.DelayIfStillRunning(cron.DefaultLogger)).Then(&TaskJyList{}))
+		//近3天点击标讯三级页次数
+		c.AddJob(jyListAndDetailTask, cron.NewChain(cron.DelayIfStillRunning(cron.DefaultLogger)).Then(&TaskJyDetail{}))
+		//会员是否到期
+		c.AddJob(vipExpireTask, cron.NewChain(cron.DelayIfStillRunning(cron.DefaultLogger)).Then(&TaskVipExpire{}))
+
+		c.Start()
 	}
 }