Procházet zdrojové kódy

Merge branch 'develop' of http://192.168.3.17/gitlab/zhanghongbo/qfw into develop

zhanghongbo před 9 roky
rodič
revize
479a076633

+ 6 - 0
common/src/qfw/util/rpc/push.go

@@ -0,0 +1,6 @@
+package rpc
+
+type PushData struct {
+	Mopenid  string
+	PushType map[string]string
+}

+ 2 - 1
core/src/timetask.json

@@ -1 +1,2 @@
-{"comment":{"c_rate":720,"commentrate":900},"market":{"demand":{"attr":["i_hits","i_bids","i_status"],"timepoint":"2016-01-18 11:06:50"},"service":{"attr":["i_hits","i_sales","i_comments","i_score","i_appcounts"],"timepoint":"2016-01-18 11:06:50"}},"marketisstart":true,"marketrate":300}
+{"comment":{"c_rate":720,"commentrate":900},"market":{"demand":{"attr":["i_hits","i_bids","i_status"],"timepoint":"2016-01-18 14:14:51"},"service":{"attr":["i_hits","i_sales","i_comments","i_score","i_appcounts"],"timepoint":"2016-01-18 14:14:51"}},"marketisstart":true,"marketrate":300}
+

+ 4 - 0
push/src/config.json

@@ -6,6 +6,7 @@
     "bidStartTime": "2015-12-17 14:10:11",
     "bidTitle": "亲!剑鱼为您速报最新鲜的中标信息啦",
     "bidViewDomain": "192.168.3.132",
+    "bidrStartTime": "2015-12-30 17:27:31",
     "durationMinutes": 1,
     "fixPush": "oJULtwzXo6EFV1Ah-XeyRBimXGM8",
     "mail_bid": "\u003cdiv\u003e%s\u003c/div\u003e,想了解更多信息,请访问http://www.qimingxing.info。",
@@ -48,6 +49,8 @@
         "香港": 33,
         "黑龙江": 8
     },
+    "pushInfoScopeDays": 1,
+    "rpcPort": 8766,
     "smtpAddr": "smtp.exmail.qq.com",
     "smtpFromUser": "企明星",
     "smtpPort": 465,
@@ -55,6 +58,7 @@
     "smtpUser": "qyfw@topnet.net.cn",
     "tenderStartTime": "2015-12-17 14:10:11",
     "tenderTitle": "亲!剑鱼为您速报最新鲜的招标信息啦",
+    "tenderrStartTime": "2015-12-30 17:27:29",
     "weixinRpcServer": "127.0.0.1:82",
     "weixin_bid": "\u003cdiv\u003e%s最新招标信息\u003c/div\u003e\u003cdiv\u003e%s\u003c/div\u003e",
     "wxRpcRemark": "请到网站个人中心查看详细."

+ 13 - 0
push/src/main.go

@@ -4,8 +4,13 @@
 package main
 
 import (
+	"log"
+	"net"
+	"net/http"
+	"net/rpc"
 	"qfw/push"
 	"qfw/push/bid"
+	"qfw/push/rpcpush"
 	"qfw/push/tender"
 	"qfw/util"
 	"qfw/util/mongodb"
@@ -21,6 +26,7 @@ func init() {
 		push.City[k] = uint(v.(float64))
 	}
 	bid.MaxPushSize = util.IntAll(push.PushConfig["maxPushSize"])
+	rpcpush.PushInfoScopeDays = util.IntAll(push.PushConfig["pushInfoScopeDays"])
 	tender.MaxPushSize = bid.MaxPushSize
 	mongodb.InitMongodbPool(util.IntAll(push.PushConfig["mgoSize"]), push.PushConfig["mgoAddr"].(string), "qfw")
 }
@@ -50,6 +56,13 @@ func runJob() {
 //主应用,定时任务
 func main() {
 	go runJob()
+	crpc := new(rpcpush.PushInfo)
+	rpc.Register(crpc)
+	rpc.HandleHTTP()
+	port, _ := push.PushConfig["rpcPort"].(string)
+	l, _ := net.Listen("tcp", ":"+port)
+	go http.Serve(l, nil)
+	log.Println("启动推送系统", port)
 	flag := make(chan bool)
 	<-flag
 }

+ 9 - 208
push/src/qfw/push/bid/bidpushjob.go

@@ -9,223 +9,24 @@
 package bid
 
 import (
-	"container/list"
-	"fmt"
-	"log"
-	"math/rand"
 	"qfw/push"
-	"qfw/push/dfa"
+	"qfw/push/dopush"
 	"qfw/util"
-	"qfw/util/mongodb"
-	qrpc "qfw/util/rpc"
-	"runtime"
-	"strconv"
-	"strings"
 	"time"
 )
 
 type BidPushJob struct {
-	dfa *dfa.DFA
 }
 
-//构造用户兴趣词库
-func (b *BidPushJob) createUserInterestWord() {
-	b.dfa = &dfa.DFA{}
-	words := make([]string, 0)
-	for k, _ := range push.Cache {
-		words = append(words, k)
-	}
-	b.dfa.AddWord(words...)
-}
-
-var TITLEA string = "[中标信息]" //tender
 var MaxPushSize int
 
-//遍历查到的
-func (b *BidPushJob) eachAllBidInfo() {
-	defer func() {
-		if r := recover(); r != nil {
-			fmt.Println("推送开始[E]", r)
-		}
-	}()
-	session := mongodb.GetMgoConn()
-	defer mongodb.DestoryMongoConn(session)
-	startTime := push.PushConfig["bidStartTime"].(string)
-	st, _ := time.ParseInLocation(util.Date_Full_Layout, startTime, time.Local)
-	q := `{"comeintime":{"$gt":` + fmt.Sprintf("%d", st.Unix()) + `},"type":"bid"}`
-	n, _ := session.DB("qfw").C("bidding").Find(mongodb.ObjToOth(q)).Count()
-	log.Println(q, "查询推送信息:", n, ",时间", startTime)
-	if n == 0 {
-		//没有查询到结果
-		return
-	}
-	query := session.DB("qfw").C("bidding").Find(mongodb.ObjToOth(q)).Sort("-publishtime").Iter()
-	userMap := &map[*push.MemberInterest]*list.List{}
-	for tmp := new(map[string]interface{}); query.Next(tmp); {
-		title := util.ObjToString((*tmp)["title"])
-		if title != "" {
-			//返回匹配到的词组
-			res := b.dfa.Analy(title)
-			if len(res) > 0 {
-				province := (*tmp)["area"].(string)
-				provinceVal := push.GetChoiceCode(province)
-				for _, v := range res {
-					//根据关键词返回用户指针
-					tw := push.Cache[v]
-					if tw != nil {
-						//遍历用户加入到此条信息上
-						for _, v2 := range *tw {
-							if v2.Province == "A" || v2.ProvinceVal&provinceVal > 0 {
-								s := (*userMap)[v2]
-								if s == nil {
-									//s = &map[*map[string]interface{}]bool{}
-									s = list.New()
-									(*userMap)[v2] = s
-								}
-								s.PushBack(tmp)
-							}
-						}
-					}
-				}
-			}
-		}
-		tmp = new(map[string]interface{})
-	}
-
-	now := time.Now()
-	nowtime := util.FormatDate(&now, util.Date_Full_Layout)
-	//更改开始时间
-	push.PushConfig["bidStartTime"] = nowtime
-	//date := util.FormatDate(&now, util.Date_Short_Layout)
-
-	for k, v := range *(userMap) {
-		kk := *k
-		vv := *v
-		time.Sleep(50 * time.Millisecond)
-		go send(&kk, &vv, now, nowtime)
-	}
-}
-
-func send(k *push.MemberInterest, v *list.List, now time.Time, nowtime string) {
-	defer func() {
-		if r := recover(); r != nil {
-			log.Println("[E]", r)
-			for skip := 1; ; skip++ {
-				_, file, line, ok := runtime.Caller(skip)
-				if !ok {
-					break
-				}
-				go log.Printf("%v,%v\n", file, line)
-			}
-		}
-	}()
-	//wxstr := ""
-	str := fmt.Sprintf("<div>根据您设置的关键词(%s),给您推送以下信息:</div>", strings.Join(k.Interest, ";"))
-
-	//发送内容组合
-	i := 0
-	lastInfoDate := int64(0)
-	firstTitle := ""
-	publishTimes := map[string]interface{}{}
-	for ks := v.Front(); ks != nil; ks = ks.Next() {
-		k2 := *(ks.Value.(*map[string]interface{}))
-		i++
-		if i == 1 {
-			firstTitle = strings.Replace(k2["title"].(string), "\n", "", -1)
-			lastInfoDate = k2["publishtime"].(int64)
-		}
-		str += "<div class='tslist'><span class='xh'>" + fmt.Sprintf("%d", i) + ".</span><a class='bt' target='_blank' href='" + k2["href"].(string) + "'>" + strings.Replace(k2["title"].(string), "\n", "", -1) + "</a></div>"
-		publishTimes[strconv.Itoa(i)] = k2["publishtime"]
-
-		if i >= MaxPushSize {
-			//限制最大信息条数
-			break
-		}
-
-	}
-	TITLE := TITLEA + fmt.Sprintf("%d条,关键词(%s)", i, strings.Join(k.Interest, ";"))
-	WXTitle := fmt.Sprintf("%s《%s》%s", func() string {
-		minute := now.Unix() - lastInfoDate
-		if minute > -1 && minute < 61 {
-			return fmt.Sprintf("%d秒前发布的", minute)
-		} else {
-			minute = minute / 60
-			if minute > 121 {
-				return ""
-			} else {
-				if minute < 1 {
-					minute = 1
-				}
-				return fmt.Sprintf("%d分钟前发布的", minute)
-			}
-		}
-	}(), firstTitle, func() string {
-		if i == 1 {
-			return ""
-		} else {
-			return "等" + strconv.Itoa(i) + "条"
-		}
-	}())
-
-	//发送微信
-	if len(k.Openid) > 0 {
-		sendWeixin(k, TITLE, str, nowtime, "", now, "", WXTitle, publishTimes)
-	}
-
-}
-
-//推送微信
-func sendWeixin(k *push.MemberInterest, TITLE, str, nowtime, wxstr string, now time.Time, msgid, WXTitle string, publishTimes map[string]interface{}) {
-	defer func() {
-		if r := recover(); r != nil {
-			fmt.Println("发送微信[E]", r)
-		}
-	}()
-	time.Sleep(time.Millisecond * 100)
-	//详情存库
-	wxpush := map[string]interface{}{
-		"s_m_openid":    k.Openid,
-		"l_date":        now.Unix(),
-		"s_words":       k.Interest,
-		"s_email":       k.Email,
-		"s_uid":         k.Id,
-		"s_province":    k.Province,
-		"a_interest":    k.Interest,
-		"s_content":     str,
-		"s_type":        "bid",
-		"a_publishtime": publishTimes,
-		"i_size":        len(publishTimes),
-	}
-	wid := mongodb.Save("wxpush", &wxpush)
-	wxstr = "\n点击下方“详情”查看详细信息。\n以上中标信息,是剑鱼根据关键字“" + strings.Join(k.Interest, ";") + "”奋力查找并推送,如不合您心意,请猛戳企明星菜单“会员服务—剑鱼”进行修改。"
-
-	wxDate := ""
-	if k.InterestDate > 0 {
-		mt1 := interface{}(k.InterestDate)
-		wxDate = util.FormatDateWithObj(&mt1, util.Date_Full_Layout)
-	} else {
-		r := rand.New(rand.NewSource(time.Now().UnixNano()))
-		n1 := r.Int63n(9)
-		n2 := r.Int63n(7200)
-		wxDate = time.Now().Local().Add(time.Duration(-n2) * time.Second).Add(time.Duration(-n1*24) * time.Hour).Format(util.Date_Full_Layout)
-	}
-
-	push.SendWinXin(&qrpc.NotifyMsg{
-		Openid:  k.Openid,
-		Title:   push.PushConfig["bidTitle"].(string),
-		Remark:  wxstr,
-		Detail:  WXTitle,
-		Date:    wxDate,
-		Service: "剑鱼君",
-		Url:     push.PushConfig["bidViewDomain"].(string) + "/wxpush/bid/" + k.Openid + "/" + wid + "/a"})
-
-}
-
-//执行日常招标中标公告的消息推送
+//执行日常招标的消息推送
 func (b *BidPushJob) Execute() bool {
-	log.Println("开始执行中标任务:", push.PushConfig["bidStartTime"])
-	push.InitCache("bid")
-	b.createUserInterestWord()
-	b.eachAllBidInfo()
-	return false
+	pj := dopush.Pjob{
+		MaxPushSize: MaxPushSize,
+		Stype:       "bid",
+		StypeName:   "中标",
+	}
+	st, _ := time.ParseInLocation(util.Date_Full_Layout, push.PushConfig["bidStartTime"].(string), time.Local)
+	return pj.DoPush("", push.PushConfig["bidStartTime"].(string), 1, st.Unix())
 }

+ 25 - 35
push/src/qfw/push/cache.go

@@ -14,36 +14,32 @@ import (
 )
 
 type MemberInterest struct {
-	Id          string   //mongoid
-	Province    string   //省份
-	ProvinceVal uint64   //可选多个省份的处理
-	Interest    []string //用户兴趣
-	//Type     string   //兴趣类型
-	//SendMode     []string //发送方式
-	Unionid      string
+	Id           string   //mongoid
+	Province     string   //省份
+	ProvinceVal  uint64   //可选多个省份的处理
+	Interest     []string //用户兴趣
 	Openid       string
-	Email        string
 	InterestDate int64
 }
 
-var Cache map[string]*[]*MemberInterest //缓存
 //初始化缓存,在每次执行任务时调用,
-//加载用户数据到Cache中
-func InitCache(flag string) {
-	Cache = make(map[string]*[]*MemberInterest)
-	//TODO 查Mogo数据库
-	fixPush := util.ObjToString(PushConfig["fixPush"])
+func InitCache(flag, m_openid string) map[string]*[]*MemberInterest {
+	cache := make(map[string]*[]*MemberInterest)
 	q := map[string]interface{}{}
-	if len(fixPush) > 5 {
-		log.Println("推指定的人", fixPush)
-		q["s_m_openid"] = map[string]interface{}{
-			"$in": strings.Split(fixPush, ","),
-		}
+	if m_openid != "" {
+		q["s_m_openid"] = m_openid
 	} else {
-		q = map[string]interface{}{
-			"o_msgset." + flag: map[string]interface{}{
-				"$exists": true,
-			},
+		fixPush := util.ObjToString(PushConfig["fixPush"])
+		if len(fixPush) > 5 {
+			log.Println("推指定的人", fixPush)
+			q["s_m_openid"] = map[string]interface{}{
+				"$in": strings.Split(fixPush, ","),
+			}
+		} else {
+			q = map[string]interface{}{
+				"o_msgset." + flag + ".i_switchstatus": 1,
+				"o_msgset." + flag + ".i_status":       1,
+			}
 		}
 	}
 	session := mongodb.GetMgoConn()
@@ -52,9 +48,7 @@ func InitCache(flag string) {
 		"_id":                   1,
 		"o_msgset." + flag:      1,
 		"o_msgset.l_modifydate": 1,
-		"s_unionid":             1,
 		"s_m_openid":            1,
-		"s_email":               1,
 	}).Iter()
 	for tmp := make(map[string]interface{}); query.Next(tmp); {
 		util.Try(func() {
@@ -62,18 +56,14 @@ func InitCache(flag string) {
 			o_msgset := tmp["o_msgset"].(map[string]interface{})
 			flagModule := o_msgset[flag].(map[string]interface{})
 			a_key := util.ObjArrToStringArr(flagModule["a_key"].([]interface{}))
-			//a_mode := util.ObjArrToStringArr(flagModule["a_mode"].([]interface{}))
 			s_scope := util.ObjToString(flagModule["s_scope"])
 			if len(a_key) > 0 && len(s_scope) > 0 {
 				user := MemberInterest{
-					Id: _id,
-					//SendMode:    a_mode,
+					Id:          _id,
 					Province:    s_scope,
 					ProvinceVal: GetChoiceCode(strings.Split(s_scope, ",")...),
 					Interest:    a_key,
-					Unionid:     util.ObjToString(tmp["s_unionid"]),
 					Openid:      util.ObjToString(tmp["s_m_openid"]),
-					Email:       util.ObjToString(tmp["s_email"]),
 				}
 				date := o_msgset["l_modifydate"]
 				if date != nil {
@@ -83,12 +73,12 @@ func InitCache(flag string) {
 				}
 				for i := 0; i < len(a_key) && a_key[i] != ""; i++ {
 					var arr []*MemberInterest
-					if nil == Cache[a_key[i]] {
+					if nil == cache[a_key[i]] {
 						arr = make([]*MemberInterest, 0)
-						Cache[a_key[i]] = &arr
+						cache[a_key[i]] = &arr
 					} else {
-						arr = *Cache[a_key[i]]
-						Cache[a_key[i]] = &arr
+						arr = *cache[a_key[i]]
+						cache[a_key[i]] = &arr
 					}
 					arr = append(arr, &user)
 				}
@@ -97,8 +87,8 @@ func InitCache(flag string) {
 			log.Println(e)
 		})
 		tmp = make(map[string]interface{})
-		//log.Println(_id, o_msgset)
 	}
+	return cache
 }
 
 //各省份排序,最终会占某个2进制位

+ 16 - 0
push/src/qfw/push/dfa/interestanalysis_test.go

@@ -27,3 +27,19 @@ func TestAnaly(t *testing.T) {
 	//log.Println(d.Analy("这是胡锦涛写给江泽民的信啊。"))
 
 }
+
+func Test_Label(t *testing.T) {
+	log.Println("000----")
+
+	for _, v := range []int{1, 2, 3, 4, 5} {
+		log.Println(v)
+	L1:
+		for _, vv := range []string{"a", "b", "c", "d"} {
+			log.Println(vv)
+			if vv == "add" {
+				break L1
+			}
+		}
+	}
+	log.Println("111----")
+}

+ 221 - 0
push/src/qfw/push/dopush/dopush.go

@@ -0,0 +1,221 @@
+package dopush
+
+import (
+	"container/list"
+	"fmt"
+	"log"
+	"math/rand"
+	"qfw/push"
+	"qfw/push/dfa"
+	"qfw/util"
+	"qfw/util/mongodb"
+	qrpc "qfw/util/rpc"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type Pjob struct {
+	Dfa         *dfa.DFA
+	Cache       *map[string]*[]*push.MemberInterest
+	MaxPushSize int
+	Stype       string
+	StypeName   string
+}
+
+//构造用户兴趣词库
+func (b *Pjob) CreateUserInterestWord() {
+	b.Dfa = &dfa.DFA{}
+	words := make([]string, 0)
+	for k, _ := range *b.Cache {
+		words = append(words, k)
+	}
+	b.Dfa.AddWord(words...)
+}
+
+func (p *Pjob) DoPush(mopenid, stime string, opr int, ltime int64) bool {
+	log.Println("开始执行任务:", p.StypeName, stime)
+	p.Cache = new(map[string]*[]*push.MemberInterest)
+	*p.Cache = push.InitCache(p.Stype, mopenid)
+	p.CreateUserInterestWord()
+	EachAllBidInfo(p.Stype, "["+p.StypeName+"信息]", p.StypeName, ltime, p.MaxPushSize, p.Dfa, p.Cache, opr)
+	return false
+}
+
+//遍历数据并执行推送操作
+func EachAllBidInfo(stype, TITLEA, ShortTitle string, lastTime int64, MaxPushSize int, dfas *dfa.DFA, cache *map[string]*[]*push.MemberInterest, pushType int) {
+	defer func() {
+		if r := recover(); r != nil {
+			fmt.Println("推送开始[E]", r)
+		}
+	}()
+	session := mongodb.GetMgoConn()
+	defer mongodb.DestoryMongoConn(session)
+	q := `{"comeintime":{"$gt":` + fmt.Sprintf("%d", lastTime) + `},"type":"` + stype + `"}`
+	n, _ := session.DB("qfw").C("bidding").Find(mongodb.ObjToOth(q)).Count()
+	if n == 0 {
+		log.Println("执行推送任务", stype, "没有数据。")
+		return
+	}
+	query := session.DB("qfw").C("bidding").Find(mongodb.ObjToOth(q)).Sort("-publishtime").Iter()
+	userMap := &map[*push.MemberInterest]*list.List{}
+	var returnLastTime interface{}
+L1:
+	for tmp := new(map[string]interface{}); query.Next(tmp); {
+		title := util.ObjToString((*tmp)["title"])
+		if title != "" {
+			//返回匹配到的词组
+			res := dfas.Analy(title)
+			if len(res) > 0 {
+				province := (*tmp)["area"].(string)
+				provinceVal := push.GetChoiceCode(province)
+				for _, v := range res {
+					//根据关键词返回用户指针
+					tw := (*cache)[v]
+					if tw != nil {
+						//遍历用户加入到此条信息上
+						for _, v2 := range *tw {
+							if v2.Province == "A" || v2.ProvinceVal&provinceVal > 0 {
+								s := (*userMap)[v2]
+								if s == nil {
+									s = list.New()
+									(*userMap)[v2] = s
+								}
+								s.PushBack(tmp)
+								if pushType == 2 && s.Len() > MaxPushSize {
+									break L1
+								}
+							}
+						}
+					}
+				}
+			}
+			if returnLastTime == nil {
+				returnLastTime = (*tmp)["comeintime"]
+			}
+		}
+		tmp = new(map[string]interface{})
+	}
+	now := time.Now()
+	if pushType == 1 && returnLastTime != nil {
+		push.PushConfig[stype+"rStartTime"] = util.FormatDateWithObj(&returnLastTime, util.Date_Full_Layout)
+	}
+	for k, v := range *(userMap) {
+		kk := *k
+		vv := *v
+		time.Sleep(50 * time.Millisecond)
+		go Send(&kk, &vv, now, TITLEA, ShortTitle, MaxPushSize)
+	}
+}
+
+//全局推送功能
+func Send(k *push.MemberInterest, v *list.List, now time.Time, TITLEA, ShortTitle string, MaxPushSize int) {
+	defer func() {
+		if r := recover(); r != nil {
+			log.Println("[E]", r)
+			for skip := 1; ; skip++ {
+				_, file, line, ok := runtime.Caller(skip)
+				if !ok {
+					break
+				}
+				go log.Printf("%v,%v\n", file, line)
+			}
+		}
+	}()
+	str := fmt.Sprintf("<div>根据您设置的关键词(%s),给您推送以下信息:</div>", strings.Join(k.Interest, ";"))
+	//发送内容组合
+	i := 0
+	lastInfoDate := int64(0)
+	firstTitle := ""
+	publishTimes := map[string]interface{}{}
+	for ks := v.Front(); ks != nil; ks = ks.Next() {
+		k2 := *(ks.Value.(*map[string]interface{}))
+		i++
+		if i == 1 {
+			firstTitle = strings.Replace(k2["title"].(string), "\n", "", -1)
+			lastInfoDate = k2["publishtime"].(int64)
+		}
+		str += "<div class='tslist'><span class='xh'>" + fmt.Sprintf("%d", i) + ".</span><a class='bt' target='_blank' href='" + k2["href"].(string) + "'>" + strings.Replace(k2["title"].(string), "\n", "", -1) + "</a></div>"
+		publishTimes[strconv.Itoa(i)] = k2["publishtime"]
+		if i >= MaxPushSize {
+			//限制最大信息条数
+			break
+		}
+
+	}
+	TITLE := TITLEA + fmt.Sprintf("%d条,关键词(%s)", i, strings.Join(k.Interest, ";"))
+	WXTitle := fmt.Sprintf("%s《%s》%s", func() string {
+		minute := now.Unix() - lastInfoDate
+		if minute > -1 && minute < 61 {
+			return fmt.Sprintf("%d秒前发布的", minute)
+		} else {
+			minute = minute / 60
+			if minute > 121 {
+				return ""
+			} else {
+				if minute < 1 {
+					minute = 1
+				}
+				return fmt.Sprintf("%d分钟前发布的", minute)
+			}
+		}
+	}(), firstTitle, func() string {
+		if i == 1 {
+			return ""
+		} else {
+			return "等" + strconv.Itoa(i) + "条"
+		}
+	}())
+
+	//3、发送微信
+	if len(k.Openid) > 0 {
+		SendWeixin(k, TITLE, ShortTitle, str, "", now, WXTitle, publishTimes)
+	}
+
+}
+
+//推送微信
+func SendWeixin(k *push.MemberInterest, TITLE, ShortTitle, str, wxstr string, now time.Time, WXTitle string, publishTimes map[string]interface{}) {
+	defer func() {
+		if r := recover(); r != nil {
+			fmt.Println("发送微信[E]", r)
+		}
+	}()
+	time.Sleep(time.Millisecond * 100)
+	//详情存库
+	wxpush := map[string]interface{}{
+		"s_m_openid":    k.Openid,
+		"l_date":        now.Unix(),
+		"s_words":       k.Interest,
+		"s_uid":         k.Id,
+		"s_province":    k.Province,
+		"a_interest":    k.Interest,
+		"s_content":     str,
+		"s_type":        "tender",
+		"a_publishtime": publishTimes,
+		"i_size":        len(publishTimes),
+	}
+	wid := mongodb.Save("wxpush", &wxpush)
+	wxDate := ""
+	if k.InterestDate > 0 {
+		mt1 := interface{}(k.InterestDate)
+		wxDate = util.FormatDateWithObj(&mt1, util.Date_Full_Layout)
+	} else {
+		r := rand.New(rand.NewSource(time.Now().UnixNano()))
+		n1 := r.Int63n(9)
+		n2 := r.Int63n(7200)
+		wxDate = time.Now().Local().Add(time.Duration(-n2) * time.Second).Add(time.Duration(-n1*24) * time.Hour).Format(util.Date_Full_Layout)
+	}
+
+	wxstr = "\n点击下方“详情”查看详细信息。\n以上" + ShortTitle + "信息,是剑鱼根据关键字“" + strings.Join(k.Interest, ";") + "”奋力查找并推送,如不合您心意,请猛戳企明星菜单“会员服务—剑鱼”进行修改。"
+	push.SendWinXin(&qrpc.NotifyMsg{
+		Openid:  k.Openid,
+		Title:   push.PushConfig["tenderTitle"].(string),
+		Remark:  wxstr,
+		Detail:  WXTitle,
+		Date:    wxDate,
+		Service: "剑鱼君",
+		Url:     push.PushConfig["bidViewDomain"].(string) + "/wxpush/bid/" + k.Openid + "/" + wid + "/aa"})
+
+}

+ 29 - 0
push/src/qfw/push/rpcpush/rpcpush.go

@@ -0,0 +1,29 @@
+package rpcpush
+
+import (
+	"fmt"
+	"qfw/push/bid"
+	"qfw/push/dopush"
+	qrpc "qfw/util/rpc"
+	"time"
+)
+
+type PushInfo struct {
+}
+
+var PushInfoScopeDays int
+
+func (p *PushInfo) PushMsg(data *qrpc.PushData, Reply *int) error {
+	for k, v := range data.PushType {
+		//昨天到今天的数据
+		pj := dopush.Pjob{
+			MaxPushSize: bid.MaxPushSize,
+			Stype:       k,
+			StypeName:   v,
+		}
+		now := time.Now()
+		tom := time.Date(now.Year(), now.Month(), now.Day()-PushInfoScopeDays, 0, 0, 0, 0, time.Local)
+		pj.DoPush(data.Mopenid, fmt.Sprintf("%d days", PushInfoScopeDays), 2, tom.Unix())
+	}
+	return nil
+}

+ 9 - 212
push/src/qfw/push/tender/tenderpushjob.go

@@ -1,227 +1,24 @@
-/**
- *招标,中标公告的推送消息,在兴趣词分析上,存在一定的难度
- *现在采用DFA算法分析,兴趣词会构造Map结构,前期应该不会出问题。
- *后期需要改进(用户量达到5千以上)
- *可行策略:每日产生的新数据有限,大概不超过5000条,可以把标题全加到内存
- *        用户兴趣词分批次加入,每次加入3000个左右的用户的兴趣词,过滤
- *        今日产生的招标、中标数据,并完成推送,第二批载入后3000个用户的数据
- */
 package tender
 
 import (
-	"container/list"
-	"fmt"
-	"log"
-	"math/rand"
 	"qfw/push"
-	"qfw/push/dfa"
+	"qfw/push/dopush"
 	"qfw/util"
-	"qfw/util/mongodb"
-	qrpc "qfw/util/rpc"
-	"runtime"
-	"strconv"
-	"strings"
 	"time"
 )
 
 type TenderPushJob struct {
-	dfa *dfa.DFA
 }
 
-//构造用户兴趣词库
-func (b *TenderPushJob) createUserInterestWord() {
-	b.dfa = &dfa.DFA{}
-	words := make([]string, 0)
-	for k, _ := range push.Cache {
-		words = append(words, k)
-	}
-	b.dfa.AddWord(words...)
-}
-
-var TITLEA string = "[招标信息]" //tender
 var MaxPushSize int
 
-//遍历查到的
-func (b *TenderPushJob) eachAllBidInfo() {
-	defer func() {
-		if r := recover(); r != nil {
-			fmt.Println("推送开始[E]", r)
-		}
-	}()
-	session := mongodb.GetMgoConn()
-	defer mongodb.DestoryMongoConn(session)
-	startTime := push.PushConfig["tenderStartTime"].(string)
-	st, _ := time.ParseInLocation(util.Date_Full_Layout, startTime, time.Local)
-	q := `{"comeintime":{"$gt":` + fmt.Sprintf("%d", st.Unix()) + `},"type":"tender"}`
-	n, _ := session.DB("qfw").C("bidding").Find(mongodb.ObjToOth(q)).Count()
-	log.Println(q, "查询推送信息:", n, ",时间", startTime)
-	if n == 0 {
-		//没有查询到结果
-		return
-	}
-	query := session.DB("qfw").C("bidding").Find(mongodb.ObjToOth(q)).Sort("-publishtime").Iter()
-	userMap := &map[*push.MemberInterest]*list.List{}
-	for tmp := new(map[string]interface{}); query.Next(tmp); {
-		title := util.ObjToString((*tmp)["title"])
-		if title != "" {
-			//返回匹配到的词组
-			res := b.dfa.Analy(title)
-			if len(res) > 0 {
-				province := (*tmp)["area"].(string)
-				provinceVal := push.GetChoiceCode(province)
-				for _, v := range res {
-					//根据关键词返回用户指针
-					tw := push.Cache[v]
-					if tw != nil {
-						//遍历用户加入到此条信息上
-						for _, v2 := range *tw {
-							if v2.Province == "A" || v2.ProvinceVal&provinceVal > 0 {
-								s := (*userMap)[v2]
-								if s == nil {
-									s = list.New()
-									(*userMap)[v2] = s
-								}
-								s.PushBack(tmp)
-							}
-						}
-					}
-				}
-			}
-		}
-		tmp = new(map[string]interface{})
-	}
-	now := time.Now()
-	nowtime := util.FormatDate(&now, util.Date_Full_Layout)
-	//更改开始时间
-	push.PushConfig["tenderStartTime"] = nowtime
-	//date := util.FormatDate(&now, util.Date_Short_Layout)
-	for k, v := range *(userMap) {
-		kk := *k
-		vv := *v
-
-		time.Sleep(50 * time.Millisecond)
-		go send(&kk, &vv, now, nowtime)
-	}
-}
-
-func send(k *push.MemberInterest, v *list.List, now time.Time, nowtime string) {
-	defer func() {
-		if r := recover(); r != nil {
-			log.Println("[E]", r)
-			for skip := 1; ; skip++ {
-				_, file, line, ok := runtime.Caller(skip)
-				if !ok {
-					break
-				}
-				go log.Printf("%v,%v\n", file, line)
-			}
-		}
-	}()
-
-	//wxstr := ""
-	str := fmt.Sprintf("<div>根据您设置的关键词(%s),给您推送以下信息:</div>", strings.Join(k.Interest, ";"))
-	//发送内容组合
-	i := 0
-	lastInfoDate := int64(0)
-	firstTitle := ""
-	publishTimes := map[string]interface{}{}
-	for ks := v.Front(); ks != nil; ks = ks.Next() {
-		k2 := *(ks.Value.(*map[string]interface{}))
-		i++
-		if i == 1 {
-			firstTitle = strings.Replace(k2["title"].(string), "\n", "", -1)
-			lastInfoDate = k2["publishtime"].(int64)
-		}
-		str += "<div class='tslist'><span class='xh'>" + fmt.Sprintf("%d", i) + ".</span><a class='bt' target='_blank' href='" + k2["href"].(string) + "'>" + strings.Replace(k2["title"].(string), "\n", "", -1) + "</a></div>"
-		publishTimes[strconv.Itoa(i)] = k2["publishtime"]
-		if i >= MaxPushSize {
-			//限制最大信息条数
-			break
-		}
-
-	}
-	TITLE := TITLEA + fmt.Sprintf("%d条,关键词(%s)", i, strings.Join(k.Interest, ";"))
-	WXTitle := fmt.Sprintf("%s《%s》%s", func() string {
-		minute := now.Unix() - lastInfoDate
-		if minute > -1 && minute < 61 {
-			return fmt.Sprintf("%d秒前发布的", minute)
-		} else {
-			minute = minute / 60
-			if minute > 121 {
-				return ""
-			} else {
-				if minute < 1 {
-					minute = 1
-				}
-				return fmt.Sprintf("%d分钟前发布的", minute)
-			}
-		}
-	}(), firstTitle, func() string {
-		if i == 1 {
-			return ""
-		} else {
-			return "等" + strconv.Itoa(i) + "条"
-		}
-	}())
-
-	//3、发送微信
-	if len(k.Openid) > 0 {
-		sendWeixin(k, TITLE, str, nowtime, "", now, "", WXTitle, publishTimes)
-	}
-
-}
-
-//推送微信
-func sendWeixin(k *push.MemberInterest, TITLE, str, nowtime, wxstr string, now time.Time, msgid, WXTitle string, publishTimes map[string]interface{}) {
-	defer func() {
-		if r := recover(); r != nil {
-			fmt.Println("发送微信[E]", r)
-		}
-	}()
-	time.Sleep(time.Millisecond * 100)
-	//详情存库
-	wxpush := map[string]interface{}{
-		"s_m_openid":    k.Openid,
-		"l_date":        now.Unix(),
-		"s_words":       k.Interest,
-		"s_email":       k.Email,
-		"s_uid":         k.Id,
-		"s_province":    k.Province,
-		"a_interest":    k.Interest,
-		"s_content":     str,
-		"s_type":        "tender",
-		"a_publishtime": publishTimes,
-		"i_size":        len(publishTimes),
-	}
-	wid := mongodb.Save("wxpush", &wxpush)
-	wxDate := ""
-	if k.InterestDate > 0 {
-		mt1 := interface{}(k.InterestDate)
-		wxDate = util.FormatDateWithObj(&mt1, util.Date_Full_Layout)
-	} else {
-		r := rand.New(rand.NewSource(time.Now().UnixNano()))
-		n1 := r.Int63n(9)
-		n2 := r.Int63n(7200)
-		wxDate = time.Now().Local().Add(time.Duration(-n2) * time.Second).Add(time.Duration(-n1*24) * time.Hour).Format(util.Date_Full_Layout)
-	}
-
-	wxstr = "\n点击下方“详情”查看详细信息。\n以上招标信息,是剑鱼根据关键字“" + strings.Join(k.Interest, ";") + "”奋力查找并推送,如不合您心意,请猛戳企明星菜单“会员服务—剑鱼”进行修改。"
-	push.SendWinXin(&qrpc.NotifyMsg{
-		Openid:  k.Openid,
-		Title:   push.PushConfig["tenderTitle"].(string),
-		Remark:  wxstr,
-		Detail:  WXTitle,
-		Date:    wxDate,
-		Service: "剑鱼君",
-		Url:     push.PushConfig["bidViewDomain"].(string) + "/wxpush/bid/" + k.Openid + "/" + wid + "/aa"})
-
-}
-
-//执行日常招标中标公告的消息推送
+//执行日常招标的消息推送
 func (b *TenderPushJob) Execute() bool {
-	log.Println("开始执行招标任务:", push.PushConfig["tenderStartTime"])
-	push.InitCache("tender")
-	b.createUserInterestWord()
-	b.eachAllBidInfo()
-	return false
+	pj := dopush.Pjob{
+		MaxPushSize: MaxPushSize,
+		Stype:       "tender",
+		StypeName:   "招标",
+	}
+	st, _ := time.ParseInLocation(util.Date_Full_Layout, push.PushConfig["tenderStartTime"].(string), time.Local)
+	return pj.DoPush("", push.PushConfig["tenderStartTime"].(string), 1, st.Unix())
 }