Sfoglia il codice sorgente

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

李广朋 9 anni fa
parent
commit
0d6cf71f23
32 ha cambiato i file con 839 aggiunte e 104 eliminazioni
  1. 4 4
      common/src/qfw/util/encrypt_test.go
  2. 8 8
      core/src/luckdraw.json
  3. 88 21
      core/src/qfw/active/activemanage.go
  4. 1 1
      core/src/qfw/member/memberindex.go
  5. 3 1
      core/src/qfw/mobile/wxmenu.go
  6. 1 1
      core/src/qfw/swordfish/swordfishmanage.go
  7. 1 1
      core/src/timetask.json
  8. 1 0
      core/src/web/staticres/css/dev-qfw.css
  9. 9 4
      core/src/web/staticres/css/entcommunity.css
  10. BIN
      core/src/web/staticres/images/activeimages/lotteryBg.jpg
  11. 33 20
      core/src/web/staticres/js/entportrait.js
  12. 3 3
      core/src/web/staticres/js/qfw.js
  13. BIN
      core/src/web/staticres/wxswordfish/images/share-cj.jpg
  14. BIN
      core/src/web/staticres/wxswordfish/images/share-cj.png
  15. 10 3
      core/src/web/staticres/wxswordfish/main.js
  16. 21 0
      core/src/web/staticres/wxswordfish/share.js
  17. 1 1
      core/src/web/staticres/wxswordfish/style.css
  18. 1 1
      core/src/web/templates/active/luckdraw.html
  19. 2 0
      core/src/web/templates/swordfish/protocol.html
  20. 5 1
      core/src/web/templates/swordfish/protocoltxt.html
  21. 6 2
      core/src/web/templates/swordfish/rssset.html
  22. 13 0
      core/src/web/templates/swordfish/wxprotocol.html
  23. 3 7
      core/src/web/templates/swordfish/wxrssset.html
  24. 18 10
      core/src/web/templates/swordfish/wxshare.html
  25. 6 1
      core/src/web/templates/swordfish/wxtoolbar.html
  26. 22 6
      core/src/web/templates/yellowpage/enterpriseinfo.html
  27. 3 1
      credit/src/config.json
  28. 1 1
      push/src/qfw/push/dopush/dopush.go
  29. 6 0
      weixin/src/endless/doc.go
  30. 560 0
      weixin/src/endless/endless.go
  31. 4 4
      weixin/src/main.go
  32. 5 2
      weixin/src/qfw/weixin/msgtxtchandler.go

+ 4 - 4
common/src/qfw/util/encrypt_test.go

@@ -22,10 +22,10 @@ func Test_sim(t *testing.T) {
 	//s2 := "GyUlIhEDDjcfWCAyIl4xBkgsERYiLAwZLCg9VkkbLj4zMRYDPRs5ATVZOxccPAkzFxw7CCpEFj41QlRAQFdFXlRMQVZcHRIbBgsWBxYcFQwEBwoa"
 
 	//s3 := "RFYoal5bCFdXWQoQB0JuWwlXAQFZCUVfFj4JMFtT"
-	s4 := "oJULtwzXo6EFV1Ah-XeyRBimXGM8,uid,123456,swordfishaction"
+	s4 := "oJULtwzXo6EFV//////??????----oJULtwzXsLVHoDeXBEWOXCkME9p4,oZQC_s_DfLpFKIKIP2TpiR-16Glg,1453788982,swordfishaction--1Ah-Xey,_R_B/i?mXGM8,uid,123456,swordfishaction"
 	se := SimpleEncrypt{Key: "topnet"}
-	log.Println(se.EncodeString(s4))
-	log.Println(se.DecodeString("GyUlIhEDDjcfWCAyIl4xBkgsERYiLAwZLCg9VkkSEkMWCEkHAwACCgMdBwcRDREdGwE=566666666666666"))
+	log.Println("=====", se.EncodeString(s4))
+	log.Println("---", se.DecodeString("GyUlIhEDDjcDIjM8GysVNicxIyAoLQ45MVYAWkkbLj4zMRYrMAk8HiM/PSQ5PlcgBAYiQ1RCMwMXQlRAQVxHVl1NTF1cHRIbBgsWBxYcFQwEBwoa"))
 	now := time.Now()
 	tom := time.Date(now.Year(), now.Month(), now.Day(), 18, 0, 0, 0, time.Local)
 	log.Println(now.Unix(), tom.Unix(), 1453686600-1453716000)
@@ -67,6 +67,6 @@ func Test_int(t *testing.T) {
 
 func TestActivity(t *testing.T) {
 	se := SimpleEncrypt{Key: "topnet2015topnet2015"}
-	tmp := se.EncodeString("oZQC_s7VTU3p9SrhU27gA5v2MDk0")
+	tmp := se.EncodeString("obEpLuPmkfICwGUh8U3nwN_UK3qY")
 	log.Println(tmp, se.DecodeString(tmp))
 }

+ 8 - 8
core/src/luckdraw.json

@@ -1,6 +1,6 @@
 {
 	"startDate":1452750000,
-	"endDate":1454256000,
+	"endDate":1455552000,
 	"getAmount":[{
 		"min":0,
 		"max":40,
@@ -8,31 +8,31 @@
 	},{
 		"min":50,
 		"max":85,
-		"proportion":24.2
+		"proportion":37.21
 	},{
 		"min":95,
 		"max":130,
-		"proportion":1
+		"proportion":0.5
 	},{
 		"min":140,
 		"max":175,
-		"proportion":24.2
+		"proportion":20
 	},{
 		"min":185,
 		"max":220,
-		"proportion":2
+		"proportion":1
 	},{
 		"min":230,
 		"max":265,
-		"proportion":24.2
+		"proportion":37.21
 	},{
 		"min":275,
 		"max":310,
-		"proportion":0.3
+		"proportion":0.08
 	},{
 		"min":320,
 		"max":355,
-		"proportion":24.1
+		"proportion":4
 	}],
 	"promotioncode":"2001001501",
 	"weixin":{

+ 88 - 21
core/src/qfw/active/activemanage.go

@@ -12,7 +12,9 @@ import (
 	"qfw/coreutil"
 	mob "qfw/mobile"
 	. "qfw/util"
+	"qfw/util/credit"
 	. "qfw/util/mongodb"
+	"qfw/util/redis"
 	qrpc "qfw/util/rpc"
 	"strconv"
 	"time"
@@ -22,6 +24,23 @@ type Activemanage struct {
 	*xweb.Action
 	luckdraw    xweb.Mapper `xweb:"/activity/(\\w+)/([^.]*)"`
 	getluckdraw xweb.Mapper `xweb:"/activity/luckdraw"`
+	addredis    xweb.Mapper `xweb:"/activity/addredis"`
+}
+
+//分享成功后建立redis判断值
+func (a *Activemanage) Addredis() error {
+	//
+	openid := a.Session().Get("openid").(string)
+	n := time.Now()
+	tmp := n.Unix()
+	n2 := n.AddDate(0, 0, 1)
+	yxq := time.Date(n2.Year(), n2.Month(), n2.Day(), 23, 59, 59, 0, time.Local).Unix() - tmp
+	yxqs := fmt.Sprintf("%d", yxq)
+	yxqt, _ := strconv.Atoi(yxqs)
+	key := fmt.Sprintf("cj_%s_%s", openid, n2.Format("2006_01_02"))
+	redis.Put("other", key, "cj", yxqt)
+
+	return nil
 }
 
 //进入抽奖页面
@@ -32,7 +51,6 @@ func (a *Activemanage) Luckdraw(activecode, id string) error {
 	a.T["shareid"] = coreutil.FindMyShareId(activecode, openid)
 	//
 	if activecode == "topcj" {
-
 		f := FindOne("user", "{'s_m_openid':'"+openid+"'}")
 		username := (*f)["s_bindweixin"]
 		userid := (*f)["_id"]
@@ -44,10 +62,17 @@ func (a *Activemanage) Luckdraw(activecode, id string) error {
 		a.T["signature"] = mob.GetSignature(a.Url())
 		u := FindOne("winningrecord", "{'s_openid':'"+openid+"'}")
 		if *u != nil {
-			//a.T = *u
-			a.T["flog"] = "A"
-			a.T["msg"] = "小主莫贪心,每人只有一次抽奖机会呦!<br/><br/>  小主翻个牌子,动动小手分享活动,么么哒……(分享点击页面右上方···分享到朋友圈)"
-			return a.Render("/active/luckdraw.html", &a.T)
+			if ret := redis.Get("other", "cj_"+openid+"_"+time.Now().Format("2006_01_02")); ret == nil {
+				//a.T = *u
+				a.T["flog"] = "A"
+				Tm := time.Now().AddDate(0, 0, 1)
+				if ret := redis.Get("other", "cj_"+openid+"_"+Tm.Format("2006_01_02")); ret == nil {
+					a.T["msg"] = "小主,快分享朋友圈或好友即获得明天的抽奖资格吧!千万不要再忘记了,大奖可能就在明天~"
+				} else {
+					a.T["msg"] = "小主莫贪心,每人每天只有一次抽奖机会呦!分享后明天再来吧!<br/><br/>  小主翻个牌子,动动小手分享活动,么么哒……(分享点击页面右上方···分享到朋友圈)"
+				}
+				return a.Render("/active/luckdraw.html", &a.T)
+			}
 		}
 		a.SetSession("username", username)
 		a.SetSession("userid", userid)
@@ -74,9 +99,13 @@ func (a *Activemanage) Getluckdraw() error {
 	} else {
 		u := FindOne("winningrecord", "{'s_openid':'"+openid+"'}")
 		if *u != nil {
-			flog = "A"
-			msg = "  小主莫贪心,每人只有一次抽奖机会呦!<br/><br/>  小主翻个牌子,动动小手分享活动,么么哒……(分享点击页面右上方···分享到朋友圈)"
-			return a.Write(`{"flog":"` + flog + `","msg":"` + msg + `"}`)
+			if ret := redis.Get("other", "cj_"+openid+"_"+time.Now().Format("2006_01_02")); ret == nil {
+				//a.T = *u
+				a.T["flog"] = "A"
+				a.T["msg"] = "小主莫贪心,每天只有一次抽奖机会呦!分享至朋友圈或好友即可以获得明天抽奖资格呦!乖,快去分享吧!大奖可能就在明天~~"
+				return a.Write(`{"flog":"` + flog + `","msg":"` + msg + `"}`)
+			}
+			redis.Del("other", "cj_"+openid+"_"+time.Now().Format("2006_01_02"))
 		}
 	}
 	data := make(map[string]interface{})
@@ -95,8 +124,15 @@ func (a *Activemanage) Getluckdraw() error {
 	if len(id) > 0 {
 		flog = "T"
 	}
-	if i > 185 && i < 220 {
-		amount := 500 //红包金额以“元”为单位,微信红包以“分”为单位
+	//红包
+	if (i > 185 && i < 220) || (i > 320 && i < 355) {
+		var amount int //红包金额以“元”为单位,微信红包以“分”为单位
+		if i > 185 && i < 220 {
+			amount = 500 //红包金额以“元”为单位,微信红包以“分”为单位
+
+		} else if i > 320 && i < 355 {
+			amount = 100 //红包金额以“元”为单位,微信红包以“分”为单位
+		}
 		bm := qrpc.BonusMsg{Mchbillno: fmt.Sprint(today.Unix()),
 			Sendname:    LuckDraw.Weixin["sendname"].(string),
 			Reopenid:    openid,
@@ -121,22 +157,27 @@ func (a *Activemanage) Getluckdraw() error {
 			redpackage["s_actcode"] = s_actcode
 			Save("redpackage", redpackage)
 		}
-	}
-	if i > 185 && i < 220 {
-		msg = "  小主是真真的好运气,五元现金红包落入您囊中!<br/><br/>  小主翻个牌子,动动小手分享活动,么么哒……(分享点击页面右上方···分享到朋友圈)"
+		msg = "  小主是真真的好运气," + s_prize + "落入您囊中。红包将由系统自动发放到您的微信,请注意查收。<br/><br/>分享至朋友圈或好友即可以获得明天抽奖资格呦!乖,快去分享吧!大奖可能就在明天~~"
 	} else if (i > 275 && i < 310) || (i > 95 && i < 130) {
 		//时间判断,提醒不同
-		now := time.Now()
+		//now := time.Now()
 		//不在工作时间
-		if now.Weekday() == 6 || now.Weekday() == 0 || (now.Hour() > 18 || now.Hour() < 9) {
-			//
-			msg = "  小主是真真的好运气," + s_prize + "落入您囊中!<br/>  请在微信留下您的联系方式(手机号或qq号),企明星客服会在下一个工作日9:00-17:00给小主回复哦!<br/>  小主翻个牌子,动动小手分享活动,么么哒……(分享点击页面右上方···分享到朋友圈)"
-		} else { //在工作时间
-			msg = "  小主是真真的好运气," + s_prize + "落入您囊中,请速速微信联系企明星确认领奖事宜!<br/><br/>  小主翻个牌子,动动小手分享活动,么么哒……(分享点击页面右上方···分享到朋友圈)"
+		//if now.Weekday() == 6 || now.Weekday() == 0 || (now.Hour() > 18 || now.Hour() < 9) {
+		//
+		//	msg = "  小主是真真的好运气," + s_prize + "落入您囊中!<br/>  请在微信留下您的联系方式(手机号或qq号),企明星客服会在下一个工作日9:00-17:00给小主回复哦!<br/>  小主翻个牌子,动动小手分享活动,么么哒……(分享点击页面右上方···分享到朋友圈)"
+		//} else { //在工作时间
+		msg = "  小主是真真的好运气," + s_prize + "落入您囊中。请将您的联系方式和邮寄地址留言给企明星。我们会在活动截止后尽快为您发出。<br/><br/>分享至朋友圈或好友即可以获得明天抽奖资格呦!乖,快去分享吧!大奖可能就在明天~~"
+		//}
+	} else if i > 140 && i < 175 {
+		obid := BsonIdToSId(a.GetSession("userid"))
+		b := credit.UpuserCreditSession(obid, "b6", "B", nil, a.Action)
+		if b == true {
+			msg = "  小主是真真的好运气,200积分落入您囊中。积分将由系统自动发放到您的企明星账户,请登录www.qmx.top查看。<br/><br/>分享至朋友圈或好友即可以获得明天抽奖资格呦!乖,快去分享吧!大奖可能就在明天~~"
+		} else {
+			msg = "  抽奖出错!小主不要桑心,联系企明星管理员,200积分还是您的!"
 		}
-
 	} else { //不中奖
-		msg = "  小主不要桑心,这次没有中奖不代表什么,猴年依然会好运气爆棚滴~~<br/><br/>  小主翻个牌子,动动小手分享活动,么么哒……(分享点击页面右上方···分享到朋友圈)"
+		msg = "  小主不要桑心,这次没有中奖哦,明天记得要来拼运气啊!<br/><br/>分享至朋友圈或好友即可以获得明天抽奖资格呦!乖,快去分享吧!大奖可能就在明天~~"
 	}
 	return a.Write(`{"flog":"` + flog + `","msg":"` + msg + `","rotate":` + strconv.Itoa(int(i)) + `}`)
 
@@ -157,6 +198,26 @@ func getLuckDraw() int {
 		amount := min + rand.New(rand.NewSource(time.Now().UnixNano())).Intn(max-min)
 		if amount <= 0 {
 			return 1
+		} else if amount > 275 && amount < 310 {
+			count := Count("winningrecord", "{'s_prize':'《牛奶可乐经济学》'}")
+			if count > 6 {
+				amount = 240
+			}
+		} else if amount > 95 && amount < 130 {
+			count := Count("winningrecord", "{'s_prize':'限量版U盘'}")
+			if count > 100 {
+				amount = 260
+			}
+		} else if amount > 185 && amount < 220 {
+			count := Count("winningrecord", "{'s_prize':'五元现金红包'}")
+			if count > 200 {
+				amount = 60
+			}
+		} else if amount > 320 && amount < 355 {
+			count := Count("winningrecord", "{'s_prize':'一元现金红包'}")
+			if count > 1500 {
+				amount = 80
+			}
 		}
 		return amount
 	}
@@ -188,12 +249,18 @@ func getPrize(i int) string {
 		} else if 91 <= i && i < 136 {
 			prize = "限量版U盘"
 
+		} else if 140 <= i && i < 175 {
+			prize = "200积分"
+
 		} else if 181 <= i && i < 226 {
 			prize = "五元现金红包"
 
 		} else if 271 <= i && i < 316 {
 			prize = "《牛奶可乐经济学》"
 
+		} else if 320 <= i && i < 355 {
+			prize = "一元现金红包"
+
 		} else {
 			prize = "谢谢参与"
 		}

+ 1 - 1
core/src/qfw/member/memberindex.go

@@ -40,7 +40,7 @@ func init() {
 func (m *MemberIndex) Sess(str string) error {
 
 	util.Try(func() {
-		strs := strings.Split(str, "/")
+		strs := strings.Split(str, "##")
 		str := strings.Split(sewx.DecodeString(strs[0]), ",")
 		if len(str) == 4 {
 			openid := str[0]

+ 3 - 1
core/src/qfw/mobile/wxmenu.go

@@ -25,6 +25,7 @@ func init() {
 
 func (m *Mobile) Guide() error {
 	m.T["signature"] = GetSignature(m.Url())
+	m.T["shareid"] = cutil.FindMyShareId("topjy", m.Session().Get("s_m_openid").(string))
 	return m.Render("/swordfish/wxindex.html", &m.T)
 }
 func (m *Mobile) Share(shareid string) error {
@@ -78,7 +79,7 @@ func (m *Mobile) Wxrssset() error {
 			}
 			m.T["msgset"] = (*userInfo)["o_msgset"]
 			//取Shareid
-			m.T["shareid"] = cutil.FindMyShareId("topcj", m.Session().Get("s_m_openid").(string))
+			m.T["shareid"] = cutil.FindMyShareId("topjy", m.Session().Get("s_m_openid").(string))
 		}
 
 		return m.Render("/swordfish/wxrssset.html", &m.T)
@@ -331,6 +332,7 @@ func (m *Mobile) WxpushList(s_m_openid string, _id string, msgid string) error {
 	m.T["data"] = *mongodb.FindById("wxpush", _id, `{"s_content":1,"s_words":1,"a_visitedindex":1,"a_publishtime":1,"s_type":1}`)
 	m.T["_id"] = _id
 	m.T["signature"] = GetSignature(m.Url())
+	m.T["shareid"] = cutil.FindMyShareId("topjy", m.Session().Get("s_m_openid").(string))
 	return m.Render("/swordfish/wxpush.html", &m.T)
 }
 

+ 1 - 1
core/src/qfw/swordfish/swordfishmanage.go

@@ -64,7 +64,7 @@ func (s *SwordFish) Protocol() error {
 
 //剑鱼用户协议
 func (s *SwordFish) Wxprotocol() error {
-	return s.Render("/swordfish/protocoltxt.html")
+	return s.Render("/swordfish/wxprotocol.html")
 }
 
 //跳转到用户中心剑鱼信息列表

+ 1 - 1
core/src/timetask.json

@@ -1 +1 @@
-{"comment":{"c_rate":720,"commentrate":900},"market":{"demand":{"attr":["i_hits","i_bids","i_status"],"timepoint":"2016-01-25 16:16:21"},"service":{"attr":["i_hits","i_sales","i_comments","i_score","i_appcounts"],"timepoint":"2016-01-25 16:16:21"}},"marketisstart":true,"marketrate":300}
+{"comment":{"c_rate":720,"commentrate":900},"market":{"demand":{"attr":["i_hits","i_bids","i_status"],"timepoint":"2016-01-26 10:41:42"},"service":{"attr":["i_hits","i_sales","i_comments","i_score","i_appcounts"],"timepoint":"2016-01-26 10:41:42"}},"marketisstart":true,"marketrate":300}

+ 1 - 0
core/src/web/staticres/css/dev-qfw.css

@@ -33,6 +33,7 @@ a{
 }
 .font-size-12{
 	font-size: 12px;
+	font-family: tahoma, arial, 'Hiragino Sans GB', 宋体, sans-serif;
 }
 .font-size-10{
 	font-size: 10px;

+ 9 - 4
core/src/web/staticres/css/entcommunity.css

@@ -145,13 +145,13 @@ a:focus, a:hover{
 	color: #A0A0A0;
 }
 .entinfo-page .b-com-head .b-com-last .glyphicon{
-	font-size: 18px;
+	font-size: 17px;
 	color: #cccccc;
 	margin-right: 5px;
 	vertical-align: sub;
 }
 .entinfo-page .b-com-head .b-com-last a{
-	color: blue;
+	color: #415fcf;
 }
 .white_content {
 	display: none;
@@ -194,6 +194,7 @@ a:focus, a:hover{
 	height: 50px;
 	background-color: #F6F8FA;
 	padding-left: 20px;
+	font-size: 16px;
 }
 .ent-tab li{
 	padding: 0px 20px;
@@ -285,10 +286,11 @@ a:focus, a:hover{
 	color: #16a086;
 	display: inline-block;
 	margin-bottom: 5px;
+	font-weight: bold;
 }
 .entinfo-basicinfo .entinfo-round>div>div>span.entinfo-disabled{
-	background-color: #f0f0f0;
-	color: #a0a0a0;
+	background-color: #dddddd;
+	color: #7f7f7f;
 }
 .entinfo-basicinfo .entinfo-round>div>div>span:nth-child(2){
 	text-overflow: ellipsis;
@@ -625,6 +627,9 @@ a:focus, a:hover{
 	font-size: 14px;
 	margin-left: 5px;
 }
+.ent-layout-up .b-com-title font a{
+	color: #415fcf;
+}
 .ent-layout-up .b-com-content{
 	padding-top: 30px;
 }

BIN
core/src/web/staticres/images/activeimages/lotteryBg.jpg


+ 33 - 20
core/src/web/staticres/js/entportrait.js

@@ -73,28 +73,41 @@ function b_afterLogin(flag){
 function initRelation(){
 	if(isLogined){
 		$(".entrelation").height(500);
-		$.post("/member/getRelation",{regNo:regNo,entName:entName},function(r){
-			if(r.flag == false){
-				$("#entrelation-nologin").addClass("hide");
-				$("#entrelation-limit,#entrelation-noauthe").removeClass("hide");
-				$("#entrelation-infovis").hide();
-				$(".entrelation").css("height","auto");
-			}else if(r.flag == true && (r == null || typeof(r) == "undefined" || typeof(r.relation.links) == "undefined" || r.relation.links.length == 0 || typeof(r.relation.nodes) == "undefined" || r.relation.nodes.length <= 1)){
-				$("#entrelation-limit,#entrelation-nologin").addClass("hide");
-				relation = "";
-				$("#entrelation-infovis").hide();
-				$("#entrelation-findnull").removeClass("hide");
-				$(".entrelation").css("height","auto");
-			}else{
-				$("#entrelation-limit,#entrelation-nologin").addClass("hide");
-				loadJS("/js/d3.v3.min.js",function(){
-					loadJS("/js/geometry.js",function(){
-						loadJS("/js/relation.js",function(){
-							relation = new Relation(legcerNo,regNo,r.relation);
-							relation.init();
+		var relationNoData = function(){
+			$("#entrelation-limit,#entrelation-nologin").addClass("hide");
+			relation = "";
+			$("#entrelation-infovis").hide();
+			$("#entrelation-findnull").removeClass("hide");
+			$(".entrelation").css("height","auto");
+		}
+		$.ajax({
+			url: "/member/getRelation",
+			method: "post",
+			data: {regNo:regNo,entName:entName},
+			success: function(r){
+				if(r.flag == false){
+					$("#entrelation-nologin").addClass("hide");
+					$("#entrelation-limit,#entrelation-noauthe").removeClass("hide");
+					$("#entrelation-infovis").hide();
+					$(".entrelation").css("height","auto");
+				}else if(r.flag == true && (r == null || typeof(r) == "undefined" || typeof(r.relation.links) == "undefined" || r.relation.links.length == 0 || typeof(r.relation.nodes) == "undefined" || r.relation.nodes.length <= 1)){
+					relationNoData();
+				}else if(r.flag == true){
+					$("#entrelation-limit,#entrelation-nologin").addClass("hide");
+					loadJS("/js/d3.v3.min.js",function(){
+						loadJS("/js/geometry.js",function(){
+							loadJS("/js/relation.js",function(){
+								relation = new Relation(legcerNo,regNo,r.relation);
+								relation.init();
+							});
 						});
 					});
-				});
+				}else{
+					relationNoData();
+				}
+			},
+			error: function(){
+				relationNoData();
 			}
 		});
 	}else{

+ 3 - 3
core/src/web/staticres/js/qfw.js

@@ -166,10 +166,10 @@ dateFormat.i18n = {
 };
 
 // For convenience...
-Date.prototype.Format = function (mask, utc) {
+Date.prototype.FormatEnhance = function (mask, utc) {
 	return dateFormat(this, mask, utc);
 };
-/*Date.prototype.Format = function (fmt) { //author: meizz 
+Date.prototype.Format = function (fmt) { //author: meizz 
     var o = {
         "M+": this.getMonth() + 1, //月份 
         "d+": this.getDate(), //日 
@@ -183,7 +183,7 @@ Date.prototype.Format = function (mask, utc) {
     for (var k in o)
     if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
     return fmt;
-}*/
+}
 //浏览器窗口大小变化重新加载
 window.onresize=webSiteInit;
 serializeObject = function(form) {

BIN
core/src/web/staticres/wxswordfish/images/share-cj.jpg


BIN
core/src/web/staticres/wxswordfish/images/share-cj.png


+ 10 - 3
core/src/web/staticres/wxswordfish/main.js

@@ -252,9 +252,11 @@ function showSnopshot(module,type,on){
 		try{
 			var days=eval("msgset."+module+".days")	
 			if(typeof days=="number"){
-				var tiptxt="本栏目推送服务期还剩<d style='color:red'>"+days+"</d>天"
-				if(winWidth<341){
-					tiptxt="服务期还剩<d style='color:red'>"+days+"</d>天"
+				if (days<6){
+					var tiptxt="本栏目推送服务期还剩<d style='color:red'>"+days+"</d>天"
+					if(winWidth<341){
+						tiptxt="服务期还剩<d style='color:red'>"+days+"</d>天"
+					}
 				}
 			}
 		}catch(e){}
@@ -517,4 +519,9 @@ $(function(){
 				break;
 		}
 	});
+
+	//剑鱼协议
+	if(winWidth<341){
+		$("#prexieyi").append("<br>");
+	}
 });

+ 21 - 0
core/src/web/staticres/wxswordfish/share.js

@@ -1,4 +1,7 @@
 function initShare(signature,shareid){
+	if(typeof(shareid) == "undefined" || shareid == null || shareid == ""){
+		shareid = "-1";
+	}
 	if(typeof(signature) != "undefined" && signature != null && signature.length == 4){
 		wx.config({
 		    debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
@@ -15,6 +18,15 @@ function initShare(signature,shareid){
 			    imgUrl: 'http://www.qimingxing.info/wxswordfish/images/share-icon.png', // 分享图标
 			    success: function () { 
 			       //alert('分享成功');
+							$.ajax({    
+						        type:'post',        
+						        url:'/activity/addredis',    
+						        cache:false,    
+						        dataType:'json', 
+						        success:function(data){
+			      					 //alert('分享成功后第二天可以抽一次奖!');
+						        }    
+						        }); 
 			    },
 			    cancel: function () { 
 			       //alert('分享失败,或用户取消了');
@@ -30,6 +42,15 @@ function initShare(signature,shareid){
 			    dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
 			    success: function () { 
 			        //alert('分享成功');
+							$.ajax({    
+						        type:'post',        
+						        url:'/activity/addredis',    
+						        cache:false,    
+						        dataType:'json', 
+						        success:function(data){
+			      					 //alert('分享成功后第二天可以抽一次奖!');
+						        }    
+						        }); 
 			    },
 			    cancel: function () { 
 					//alert('分享失败,或用户取消了');

+ 1 - 1
core/src/web/staticres/wxswordfish/style.css

@@ -59,7 +59,7 @@ img{
 /**************/
 .operation{
 	background-color: #F8F8F8;
-	margin-bottom: 50px;
+	margin-bottom: 20px;
 }
 .operation>.parent-node{
 	width: 100%;

+ 1 - 1
core/src/web/templates/active/luckdraw.html

@@ -19,7 +19,7 @@
 <style>
 *{padding:0; margin:0;}
 .lotteryMain{ width:100%;}
-.lotteryBg{ width:100%; height:603px; margin:0 auto; background:url(/images/activeimages/lotteryBg.jpg) no-repeat center center; position:relative; overflow:hidden;background-size: 375px 603px;}
+.lotteryBg{ width:100%; height:100%; margin:0 auto; background:url(/images/activeimages/lotteryBg.jpg) no-repeat center center; position:relative; overflow:hidden;background-size: 375px 603px;}
 #run{ width:145px; height:145px; position:absolute; left:50%; top:50%;  margin-left:-73px; margin-top:-53px; z-index:1; transform:rotate(0deg); -ms-transform:rotate(0deg); }
 #btn_run{ width:80px; height:80px; background:url(/images/activeimages/btn_start.png) no-repeat; border:none; outline:none; position:absolute; left:50%; top:50%; margin-left:-40px; margin-top:-22px; z-index:2;cursor:pointer;background-position:0px 0px;background-size: 100% 100%;}
 </style>

+ 2 - 0
core/src/web/templates/swordfish/protocol.html

@@ -10,7 +10,9 @@
 {{include "/common/swordfishhead.html"}}
 <!-- 中间 -->
 <div class="b-content container-fluid swordfish-index">
+	<div class="b-left" style="padding-left:50px">
 	{{include "/swordfish/protocoltxt.html"}}
+	</div>
 	<div class="b-right">
 		<div class="swordfish-right-title">
 			剑鱼最新消息

+ 5 - 1
core/src/web/templates/swordfish/protocoltxt.html

@@ -3,7 +3,8 @@
 	padding: 0px 0px 0px 25px;
 }
 </style>
-<div class="b-left" style="line-height:30px">
+<div class="col-xs-12" style="line-height:30px;padding:0px 30px 0px 50px">
+	<p style="text-align:center;font-size:20px;">剑鱼用户服务协议<p>
 	<p>一,您以任何方式(包括但不限于企明星网站www.qmx.top、www.qimingxing.info、微信公众号qmx-cn)使用剑鱼服务即表示您已充分阅读、理解并同意接受本规则的条款和条件。</p>
 	<p>二,企明星有权根据业务发展的需要修订本规则,在本规则更新时不再单独通知您。经修订的规则一经在企明星公布,即产生效力,您继续使用剑鱼,则视为您已接受修订的规则。当使用过程中发生争议时,应以最新的规则为准。</p>
 	<p>三,服务条件</p>
@@ -17,4 +18,7 @@
 	<p class="pinden">2,从原始信息发布到您收到剑鱼推送信息会经过一个复杂的技术处理和网络传输过程,企明星对您收到剑鱼推送信息的时间延迟指标不做承诺。由于您未能在某个时间内收到剑鱼推送信息而造成的任何结果,企明星不承担责任。</p>
 	<p class="pinden">3,企明星保证您收到的剑鱼推送信息符合您指定的订阅条件。企明星不保证您收到的剑鱼推送信息准确符合您的真实意图。</p>
 	<p class="pinden">4,您保证您使用剑鱼的设备以及微信App正常运行。如果由于您使用剑鱼的设备或微信App的问题造成您无法接收剑鱼推送信息,企明星不承担责任。</p>
+</div>
+<div class="col-xs-12 hidden-sm hidden-md hidden-lg" style="text-align:center;padding:0 0 50px 50px">
+	<button class="btn btn-primary" onclick="window.location.href='/swordfish/page'" style="padding-top:3px;padding-bottom:3px;">返回</button>
 </div>

+ 6 - 2
core/src/web/templates/swordfish/rssset.html

@@ -36,7 +36,9 @@
 				{{if .T.msgset}}
 					{{if .T.msgset.tender}}
 						{{if .T.msgset.tender.day}}
-						本栏目推送服务期还剩{{.T.msgset.tender.day}}天。想要服务不间断,请确保积分充足。 <a href="/member/credit/myCredit">去做任务赚积分</a>
+							{{if gt 6 .T.msgset.tender.day}}
+							本栏目推送服务期还剩{{.T.msgset.tender.day}}天。想要服务不间断,请确保积分充足。 <a href="/member/credit/myCredit">去做任务赚积分</a>
+							{{end}}
 						{{end}}
 					{{end}}
 				{{end}}
@@ -70,7 +72,9 @@
 				{{if .T.msgset}}
 					{{if .T.msgset.bid}}
 						{{if .T.msgset.bid.day}}
-						本栏目推送服务期还剩{{.T.msgset.bid.day}}天。想要服务不间断,请确保积分充足。 <a href="/member/credit/myCredit">去做任务赚积分</a>
+							{{if gt 6 .T.msgset.bid.day}}
+							本栏目推送服务期还剩{{.T.msgset.bid.day}}天。想要服务不间断,请确保积分充足。 <a href="/member/credit/myCredit">去做任务赚积分</a>
+							{{end}}
 						{{end}}
 					{{end}}
 				{{end}}

+ 13 - 0
core/src/web/templates/swordfish/wxprotocol.html

@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>{{Msg "seo" "qfw.swordfish.title"}}</title>
+<meta name="Keywords" content="{{Msg "seo" "qfw.swordfish.key"}}"/>
+<meta name="Description" content="{{Msg "seo" "qfw.swordfish.description"}}"/>
+{{include "/common/inc.html"}}
+</head>
+<body>
+<div class="container-fluid" style="padding-left:20px">
+	{{include "/swordfish/protocoltxt.html"}} 
+</div>
+</body>
+</html>

+ 3 - 7
core/src/web/templates/swordfish/wxrssset.html

@@ -11,11 +11,7 @@
 <script src="/wxswordfish/main.js"></script>
 <script>
 	var msgset= {{.T.msgset}};
-	var shareid="{{.T.shareid}}";
 </script>
-<style>
-.xieyi{width:100%;height:80px;text-align:center;position:absolute;bottom:0px;}
-</style>
 </head>
 <body>
 <div class="credit-tip visible">
@@ -69,12 +65,12 @@
 		<li class="parent-node">
 			<img src="/wxswordfish/images/feerule.png">
 			收费规则
-			<span style="right:0"><img src="/wxswordfish/images/right.png" style="width: 10px;height: 17px;float: right;"></span>
+			<span style="right:0" class="rule"><img src="/wxswordfish/images/right.png" style="width: 10px;height: 17px;float: right;"></span>
 		</li>
 	</ul>
 	<!--剑鱼服务协议-->
-	<div class="xieyi">
-		<span style="color:#CCCCDD">继续使用表明你已经同意了<span>
+	<div style="margin-bottom:80px;text-align:center;">
+		<span id="prexieyi" style="color:#CCCCDD">继续使用表明你已经同意了</span>
 		<a style="color:#33ABFF" href='/member/swordfish/wxprotocol'>剑鱼用户服务协议</a>
 	</div>
 	<!--关键词-->

+ 18 - 10
core/src/web/templates/swordfish/wxshare.html

@@ -5,22 +5,30 @@
 <meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1" />
 <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,initial-scale=1.0" user-scalable="no" />
 <meta name="renderer" content="webkit">
+<link href="/css/bootstrap.min.css" rel="stylesheet">
+
 <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
 <script src="/js/jquery.js"></script>
+<script src="/js/bootstrap.min.js"></script>
+
 <script src="/wxswordfish/share.js"></script>
 <script>
 	initShare({{.T.signature}},{{.T.shareid}});
 </script>
 </head>
-<body style="margin:0px;">
-<div style="width: 100%;height: 603px; margin: 0 auto;background: url(/wxswordfish/images/share-cj.png) no-repeat top center;overflow: hidden;background-size: 375px 603px">
-</div>
-<table align=center width=100%>
-	<tr>
-		<td width=80><img src="/front/weixinshare/{{.T.shareid}}" style="width:80px; height:80px;" /></td>
-		<td style="word-break:break-all;word-wrap:break-word;line-height:22px;max-width:210px;">
- 长按图片识别二维码<br/>回复“抽奖”,有机会抽取iPad mini</td>
-	</tr>
-</table>
+<body style="margin:0px; background-color:#C5F7FE;">
+<img src="/wxswordfish/images/share-cj.jpg" class="img-responsive" alt="Cinque Terre">
+<img id="img2" style="position:absolute;" class="img-responsive" src="/front/weixinshare/{{.T.shareid}}" >
 </body>
+<script>
+$(function(){
+	var width=$(window).width();
+	var max=750
+	if(width>max){
+		width=max
+	}
+	$("#img2").css({"width":width*0.48,"top":width*0.78,"left":width*0.26})
+	
+})
+</script>
 </html>

+ 6 - 1
core/src/web/templates/swordfish/wxtoolbar.html

@@ -86,6 +86,11 @@ $(function(){
 		$("#feedback-textarea").focus().parent().removeClass("red-border");
 	});
 	$("[id='goToShare']").click(function(){
+		/*if(typeof(shareid) == "undefined" || shareid == ""){
+			window.location.href = "/swordfish/share/-1";
+		}else{
+			window.location.href = "/swordfish/share/"+shareid;
+		}*/
 		$(".share-dialog").show();
 		$("html,body").addClass("overflow-hidden");
 	});
@@ -102,7 +107,7 @@ $(function(){
 		}
 	});
 	//
-	initShare({{.T.signature}},typeof(shareid)=="undefined"?"":shareid);
+	initShare({{.T.signature}},{{.T.shareid}});
 });
 //意见反馈
 function Feedback(){

+ 22 - 6
core/src/web/templates/yellowpage/enterpriseinfo.html

@@ -88,7 +88,7 @@
 					</span>
 					<input id="location" type="hidden" value="{{if .T.res.Dom}}{{.T.res.Dom}}{{end}}">
 					<input id="cityname" type="hidden" value="">
-					<a href="javascript:void(0)" onclick="showMap()">查看详细地图</a>
+					<a href="javascript:void(0)" class="font-size-12" onclick="showMap()">查看详细地图</a>
 				{{end}}
 			</div>
 		</div>
@@ -124,7 +124,7 @@
 			<div class="entinfo-basicinfo ent-layout-up">
 				<div class="b-com-title">
 					<span class="glyphicon jianzhu"></span>基本信息
-					<font>(来源:<a href="http://gsxt.saic.gov.cn/" rel="nofollow" style="text-decoration: underline;color: #0099FF;">全国企业信用信息公示系统</a>)</font>
+					<font>(来源:<a href="http://gsxt.saic.gov.cn/" rel="nofollow">全国企业信用信息公示系统</a>)</font>
 				</div>
 				<div class="b-com-content">
 					<div class="entinfo-round">
@@ -143,7 +143,23 @@
 									</span>
 									<br>
 									{{end}}
-									{{if .T.res.EntName}}{{.T.res.EntName}}{{end}}
+									{{if .T.res.EntName}}
+									<script>
+										var entName = {{.T.res.EntName}};
+										if(entName.length > 15){
+											var firstLine = entName.substring(0,15);
+											var secondLine = entName.substring(15,entName.length);
+											console.info(secondLine);
+											if(secondLine.length > 15){
+												secondLine = secondLine.substring(0,12)+"...";
+											}
+											document.write(firstLine+"<br>"+secondLine);
+										}else{
+											document.write(entName);
+										}
+										
+									</script>
+									{{end}}
 								</div>
 								<br><img src="/images/entcommunity/triangle.png">
 							</span>
@@ -181,7 +197,7 @@
 						<!--公司类型-->
 					  	<div class="entinfo-enttype">
 							<div>
-								<span{{if not .T.res.EntTypeName}} class="entinfo-disabled"{{end}}>公司类型</span>
+								<span{{if not .T.res.EntTypeName}} class="entinfo-disabled"{{end}}>企业类型</span>
 								<span>{{if .T.res.EntTypeName}}{{.T.res.EntTypeName}}{{end}}</span>
 							</div>
 							<img src="/images/entcommunity/gongsileixing.png">
@@ -326,13 +342,13 @@
 					{{range $k,$v := .T.res.alterInfo}}
 						<li>
 							<div>
-								<div><script>document.write(new Date({{$v.AltDate}}).Format("yyyy-MM-dd hh:mm:ss"));</script></div>
+								<div><script>document.write(new Date({{$v.AltDate}}).FormatEnhance("yyyy-mm-dd HH:MM:ss"));</script></div>
 								<div>{{$v.AltItemName}}</div>
 								<div>变更前:{{$v.AltBe}}<br>变更后:{{$v.AltAf}}</div>
 								<a></a>
 							</div>
 							<div>
-								<div><script>document.write(new Date({{$v.AltDate}}).Format("yyyy-MM-dd hh:mm:ss"));</script></div>
+								<div><script>document.write(new Date({{$v.AltDate}}).FormatEnhance("yyyy-mm-dd HH:MM:ss"));</script></div>
 								<div>{{$v.AltItemName}}</div>
 								<div>变更前:{{$v.AltBe}}<br>变更后:{{$v.AltAf}}</div>
 								<a></a>

+ 3 - 1
credit/src/config.json

@@ -36,6 +36,7 @@
         "b4_n": 3,
         "b5": 20,
         "b5_n": 2,
+        "b6": 200,
         "c1": 100,
         "c2": 80,
         "c3": 150,
@@ -67,13 +68,14 @@
         "txt_a13": "首次分享服务",
         "txt_a14": "完成首次交易",
         "txt_a15": "完成首次交易评价",
-		"txt_a61": "剑鱼首次推送",
+        "txt_a61": "剑鱼首次推送",
         "txt_a62": "完成一次性所有任务",
         "txt_b1": "签到",
         "txt_b2": "企业查询",
         "txt_b3": "发服务",
         "txt_b4": "发需求",
         "txt_b5": "分享服务/需求",
+		"txt_b6": "抽奖",
         "txt_c1": "交易",
         "txt_c2": "评价",
         "txt_c3": "邀请用户",

+ 1 - 1
push/src/qfw/push/dopush/dopush.go

@@ -228,6 +228,6 @@ func SendWeixin(k *push.MemberInterest, TITLE, ShortTitle, str, stype string, no
 		Date:    wxDate,
 		Service: "剑鱼君",
 		//Url:     push.PushConfig["bidViewDomain"].(string) + "/wxpush/bid/" + k.Openid + "/" + wid + "/aa"})
-		Url: push.PushConfig["bidViewDomain"].(string) + "/mobile/sess/" + se.EncodeString(k.Openid+",uid,"+strconv.Itoa(int(time.Now().Unix()))+",wxpushlist") + "/" + k.Openid + "/" + wid + "/aa"})
+		Url: push.PushConfig["bidViewDomain"].(string) + "/mobile/sess/" + se.EncodeString(k.Openid+",uid,"+strconv.Itoa(int(time.Now().Unix()))+",wxpushlist") + "##" + k.Openid + "##" + wid + "##aa"})
 
 }

+ 6 - 0
weixin/src/endless/doc.go

@@ -0,0 +1,6 @@
+/*
+endless provides a drop in  replacement for the `net/http` stl functions `ListenAndServe` and `ListenAndServeTLS` to achieve zero downtime restarts and code upgrades.
+
+The code is based on the excellent post [Graceful Restart in Golang](http://grisha.org/blog/2014/06/03/graceful-restart-in-golang/) by [Grisha Trubetskoy](https://github.com/grisha). I took his code as a start. So a lot of credit to Grisha!
+*/
+package endless

+ 560 - 0
weixin/src/endless/endless.go

@@ -0,0 +1,560 @@
+package endless
+
+import (
+	"crypto/tls"
+	"errors"
+	"flag"
+	"fmt"
+	"log"
+	"net"
+	"net/http"
+	"os"
+	"os/exec"
+	"os/signal"
+	"runtime"
+	"strings"
+	"sync"
+	"syscall"
+	"time"
+
+	// "github.com/fvbock/uds-go/introspect"
+)
+
+const (
+	PRE_SIGNAL = iota
+	POST_SIGNAL
+
+	STATE_INIT
+	STATE_RUNNING
+	STATE_SHUTTING_DOWN
+	STATE_TERMINATE
+)
+
+var (
+	runningServerReg     sync.RWMutex
+	runningServers       map[string]*endlessServer
+	runningServersOrder  []string
+	socketPtrOffsetMap   map[string]uint
+	runningServersForked bool
+
+	DefaultReadTimeOut    time.Duration
+	DefaultWriteTimeOut   time.Duration
+	DefaultMaxHeaderBytes int
+	DefaultHammerTime     time.Duration
+
+	isChild     bool
+	socketOrder string
+
+	hookableSignals []os.Signal
+)
+
+func init() {
+	flag.BoolVar(&isChild, "continue", false, "listen on open fd (after forking)")
+	flag.StringVar(&socketOrder, "socketorder", "", "previous initialization order - used when more than one listener was started")
+
+	runningServerReg = sync.RWMutex{}
+	runningServers = make(map[string]*endlessServer)
+	runningServersOrder = []string{}
+	socketPtrOffsetMap = make(map[string]uint)
+
+	DefaultMaxHeaderBytes = 0 // use http.DefaultMaxHeaderBytes - which currently is 1 << 20 (1MB)
+
+	// after a restart the parent will finish ongoing requests before
+	// shutting down. set to a negative value to disable
+	DefaultHammerTime = 60 * time.Second
+
+	hookableSignals = []os.Signal{
+		syscall.SIGHUP,
+		syscall.SIGUSR1,
+		syscall.SIGUSR2,
+		syscall.SIGINT,
+		syscall.SIGTERM,
+		syscall.SIGTSTP,
+	}
+}
+
+type endlessServer struct {
+	http.Server
+	EndlessListener  net.Listener
+	SignalHooks      map[int]map[os.Signal][]func()
+	tlsInnerListener *endlessListener
+	wg               sync.WaitGroup
+	sigChan          chan os.Signal
+	isChild          bool
+	state            uint8
+	lock             *sync.RWMutex
+}
+
+/*
+NewServer returns an intialized endlessServer Object. Calling Serve on it will
+actually "start" the server.
+*/
+func NewServer(addr string, handler http.Handler) (srv *endlessServer) {
+	runningServerReg.Lock()
+	defer runningServerReg.Unlock()
+	if !flag.Parsed() {
+		flag.Parse()
+	}
+	if len(socketOrder) > 0 {
+		for i, addr := range strings.Split(socketOrder, ",") {
+			socketPtrOffsetMap[addr] = uint(i)
+		}
+	} else {
+		socketPtrOffsetMap[addr] = uint(len(runningServersOrder))
+	}
+
+	srv = &endlessServer{
+		wg:      sync.WaitGroup{},
+		sigChan: make(chan os.Signal),
+		isChild: isChild,
+		SignalHooks: map[int]map[os.Signal][]func(){
+			PRE_SIGNAL: map[os.Signal][]func(){
+				syscall.SIGHUP:  []func(){},
+				syscall.SIGUSR1: []func(){},
+				syscall.SIGUSR2: []func(){},
+				syscall.SIGINT:  []func(){},
+				syscall.SIGTERM: []func(){},
+				syscall.SIGTSTP: []func(){},
+			},
+			POST_SIGNAL: map[os.Signal][]func(){
+				syscall.SIGHUP:  []func(){},
+				syscall.SIGUSR1: []func(){},
+				syscall.SIGUSR2: []func(){},
+				syscall.SIGINT:  []func(){},
+				syscall.SIGTERM: []func(){},
+				syscall.SIGTSTP: []func(){},
+			},
+		},
+		state: STATE_INIT,
+		lock:  &sync.RWMutex{},
+	}
+
+	srv.Server.Addr = addr
+	srv.Server.ReadTimeout = DefaultReadTimeOut
+	srv.Server.WriteTimeout = DefaultWriteTimeOut
+	srv.Server.MaxHeaderBytes = DefaultMaxHeaderBytes
+	srv.Server.Handler = handler
+
+	runningServersOrder = append(runningServersOrder, addr)
+	runningServers[addr] = srv
+
+	return
+}
+
+/*
+ListenAndServe listens on the TCP network address addr and then calls Serve
+with handler to handle requests on incoming connections. Handler is typically
+nil, in which case the DefaultServeMux is used.
+*/
+func ListenAndServe(addr string, handler http.Handler) error {
+	server := NewServer(addr, handler)
+	return server.ListenAndServe()
+}
+
+/*
+ListenAndServeTLS acts identically to ListenAndServe, except that it expects
+HTTPS connections. Additionally, files containing a certificate and matching
+private key for the server must be provided. If the certificate is signed by a
+certificate authority, the certFile should be the concatenation of the server's
+certificate followed by the CA's certificate.
+*/
+func ListenAndServeTLS(addr string, certFile string, keyFile string, handler http.Handler) error {
+	server := NewServer(addr, handler)
+	return server.ListenAndServeTLS(certFile, keyFile)
+}
+
+func (srv *endlessServer) getState() uint8 {
+	srv.lock.RLock()
+	defer srv.lock.RUnlock()
+
+	return srv.state
+}
+
+func (srv *endlessServer) setState(st uint8) {
+	srv.lock.Lock()
+	defer srv.lock.Unlock()
+
+	srv.state = st
+}
+
+/*
+Serve accepts incoming HTTP connections on the listener l, creating a new
+service goroutine for each. The service goroutines read requests and then call
+handler to reply to them. Handler is typically nil, in which case the
+DefaultServeMux is used.
+
+In addition to the stl Serve behaviour each connection is added to a
+sync.Waitgroup so that all outstanding connections can be served before shutting
+down the server.
+*/
+func (srv *endlessServer) Serve() (err error) {
+	defer log.Println(syscall.Getpid(), "Serve() returning...")
+	srv.setState(STATE_RUNNING)
+	err = srv.Server.Serve(srv.EndlessListener)
+	log.Println(syscall.Getpid(), "Waiting for connections to finish...")
+	srv.wg.Wait()
+	srv.setState(STATE_TERMINATE)
+	return
+}
+
+/*
+ListenAndServe listens on the TCP network address srv.Addr and then calls Serve
+to handle requests on incoming connections. If srv.Addr is blank, ":http" is
+used.
+*/
+func (srv *endlessServer) ListenAndServe() (err error) {
+	addr := srv.Addr
+	if addr == "" {
+		addr = ":http"
+	}
+
+	go srv.handleSignals()
+
+	l, err := srv.getListener(addr)
+	if err != nil {
+		log.Println(err)
+		return
+	}
+
+	srv.EndlessListener = newEndlessListener(l, srv)
+
+	if srv.isChild {
+		syscall.Kill(syscall.Getppid(), syscall.SIGTERM)
+	}
+
+	log.Println(syscall.Getpid(), srv.Addr)
+	return srv.Serve()
+}
+
+/*
+ListenAndServeTLS listens on the TCP network address srv.Addr and then calls
+Serve to handle requests on incoming TLS connections.
+
+Filenames containing a certificate and matching private key for the server must
+be provided. If the certificate is signed by a certificate authority, the
+certFile should be the concatenation of the server's certificate followed by the
+CA's certificate.
+
+If srv.Addr is blank, ":https" is used.
+*/
+func (srv *endlessServer) ListenAndServeTLS(certFile, keyFile string) (err error) {
+	addr := srv.Addr
+	if addr == "" {
+		addr = ":https"
+	}
+
+	config := &tls.Config{}
+	if srv.TLSConfig != nil {
+		*config = *srv.TLSConfig
+	}
+	if config.NextProtos == nil {
+		config.NextProtos = []string{"http/1.1"}
+	}
+
+	config.Certificates = make([]tls.Certificate, 1)
+	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+	if err != nil {
+		return
+	}
+
+	go srv.handleSignals()
+
+	l, err := srv.getListener(addr)
+	if err != nil {
+		log.Println(err)
+		return
+	}
+
+	srv.tlsInnerListener = newEndlessListener(l, srv)
+	srv.EndlessListener = tls.NewListener(srv.tlsInnerListener, config)
+
+	if srv.isChild {
+		syscall.Kill(syscall.Getppid(), syscall.SIGTERM)
+	}
+
+	log.Println(syscall.Getpid(), srv.Addr)
+	return srv.Serve()
+}
+
+/*
+getListener either opens a new socket to listen on, or takes the acceptor socket
+it got passed when restarted.
+*/
+func (srv *endlessServer) getListener(laddr string) (l net.Listener, err error) {
+	if srv.isChild {
+		var ptrOffset uint = 0
+		runningServerReg.RLock()
+		defer runningServerReg.RUnlock()
+		if len(socketPtrOffsetMap) > 0 {
+			ptrOffset = socketPtrOffsetMap[laddr]
+			// log.Println("laddr", laddr, "ptr offset", socketPtrOffsetMap[laddr])
+		}
+
+		f := os.NewFile(uintptr(3+ptrOffset), "")
+		l, err = net.FileListener(f)
+		if err != nil {
+			err = fmt.Errorf("net.FileListener error: %v", err)
+			return
+		}
+	} else {
+		l, err = net.Listen("tcp", laddr)
+		if err != nil {
+			err = fmt.Errorf("net.Listen error: %v", err)
+			return
+		}
+	}
+	return
+}
+
+/*
+handleSignals listens for os Signals and calls any hooked in function that the
+user had registered with the signal.
+*/
+func (srv *endlessServer) handleSignals() {
+	var sig os.Signal
+
+	signal.Notify(
+		srv.sigChan,
+		hookableSignals...,
+	)
+
+	pid := syscall.Getpid()
+	for {
+		sig = <-srv.sigChan
+		srv.signalHooks(PRE_SIGNAL, sig)
+		switch sig {
+		case syscall.SIGHUP:
+			log.Println(pid, "Received SIGHUP. forking.")
+			err := srv.fork()
+			if err != nil {
+				log.Println("Fork err:", err)
+			}
+		case syscall.SIGUSR1:
+			log.Println(pid, "Received SIGUSR1.")
+		case syscall.SIGUSR2:
+			log.Println(pid, "Received SIGUSR2.")
+			srv.hammerTime(0 * time.Second)
+		case syscall.SIGINT:
+			log.Println(pid, "Received SIGINT.")
+			srv.shutdown()
+		case syscall.SIGTERM:
+			log.Println(pid, "Received SIGTERM.")
+			srv.shutdown()
+		case syscall.SIGTSTP:
+			log.Println(pid, "Received SIGTSTP.")
+		default:
+			log.Printf("Received %v: nothing i care about...\n", sig)
+		}
+		srv.signalHooks(POST_SIGNAL, sig)
+	}
+}
+
+func (srv *endlessServer) signalHooks(ppFlag int, sig os.Signal) {
+	if _, notSet := srv.SignalHooks[ppFlag][sig]; !notSet {
+		return
+	}
+	for _, f := range srv.SignalHooks[ppFlag][sig] {
+		f()
+	}
+	return
+}
+
+/*
+shutdown closes the listener so that no new connections are accepted. it also
+starts a goroutine that will hammer (stop all running requests) the server
+after DefaultHammerTime.
+*/
+func (srv *endlessServer) shutdown() {
+	if srv.getState() != STATE_RUNNING {
+		return
+	}
+
+	srv.setState(STATE_SHUTTING_DOWN)
+	if DefaultHammerTime >= 0 {
+		go srv.hammerTime(DefaultHammerTime)
+	}
+	// disable keep-alives on existing connections
+	srv.SetKeepAlivesEnabled(false)
+	err := srv.EndlessListener.Close()
+	if err != nil {
+		log.Println(syscall.Getpid(), "Listener.Close() error:", err)
+	} else {
+		log.Println(syscall.Getpid(), srv.EndlessListener.Addr(), "Listener closed.")
+	}
+}
+
+/*
+hammerTime forces the server to shutdown in a given timeout - whether it
+finished outstanding requests or not. if Read/WriteTimeout are not set or the
+max header size is very big a connection could hang...
+
+srv.Serve() will not return until all connections are served. this will
+unblock the srv.wg.Wait() in Serve() thus causing ListenAndServe(TLS) to
+return.
+*/
+func (srv *endlessServer) hammerTime(d time.Duration) {
+	defer func() {
+		// we are calling srv.wg.Done() until it panics which means we called
+		// Done() when the counter was already at 0 and we're done.
+		// (and thus Serve() will return and the parent will exit)
+		if r := recover(); r != nil {
+			log.Println("WaitGroup at 0", r)
+		}
+	}()
+	if srv.getState() != STATE_SHUTTING_DOWN {
+		return
+	}
+	time.Sleep(d)
+	log.Println("[STOP - Hammer Time] Forcefully shutting down parent")
+	for {
+		if srv.getState() == STATE_TERMINATE {
+			break
+		}
+		srv.wg.Done()
+		runtime.Gosched()
+	}
+}
+
+func (srv *endlessServer) fork() (err error) {
+	runningServerReg.Lock()
+	defer runningServerReg.Unlock()
+	
+	// only one server isntance should fork!
+	if runningServersForked {
+		return errors.New("Another process already forked. Ignoring this one.")
+	}
+
+	runningServersForked = true
+
+	var files = make([]*os.File, len(runningServers))
+	var orderArgs = make([]string, len(runningServers))
+	// get the accessor socket fds for _all_ server instances
+	for _, srvPtr := range runningServers {
+		// introspect.PrintTypeDump(srvPtr.EndlessListener)
+		switch srvPtr.EndlessListener.(type) {
+		case *endlessListener:
+			// normal listener
+			files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.EndlessListener.(*endlessListener).File()
+		default:
+			// tls listener
+			files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.tlsInnerListener.File()
+		}
+		orderArgs[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.Server.Addr
+	}
+
+	// log.Println(files)
+	path := os.Args[0]
+	var args []string
+	if len(os.Args) > 1 {
+		for _, arg := range os.Args[1:] {
+			if arg == "-continue" {
+				break
+			}
+			args = append(args, arg)
+		}
+	}
+	args = append(args, "-continue")
+	if len(runningServers) > 1 {
+		args = append(args, fmt.Sprintf(`-socketorder=%s`, strings.Join(orderArgs, ",")))
+		// log.Println(args)
+	}
+
+	cmd := exec.Command(path, args...)
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	cmd.ExtraFiles = files
+	// cmd.SysProcAttr = &syscall.SysProcAttr{
+	// 	Setsid:  true,
+	// 	Setctty: true,
+	// 	Ctty:    ,
+	// }
+
+	err = cmd.Start()
+	if err != nil {
+		log.Fatalf("Restart: Failed to launch, error: %v", err)
+	}
+
+	return
+}
+
+type endlessListener struct {
+	net.Listener
+	stopped bool
+	server  *endlessServer
+}
+
+func (el *endlessListener) Accept() (c net.Conn, err error) {
+	tc, err := el.Listener.(*net.TCPListener).AcceptTCP()
+	if err != nil {
+		return
+	}
+
+	tc.SetKeepAlive(true)                  // see http.tcpKeepAliveListener
+	tc.SetKeepAlivePeriod(3 * time.Minute) // see http.tcpKeepAliveListener
+
+	c = endlessConn{
+		Conn:   tc,
+		server: el.server,
+	}
+
+	el.server.wg.Add(1)
+	return
+}
+
+func newEndlessListener(l net.Listener, srv *endlessServer) (el *endlessListener) {
+	el = &endlessListener{
+		Listener: l,
+		server:   srv,
+	}
+
+	return
+}
+
+func (el *endlessListener) Close() error {
+	if el.stopped {
+		return syscall.EINVAL
+	}
+
+	el.stopped = true
+	return el.Listener.Close()
+}
+
+func (el *endlessListener) File() *os.File {
+	// returns a dup(2) - FD_CLOEXEC flag *not* set
+	tl := el.Listener.(*net.TCPListener)
+	fl, _ := tl.File()
+	return fl
+}
+
+type endlessConn struct {
+	net.Conn
+	server *endlessServer
+}
+
+func (w endlessConn) Close() error {
+	err := w.Conn.Close()
+	if err == nil {
+		w.server.wg.Done()
+	}
+	return err
+}
+
+/*
+RegisterSignalHook registers a function to be run PRE_SIGNAL or POST_SIGNAL for
+a given signal. PRE or POST in this case means before or after the signal
+related code endless itself runs
+*/
+func (srv *endlessServer) RegisterSignalHook(prePost int, sig os.Signal, f func()) (err error) {
+	if prePost != PRE_SIGNAL && prePost != POST_SIGNAL {
+		err = fmt.Errorf("Cannot use %v for prePost arg. Must be endless.PRE_SIGNAL or endless.POST_SIGNAL.")
+		return
+	}
+	for _, s := range hookableSignals {
+		if s == sig {
+			srv.SignalHooks[prePost][sig] = append(srv.SignalHooks[prePost][sig], f)
+			return
+		}
+	}
+	err = fmt.Errorf("Signal %v is not supported.")
+	return
+}

+ 4 - 4
weixin/src/main.go

@@ -1,9 +1,9 @@
 package main
 
 import (
-	//"endless"
+	"endless"
 	"log"
-	"net/http"
+	//"net/http"
 	"qfw/util"
 	"qfw/util/elastic"
 	"qfw/util/mongodb"
@@ -37,6 +37,6 @@ func main() {
 	//启动Rpc服务
 	rpc.StartWeixinRpc(weixin.Mux)
 	//启动web服务
-	http.ListenAndServe(":"+wf.SysConfig.Port, nil) // 启动接收微信数据服务器
-	//endless.ListenAndServe(":"+wf.SysConfig.Port, nil)
+	//http.ListenAndServe(":"+wf.SysConfig.Port, nil) // 启动接收微信数据服务器
+	endless.ListenAndServe(":"+wf.SysConfig.Port, nil)
 }

+ 5 - 2
weixin/src/qfw/weixin/msgtxtchandler.go

@@ -4,7 +4,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
-	"log"
+	_ "log"
 	"math/rand"
 	"net"
 	"net/http"
@@ -40,6 +40,7 @@ func InitRobotHttpClient() {
 //文本消息处理
 func MsgTxtHandler(w ResponseWriter, r *Request) {
 	openid := r.FromUserName
+	//log.Println("........", r.FromUserName, r.Content)
 	//在会话中
 	if us, ok := UserSession[openid]; ok {
 		if r.Content == "q" || r.Content == "Q" {
@@ -68,7 +69,7 @@ func MsgTxtHandler(w ResponseWriter, r *Request) {
 		w.ReplyNews([]Article{Article{PicUrl: wf.SysConfig.Activity["picurl"], Title: wf.SysConfig.Activity["title"], Url: targeturl}})
 	} else if strings.HasPrefix(r.Content, "内部报名") { //绑定拓普员工姓名
 		tmp := strings.Fields(r.Content)
-		log.Println(tmp, len(tmp))
+		//log.Println(tmp, len(tmp))
 		if len(tmp) != 2 {
 			w.ReplyText("请按以下格式输入:内部报名 姓名")
 		} else {
@@ -79,7 +80,9 @@ func MsgTxtHandler(w ResponseWriter, r *Request) {
 			}
 		}
 	} else if r.Content == "成果查询" { //查询我的邀请人数
+		//log.Println(r.FromUserName, "查询成果")
 		total := dao.GetMyInvitePersons(r.FromUserName)
+		//log.Println(r.FromUserName, total)
 		w.ReplyText(fmt.Sprintf("感谢您,已经成功邀请%d个用户", total))
 	} else {
 		//属于在线咨询,暂时直接中转到微信客服系统