Преглед на файлове

perf:详情页并发请求控制

wangshan преди 1 година
родител
ревизия
c66a005f60

+ 4 - 1
src/jfw/modules/bigmember/src/config.json

@@ -208,5 +208,8 @@
     "entService": 10,
     "free": 0
   },
-  "miniPortraitCacheTime": 604800
+  "miniPortraitCacheTime": 604800,
+  "restrictionSwitch": true,
+  "restrictionDoPool":5,
+  "restrictionWaitPool":5
 }

+ 7 - 0
src/jfw/modules/bigmember/src/config/config.go

@@ -9,6 +9,7 @@ import (
 	"github.com/gogf/gf/v2/frame/g"
 	"github.com/gogf/gf/v2/os/gcfg"
 	"github.com/gogf/gf/v2/os/gctx"
+	"jy/src/jfw/modules/bigmember/src/restriction"
 )
 
 type config struct {
@@ -94,6 +95,9 @@ type config struct {
 		Free       int //免费用户 0个
 	}
 	MiniPortraitCacheTime int
+	RestrictionSwitch     bool
+	RestrictionDoPool     int
+	RestrictionWaitPool   int
 }
 
 type CustomerInfo struct {
@@ -131,4 +135,7 @@ func init() {
 		RegPowerCheckCenter(g.Cfg().MustGet(ctx, "powerCheckCenterKey").String()).
 		RegUserCenter(g.Cfg().MustGet(ctx, "userCenterKey").String()).
 		RegResourceCenter(g.Cfg().MustGet(ctx, "resourceCenterKey").String())
+	if Config.RestrictionSwitch {
+		restriction.ReqLimitInit(Config.RestrictionDoPool, Config.RestrictionWaitPool)
+	}
 }

+ 77 - 0
src/jfw/modules/bigmember/src/restriction/restriction.go

@@ -0,0 +1,77 @@
+package restriction
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"time"
+)
+
+var (
+	ReqLimitFunc *ReqLimit
+)
+
+type ReqLimit struct {
+	DoPool   chan struct{}
+	WaitPool chan struct{}
+}
+
+func ReqLimitInit(do, wait int) {
+	//创建执行池 等待池
+	doPool := make(chan struct{}, do)
+	for i := 0; i < do; i++ {
+		doPool <- struct{}{}
+	}
+	waitPool := make(chan struct{}, wait)
+	for i := 0; i < wait; i++ {
+		waitPool <- struct{}{}
+	}
+	ReqLimitFunc = &ReqLimit{
+		DoPool:   doPool,
+		WaitPool: waitPool,
+	}
+}
+
+// -2 等待池已满
+// -1 超时
+// 1:可以执行查询
+func (r *ReqLimit) Limit(ctx context.Context) int {
+	ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
+	defer cancel()
+	select {
+	case <-r.WaitPool:
+		defer func() {
+			r.WaitPool <- struct{}{}
+		}()
+		select {
+		case <-r.DoPool:
+			return 1
+		case <-ctx.Done(): //超时
+			return -1
+		}
+	default:
+		return -2
+	}
+}
+
+// 回收
+func (r *ReqLimit) Release() {
+	r.DoPool <- struct{}{}
+}
+
+func ReqCheck(key string) (err error) {
+	if ReqLimitFunc != nil {
+		if no := ReqLimitFunc.Limit(context.Background()); no == 1 {
+			defer ReqLimitFunc.Release()
+		} else {
+			if no == -2 {
+				err = fmt.Errorf("当前请求过于频繁,请稍后再试")
+			} else if no == -1 {
+				err = fmt.Errorf("当前请求超时,请稍后再试")
+			}
+			log.Println(fmt.Sprintf("%s err: %s", key, err.Error()))
+			return
+		}
+	}
+	return
+}

+ 11 - 0
src/jfw/modules/bigmember/src/service/portrait/memberPortraitAction.go

@@ -7,6 +7,7 @@ import (
 	"fmt"
 	"jy/src/jfw/modules/bigmember/src/config"
 	"jy/src/jfw/modules/bigmember/src/entity"
+	rest "jy/src/jfw/modules/bigmember/src/restriction"
 	"jy/src/jfw/modules/bigmember/src/util"
 	"log"
 	"regexp"
@@ -257,6 +258,11 @@ func (this *EntPortrait) WinnerPortrait() {
 func (this *EntPortrait) WinnerMiniPortrait() {
 	userId := qutil.ObjToString(this.GetSession("userId"))
 	rData, errMsg := func() (interface{}, error) {
+		if config.Config.RestrictionSwitch {
+			if err := rest.ReqCheck("winner mini portrait"); err != nil {
+				return nil, err
+			}
+		}
 		cepm, _, err, _ := entity.CreatePortraitManager(this.Session(), "entPortrait")
 		if err != nil {
 			return nil, err
@@ -507,6 +513,11 @@ func (this *EntPortrait) BuyerPortrait() {
 func (this *EntPortrait) BuyerMiniPortrait() {
 	userId := qutil.ObjToString(this.GetSession("userId"))
 	rData, errMsg := func() (interface{}, error) {
+		if config.Config.RestrictionSwitch {
+			if err := rest.ReqCheck("buyer mini portrait"); err != nil {
+				return nil, err
+			}
+		}
 		cepm, _, err, _ := entity.CreatePortraitManager(this.Session(), "buyerPortrait")
 		if err != nil {
 			return nil, err

+ 12 - 1
src/jfw/modules/publicapply/src/detail/config.json

@@ -142,5 +142,16 @@
         }
       ]
     }
-  ]
+  ],
+  "restrictionSwitch": true,
+  "restrictions": {
+    "baseInfo": {
+      "doPool": 5,
+      "waitPool": 5
+    },
+    "advanced": {
+      "doPool": 5,
+      "waitPool": 5
+    }
+  }
 }

+ 18 - 0
src/jfw/modules/publicapply/src/detail/config/config.go

@@ -3,6 +3,7 @@ package config
 import (
 	util "app.yhyue.com/moapp/jybase/common"
 	"jy/src/jfw/modules/publicapply/src/detail/entity"
+	"jy/src/jfw/modules/publicapply/src/detail/restriction"
 	"log"
 )
 
@@ -13,4 +14,21 @@ var (
 func init() {
 	log.Println("初始化 config 配置")
 	util.ReadConfig("./detail/config.json", &Config)
+	if Config.RestrictionSwitch && Config.Restrictions != nil {
+		for k, v := range Config.Restrictions {
+			//创建执行池 等待池
+			doPool := make(chan struct{}, v.DoPool)
+			for i := 0; i < v.DoPool; i++ {
+				doPool <- struct{}{}
+			}
+			waitPool := make(chan struct{}, v.WaitPool)
+			for i := 0; i < v.WaitPool; i++ {
+				waitPool <- struct{}{}
+			}
+			restriction.ReqLimitMap[k] = &restriction.ReqLimit{
+				DoPool:   doPool,
+				WaitPool: waitPool,
+			}
+		}
+	}
 }

+ 7 - 0
src/jfw/modules/publicapply/src/detail/dao/advanced.go

@@ -13,6 +13,7 @@ import (
 	dc "jy/src/jfw/modules/publicapply/src/detail/config"
 	"jy/src/jfw/modules/publicapply/src/detail/consts"
 	"jy/src/jfw/modules/publicapply/src/detail/entity"
+	rest "jy/src/jfw/modules/publicapply/src/detail/restriction"
 	"jy/src/jfw/modules/publicapply/src/detail/util"
 	"log"
 	"net/http"
@@ -74,6 +75,12 @@ func (a *Advanced) AdvancedInfo() (*entity.AdvancedInfo, error) {
 		}
 		err error
 	)
+	//招标其他信息并发过滤
+	if dc.Config.RestrictionSwitch {
+		if err = rest.ReqCheck("advanced"); err != nil {
+			return nil, err
+		}
+	}
 	//投标服务
 	ai.Services = a.BidService()
 	wg := &sync.WaitGroup{}

+ 14 - 7
src/jfw/modules/publicapply/src/detail/dao/baseInfo.go

@@ -14,6 +14,7 @@ import (
 	dc "jy/src/jfw/modules/publicapply/src/detail/config"
 	"jy/src/jfw/modules/publicapply/src/detail/consts"
 	"jy/src/jfw/modules/publicapply/src/detail/entity"
+	rest "jy/src/jfw/modules/publicapply/src/detail/restriction"
 	"jy/src/jfw/modules/publicapply/src/detail/util"
 	"log"
 	"net/http"
@@ -46,6 +47,19 @@ func NewBaseInfo(id, pageType string, ui util.SessUserInfo, fromUserId string, s
 
 // BidBaseInfo data
 func (b *BaseInfo) BidBaseInfo() (bi *entity.BidInfo, err error) {
+	bi = &entity.BidInfo{
+		BaseInfo:  &entity.BidBaseInfo{},
+		Abstract:  &entity.Abstract{},
+		Detail:    &entity.DetailInfo{},
+		RightSide: map[string]interface{}{},
+		CanRead:   false,
+	}
+	//招标数据基本信息并发过滤
+	if dc.Config.RestrictionSwitch {
+		if err = rest.ReqCheck("baseInfo"); err != nil {
+			return
+		}
+	}
 	//未登录用户 会考虑用户是否在白名单中 ipTrue;登录用户不考虑
 	//注意三端不同  pageType类型不同的处理
 	var (
@@ -60,13 +74,6 @@ func (b *BaseInfo) BidBaseInfo() (bi *entity.BidInfo, err error) {
 		pageTypeCheck = consts.PageTypeCheck
 		isPay         = isVip || isMember || isEntniche
 	)
-	bi = &entity.BidInfo{
-		BaseInfo:  &entity.BidBaseInfo{},
-		Abstract:  &entity.Abstract{},
-		Detail:    &entity.DetailInfo{},
-		RightSide: map[string]interface{}{},
-		CanRead:   false,
-	}
 	//企业级商机管理权限判断
 	entId := int(b.UserInfo.EntId)
 	if entId > 0 && userPower.EntInfo[entId] != nil {

+ 535 - 541
src/jfw/modules/publicapply/src/detail/dao/bidding.go

@@ -1,616 +1,610 @@
 package dao
 
 import (
-	"app.yhyue.com/moapp/jybase/common"
-	"app.yhyue.com/moapp/jybase/date"
-	"app.yhyue.com/moapp/jybase/encrypt"
-	elastic "app.yhyue.com/moapp/jybase/es"
-	mg "app.yhyue.com/moapp/jybase/mongodb"
-	"app.yhyue.com/moapp/jybase/redis"
-	"app.yhyue.com/moapp/jypkg/common/src/qfw/util/jy"
-	"app.yhyue.com/moapp/jypkg/public"
-	"database/sql"
-	"fmt"
-	"github.com/gogf/gf/v2/util/gconv"
-	"go.mongodb.org/mongo-driver/bson"
-	"jy/src/jfw/modules/publicapply/src/config"
-	"jy/src/jfw/modules/publicapply/src/db"
-	dc "jy/src/jfw/modules/publicapply/src/detail/config"
-	"jy/src/jfw/modules/publicapply/src/detail/consts"
-	"jy/src/jfw/modules/publicapply/src/detail/entity"
-	"jy/src/jfw/modules/publicapply/src/detail/util"
-	"log"
-	"regexp"
-	"strconv"
-	"strings"
-	"time"
+    "app.yhyue.com/moapp/jybase/common"
+    "app.yhyue.com/moapp/jybase/date"
+    "app.yhyue.com/moapp/jybase/encrypt"
+    elastic "app.yhyue.com/moapp/jybase/es"
+    mg "app.yhyue.com/moapp/jybase/mongodb"
+    "app.yhyue.com/moapp/jybase/redis"
+    "app.yhyue.com/moapp/jypkg/common/src/qfw/util/jy"
+    "app.yhyue.com/moapp/jypkg/public"
+    "database/sql"
+    "fmt"
+    "github.com/gogf/gf/v2/util/gconv"
+    "jy/src/jfw/modules/publicapply/src/config"
+    "jy/src/jfw/modules/publicapply/src/db"
+    dc "jy/src/jfw/modules/publicapply/src/detail/config"
+    "jy/src/jfw/modules/publicapply/src/detail/consts"
+    "jy/src/jfw/modules/publicapply/src/detail/entity"
+    "jy/src/jfw/modules/publicapply/src/detail/util"
+    "log"
+    "regexp"
+    "strconv"
+    "strings"
+    "time"
 )
 
 // userid  by openid
 func GetUserId(openid string) string {
-	data, ok := db.Mgo.FindOne(consts.UserTable, map[string]interface{}{"s_m_openid": openid})
-	if data != nil && len(*data) > 0 && ok {
-		userid := mg.BsonIdToSId((*data)["_id"])
-		return userid
-	}
-	return ""
+    data, ok := db.Mgo.FindOne(consts.UserTable, map[string]interface{}{"s_m_openid": openid})
+    if data != nil && len(*data) > 0 && ok {
+        userid := mg.BsonIdToSId((*data)["_id"])
+        return userid
+    }
+    return ""
 }
 
 // 分销--最新一条记录 2021-09-07 10:36:05
 func GetUserIdByDisWord(disWord, userId string) (belongUserId string) {
-	if disWord != "" {
-		redisDis := redis.GetStr(consts.RedisOther, "DIS_"+disWord[1:])
-		if redisDis != "" {
-			suffix := disWord[len(disWord)-3:]
-			//公告三级页处理
-			if suffix == consts.SuffixMsgT {
-				effectiveTimeStr := strings.Split(redisDis, "##")[3]
-				effectiveTime, _ := strconv.ParseInt(effectiveTimeStr, 10, 64)
-				//是否计算佣金
-				if time.Now().Unix() <= effectiveTime {
-					belongUserId = strings.Split(redisDis, "##")[1]
-					db.Mysql.ExecTx("口号使用", func(tx *sql.Tx) bool {
-						//口号是否使用过
-						wordInfo := db.Mysql.Find("dis_word", map[string]interface{}{"userId": userId, "password": disWord}, "id", "", 0, 0)
-						if len(*wordInfo) == 0 {
-							//新增口号使用
-							startTime := time.Now().Format(date.Date_Full_Layout)
-							stopTime := util.TimeProcessing(time.Now().Format(date.Date_Full_Layout), dc.Config.TermValidity).Format(date.Date_Full_Layout)
-							insert := map[string]interface{}{
-								"password":      disWord,
-								"userId":        userId,
-								"belong_userid": belongUserId,
-								"start_time":    startTime,
-								"stop_time":     stopTime,
-							}
-							insert1 := public.Mysql.InsertByTx(tx, "dis_word", insert) //口号使用表
-							log.Println("插入口号使用表", insert1)
-							return insert1 > 0
-						}
-						return true
-					})
-				}
-			}
-		}
-	}
-	return
+    if disWord != "" {
+        redisDis := redis.GetStr(consts.RedisOther, "DIS_"+disWord[1:])
+        if redisDis != "" {
+            suffix := disWord[len(disWord)-3:]
+            //公告三级页处理
+            if suffix == consts.SuffixMsgT {
+                effectiveTimeStr := strings.Split(redisDis, "##")[3]
+                effectiveTime, _ := strconv.ParseInt(effectiveTimeStr, 10, 64)
+                //是否计算佣金
+                if time.Now().Unix() <= effectiveTime {
+                    belongUserId = strings.Split(redisDis, "##")[1]
+                    db.Mysql.ExecTx("口号使用", func(tx *sql.Tx) bool {
+                        //口号是否使用过
+                        wordInfo := db.Mysql.Find("dis_word", map[string]interface{}{"userId": userId, "password": disWord}, "id", "", 0, 0)
+                        if len(*wordInfo) == 0 {
+                            //新增口号使用
+                            startTime := time.Now().Format(date.Date_Full_Layout)
+                            stopTime := util.TimeProcessing(time.Now().Format(date.Date_Full_Layout), dc.Config.TermValidity).Format(date.Date_Full_Layout)
+                            insert := map[string]interface{}{
+                                "password":      disWord,
+                                "userId":        userId,
+                                "belong_userid": belongUserId,
+                                "start_time":    startTime,
+                                "stop_time":     stopTime,
+                            }
+                            insert1 := public.Mysql.InsertByTx(tx, "dis_word", insert) //口号使用表
+                            log.Println("插入口号使用表", insert1)
+                            return insert1 > 0
+                        }
+                        return true
+                    })
+                }
+            }
+        }
+    }
+    return
 }
 
 // 检查用户是否关注
 func CheckUserIsSubscribe(openid string) bool {
-	user, ok := db.Mgo.FindOneByField("user", map[string]interface{}{
-		"i_appid":    2,
-		"s_m_openid": openid,
-		"s_unionid":  map[string]interface{}{"$ne": openid},
-	}, `{"i_ispush":1}`)
-	if ok && user != nil {
-		if (*user)["_id"] == nil || common.IntAllDef((*user)["i_ispush"], 1) == 0 {
-			return false
-		} else {
-			return true
-		}
-	}
-	return false
+    user, ok := db.Mgo.FindOneByField("user", map[string]interface{}{
+        "i_appid":    2,
+        "s_m_openid": openid,
+        "s_unionid":  map[string]interface{}{"$ne": openid},
+    }, `{"i_ispush":1}`)
+    if ok && user != nil {
+        if (*user)["_id"] == nil || common.IntAllDef((*user)["i_ispush"], 1) == 0 {
+            return false
+        } else {
+            return true
+        }
+    }
+    return false
 }
 
 // 超前信息
 func AdvancedInfo(newUserId int64, bdId string) (b bool) {
-	pushData := public.BaseMysql.FindOne("leadproject_push", map[string]interface{}{"user_id": newUserId, "info_id": bdId}, "id", "")
-	//访问次数加1
-	if pushData != nil {
-		b = public.BaseMysql.UpdateOrDeleteBySql("UPDATE leadproject_push SET  visit_count=visit_count+1 ,lastvisit_time=? WHERE id = ?", time.Now().Format("2006-01-02 15:04:05"), (*pushData)["id"]) > 0
-	}
-	return
+    pushData := public.BaseMysql.FindOne("leadproject_push", map[string]interface{}{"user_id": newUserId, "info_id": bdId}, "id", "")
+    //访问次数加1
+    if pushData != nil {
+        b = public.BaseMysql.UpdateOrDeleteBySql("UPDATE leadproject_push SET  visit_count=visit_count+1 ,lastvisit_time=? WHERE id = ?", time.Now().Format("2006-01-02 15:04:05"), (*pushData)["id"]) > 0
+    }
+    return
 }
 
 // 该节点是否留资
 func hasRetainedCapital(uid string, source []string) bool {
-	if count, err := db.Mgo.CountByErr("saleLeads", map[string]interface{}{"userid": uid, "source": map[string]interface{}{"$in": source}}); err != nil || count > 0 {
-		return true
-	}
-	return false
+    if count, err := db.Mgo.CountByErr("saleLeads", map[string]interface{}{"userid": uid, "source": map[string]interface{}{"$in": source}}); err != nil || count > 0 {
+        return true
+    }
+    return false
 }
 
 // 留资信息
 func CNode(userId string) bool {
-	if hasRetainedCapital(userId, []string{"jyarticle_see3_plus", "jyarticle_see3_plus_pc", "jyarticle_see3_plus_wx", "jyarticle_see3_plus_app", "pc_article_member_freeuse", "app_article_member_freeuse", "wx_article_member_freeuse", "h5_article_member_freeuse"}) {
-		return true
-	}
-	rM := map[string]interface{}{}
-	rdata, ok := db.Mgo.Find("saleLeads", map[string]interface{}{
-		"userid": userId,
-	}, `{"createtime":-1}`, nil, false, 0, 10)
-	if rdata != nil && len(*rdata) > 0 && ok {
-		for _, v := range *rdata {
-			for kk, vv := range v {
-				if vv == nil {
-					continue
-				}
-				if rM[kk] != nil {
-					continue
-				}
-				rM[kk] = vv
-			}
-		}
-		delete(rM, "_id")
-		delete(rM, "userid")
-		delete(rM, "createtime")
-		delete(rM, "client")
-	}
-	if userinfo := config.Compatible.Select(userId, `{"s_phone":1,"s_m_phone":1,"s_myemail":1,"s_company":1,"o_jy":1,"o_vipjy":1}`); userinfo != nil && len(*userinfo) > 0 {
-		s_phone := common.ObjToString((*userinfo)["s_phone"])
-		phone := common.If(s_phone == "", common.ObjToString((*userinfo)["s_m_phone"]), s_phone)
-		if rM["phone"] == nil || rM["phone"] == "" {
-			rM["phone"] = phone
-		}
-		if rM["company"] == nil || rM["company"] == "" {
-			rM["company"] = common.ObjToString((*userinfo)["s_company"])
-		}
-	}
-	if rM["name"] != nil && rM["name"] != "" && rM["phone"] != nil && rM["phone"] != "" && rM["company"] != nil && rM["company"] != "" && rM["position"] != nil && rM["position"] != "" && rM["companyType"] != "" {
+    if hasRetainedCapital(userId, []string{"jyarticle_see3_plus", "jyarticle_see3_plus_pc", "jyarticle_see3_plus_wx", "jyarticle_see3_plus_app", "pc_article_member_freeuse", "app_article_member_freeuse", "wx_article_member_freeuse", "h5_article_member_freeuse"}) {
+        return true
+    }
+    rM := map[string]interface{}{}
+    rdata, ok := db.Mgo.Find("saleLeads", map[string]interface{}{
+        "userid": userId,
+    }, `{"createtime":-1}`, nil, false, 0, 10)
+    if rdata != nil && len(*rdata) > 0 && ok {
+        for _, v := range *rdata {
+            for kk, vv := range v {
+                if vv == nil {
+                    continue
+                }
+                if rM[kk] != nil {
+                    continue
+                }
+                rM[kk] = vv
+            }
+        }
+        delete(rM, "_id")
+        delete(rM, "userid")
+        delete(rM, "createtime")
+        delete(rM, "client")
+    }
+    if userinfo := config.Compatible.Select(userId, `{"s_phone":1,"s_m_phone":1,"s_myemail":1,"s_company":1,"o_jy":1,"o_vipjy":1}`); userinfo != nil && len(*userinfo) > 0 {
+        s_phone := common.ObjToString((*userinfo)["s_phone"])
+        phone := common.If(s_phone == "", common.ObjToString((*userinfo)["s_m_phone"]), s_phone)
+        if rM["phone"] == nil || rM["phone"] == "" {
+            rM["phone"] = phone
+        }
+        if rM["company"] == nil || rM["company"] == "" {
+            rM["company"] = common.ObjToString((*userinfo)["s_company"])
+        }
+    }
+    if rM["name"] != nil && rM["name"] != "" && rM["phone"] != nil && rM["phone"] != "" && rM["company"] != nil && rM["company"] != "" && rM["position"] != nil && rM["position"] != "" && rM["companyType"] != "" {
 
-		if rM["position"] != "总裁" && rM["position"] != "总经理" && (rM["branch"] == nil || rM["branch"] == "") {
-			return false
-		}
-		return true
+        if rM["position"] != "总裁" && rM["position"] != "总经理" && (rM["branch"] == nil || rM["branch"] == "") {
+            return false
+        }
+        return true
 
-	}
-	return false
+    }
+    return false
 }
 
 // 查看公告详情次数限制
 func SeeDetailLimit(obj map[string]interface{}, userId, sid string) bool {
-	if obj != nil {
-		subTypeStr, _ := obj["subtype"].(string)
-		if strings.Contains(subTypeStr, "拟建") || strings.Contains(subTypeStr, "采购意向") {
-			return false
-		}
-	} else {
-		watchKey := fmt.Sprintf("article_count_%d_%s_%d_%s", time.Now().Year(), time.Now().Month(), time.Now().Day(), userId)
-		//检验是否留资
-		if CNode(userId) {
-			return true
-		}
-		if seeRes := redis.Get(consts.RedisLimitation, watchKey); seeRes != nil && seeRes != "" {
-			if resVal, _ := seeRes.(string); resVal != "" {
-				sidss := strings.Split(resVal, "_")
-				if len(sidss) < dc.Config.CanReadNotice {
-					sidss = append(sidss, sid)
-					arrs := util.RemoveDuplicatesAndEmpty(sidss)
-					newVal := strings.Join(arrs, "_")
-					redis.Put(consts.RedisLimitation, watchKey, newVal, jy.GetExpire())
-					return true
-				} else {
-					for _, v := range sidss {
-						if sid == v {
-							return true
-						}
-					}
-					return false
-				}
-			}
-		} else {
-			redis.Put(consts.RedisLimitation, watchKey, sid, jy.GetExpire())
-			return true
-		}
-	}
-	return false
+    if obj != nil {
+        subTypeStr, _ := obj["subtype"].(string)
+        if strings.Contains(subTypeStr, "拟建") || strings.Contains(subTypeStr, "采购意向") {
+            return false
+        }
+    } else {
+        watchKey := fmt.Sprintf("article_count_%d_%s_%d_%s", time.Now().Year(), time.Now().Month(), time.Now().Day(), userId)
+        //检验是否留资
+        if CNode(userId) {
+            return true
+        }
+        if seeRes := redis.Get(consts.RedisLimitation, watchKey); seeRes != nil && seeRes != "" {
+            if resVal, _ := seeRes.(string); resVal != "" {
+                sidss := strings.Split(resVal, "_")
+                if len(sidss) < dc.Config.CanReadNotice {
+                    sidss = append(sidss, sid)
+                    arrs := util.RemoveDuplicatesAndEmpty(sidss)
+                    newVal := strings.Join(arrs, "_")
+                    redis.Put(consts.RedisLimitation, watchKey, newVal, jy.GetExpire())
+                    return true
+                } else {
+                    for _, v := range sidss {
+                        if sid == v {
+                            return true
+                        }
+                    }
+                    return false
+                }
+            }
+        } else {
+            redis.Put(consts.RedisLimitation, watchKey, sid, jy.GetExpire())
+            return true
+        }
+    }
+    return false
 }
 
 // 详情页数据
 func GetBiddingData(id string) (subtype string, obj map[string]interface{}) {
-	bidRec, ok := db.Mgo.Find("bidding_rec", bson.M{"s_id": id}, `{"l_recoverydate":-1}`, nil, false, 0, 1)
-	if ok && (*bidRec) != nil && len(*bidRec) == 1 && (*bidRec)[0] != nil {
-		obj = (*bidRec)[0]
-	} else {
-		cObj, ok := db.Mgo_Bidding.FindById(db.DbConf.Mongodb.Bidding.Collection, id, nil)
-		if ok && (cObj == nil || *cObj == nil || len(*cObj) == 0) {
-			cObj, ok = db.Mgo_Bidding.FindById(db.DbConf.Mongodb.Bidding.Collection_change, id, nil)
-		}
-		obj = *cObj
-	}
-	if ok && obj != nil && len(obj) > 0 {
-		subtype = common.ObjToString(obj["subtype"])
-		topType := common.ObjToString(obj["toptype"])
-		if topType == "" {
-			subtype = topType
-		}
-	}
-	return
+    cObj, ok := db.Mgo_Bidding.FindById(db.DbConf.Mongodb.Bidding.Collection, id, nil)
+    if ok && (cObj == nil || *cObj == nil || len(*cObj) == 0) {
+        cObj, ok = db.Mgo_Bidding.FindById(db.DbConf.Mongodb.Bidding.Collection_change, id, nil)
+    }
+    obj = *cObj
+    if ok && obj != nil && len(obj) > 0 {
+        subtype = common.ObjToString(obj["subtype"])
+        topType := common.ObjToString(obj["toptype"])
+        if topType == "" {
+            subtype = topType
+        }
+    }
+    return
 }
 
 // 没有权限招标信息处理
 func BiddingDataFormatNoPower(obj map[string]interface{}, id string) *entity.BidInfo {
-	var (
-		bi = &entity.BidInfo{
-			BaseInfo: &entity.BidBaseInfo{},
-			Abstract: &entity.Abstract{},
-			Detail:   &entity.DetailInfo{},
-			CanRead:  false,
-		}
-	)
-	//基本信息
-	bi.BaseInfo.Id = encrypt.EncodeArticleId2ByCheck(id)
-	industry := common.ObjToString(obj["s_subscopeclass"])
-	if industry != "" {
-		industry = strings.Replace(industry, "它", "他", -1)
-		industry = strings.Split(industry, ",")[0]
-	}
-	bi.BaseInfo.Industry = industry
-	title := common.ObjToString(obj["title"])
-	if len([]rune(title)) > dc.Config.TitleSize {
-		title = fmt.Sprintf("%s...", string([]rune(title)[:dc.Config.TitleSize]))
-	}
-	bi.BaseInfo.Title = title
-	bi.BaseInfo.SubType = common.ObjToString(obj["subtype"])
-	bi.BaseInfo.Area = common.ObjToString(obj["area"])
-	bi.BaseInfo.City = common.ObjToString(obj["city"])
-	bi.BaseInfo.BuyerClass = common.ObjToString(obj["buyerclass"])
-	return bi
+    var (
+        bi = &entity.BidInfo{
+            BaseInfo: &entity.BidBaseInfo{},
+            Abstract: &entity.Abstract{},
+            Detail:   &entity.DetailInfo{},
+            CanRead:  false,
+        }
+    )
+    //基本信息
+    bi.BaseInfo.Id = encrypt.EncodeArticleId2ByCheck(id)
+    industry := common.ObjToString(obj["s_subscopeclass"])
+    if industry != "" {
+        industry = strings.Replace(industry, "它", "他", -1)
+        industry = strings.Split(industry, ",")[0]
+    }
+    bi.BaseInfo.Industry = industry
+    title := common.ObjToString(obj["title"])
+    if len([]rune(title)) > dc.Config.TitleSize {
+        title = fmt.Sprintf("%s...", string([]rune(title)[:dc.Config.TitleSize]))
+    }
+    bi.BaseInfo.Title = title
+    bi.BaseInfo.SubType = common.ObjToString(obj["subtype"])
+    bi.BaseInfo.Area = common.ObjToString(obj["area"])
+    bi.BaseInfo.City = common.ObjToString(obj["city"])
+    bi.BaseInfo.BuyerClass = common.ObjToString(obj["buyerclass"])
+    return bi
 }
 
 // wx pc obj字段统一处理
 func BiddingDataFormat(obj map[string]interface{}, id string) *entity.BidInfo {
-	var (
-		bi = &entity.BidInfo{
-			BaseInfo: &entity.BidBaseInfo{},
-			Abstract: &entity.Abstract{},
-			Detail:   &entity.DetailInfo{},
-			CanRead:  true,
-		}
-	)
-	//基本信息
-	bi.BaseInfo.Id = encrypt.EncodeArticleId2ByCheck(id)
-	industry := common.ObjToString(obj["s_subscopeclass"])
-	if industry != "" {
-		industry = strings.Replace(industry, "它", "他", -1)
-		industry = strings.Split(industry, ",")[0]
-	}
-	bi.BaseInfo.Industry = industry
-	title := common.ObjToString(obj["title"])
-	if len([]rune(title)) > dc.Config.TitleSize {
-		title = fmt.Sprintf("%s...", string([]rune(title)[:dc.Config.TitleSize]))
-	}
-	bi.BaseInfo.Title = title
-	bi.BaseInfo.Area = common.ObjToString(obj["area"])
-	bi.BaseInfo.Purchasing = common.ObjToString(obj["purchasing"])
-	bi.BaseInfo.ProjectName = common.ObjToString(obj["projectname"])
-	bi.BaseInfo.ProjectCode = common.ObjToString(obj["projectcode"])
-	bi.BaseInfo.City = common.ObjToString(obj["city"])
-	bi.BaseInfo.BuyerClass = common.ObjToString(obj["buyerclass"])
-	bi.BaseInfo.District = common.ObjToString(obj["district"])
-	bi.BaseInfo.Site = common.ObjToString(obj["site"])
-	bi.BaseInfo.SubType = common.ObjToString(obj["subtype"])
-	bi.BaseInfo.TopType = common.ObjToString(obj["toptype"])
-	if bi.BaseInfo.SubType == "" {
-		bi.BaseInfo.SubType = bi.BaseInfo.TopType
-	}
-	bi.BaseInfo.BidAmount = common.Int64All(obj["bidamount"])
-	bi.BaseInfo.Budget = common.Int64All(obj["budget"])
-	bi.BaseInfo.PublishTime = common.Int64All(obj["publishtime"])
-	bi.BaseInfo.BuyerSeoId = EsSeoId(false, common.InterfaceToStr(obj["buyer"]))
-	bi.BaseInfo.RecommendedService = common.IntAll(obj["recommended_service"])
-	//摘要
-	switch bi.BaseInfo.SubType {
-	case "拟建":
-		bi.Abstract.Proposed = &entity.Proposed{}
-		bi.Abstract.Proposed.ProjectName = bi.BaseInfo.ProjectName
-		bi.Abstract.Proposed.Area = bi.BaseInfo.Area
-		bi.Abstract.Proposed.Buyer = common.ObjToString(obj["owner"])
-		if bi.Abstract.Proposed.Buyer != "" {
-			bi.Abstract.Proposed.BuyerPortraitShow = true // len(GetEntInfo(strings.Split(bi.Abstract.Proposed.Buyer, ","))) > 0
-		}
-		bi.Abstract.Proposed.BuyerClass = bi.BaseInfo.BuyerClass
-		bi.Abstract.Proposed.TotalInvestment = common.InterfaceToStr(obj["total_investment"])
-		bi.Abstract.Proposed.ProjectPeriod = common.ObjToString(obj["projectperiod"])
-		bi.Abstract.Proposed.Address = common.ObjToString(obj["projectaddr"])
-		bi.Abstract.Proposed.ApproveDept = common.ObjToString(obj["approvedept"])
-		bi.Abstract.Proposed.ApproveContent = common.ObjToString(obj["approvecontent"])
-		bi.Abstract.Proposed.ApproveCode = common.ObjToString(obj["approvecode"])
-		bi.Abstract.Proposed.ApprovalNumber = common.ObjToString(obj["approvenumber"])
-		bi.Abstract.Proposed.ApproveTime = common.ObjToString(obj["approvetime"])
-		bi.Abstract.Proposed.ApproveStatus = common.ObjToString(obj["approvestatus"])
-		bi.Abstract.Proposed.Content = common.ObjToString(obj["project_scale"])
-	default:
-		bi.Abstract.Default = &entity.Default{}
-		bi.Abstract.Default.Buyer = common.ObjToString(obj["buyer"])
-		if bi.Abstract.Default.Buyer != "" {
-			bi.Abstract.Default.BuyerPortraitShow = true // len(GetEntInfo(strings.Split(bi.Abstract.Default.Buyer, ","))) > 0
-		}
-		//判断是否公开联系人信息
-		if common.Int64All(obj["buyerhint"]) != 2 {
-			bi.Abstract.Default.BuyerPerson = common.ObjToString(obj["buyerperson"])
-			bi.Abstract.Default.BuyerTel = common.ObjToString(obj["buyertel"])
-			//ContactInfo(common.ObjToString(obj["buyerperson"]), common.ObjToString(obj["buyertel"]))
-		}
-		bi.Abstract.Default.Agency = common.ObjToString(obj["agency"])
-		bi.Abstract.Default.AgencyPerson = common.ObjToString(obj["agencyperson"])
-		bi.Abstract.Default.AgencyTel = common.ObjToString(obj["agencytel"])
-		bi.Abstract.Default.SignEndTime = common.Int64All(obj["signendtime"])
-		bi.Abstract.Default.BidEndTime = common.Int64All(obj["bidendtime"])
-		bi.Abstract.Default.BidAmount = common.Float64All(obj["bidamount"])
-		entIdList, _ := obj["entidlist"].([]interface{})
-		entIds := common.ObjArrToStringArr(entIdList)
-		if obj["winnerorder"] != nil {
-			//中标候选人
-			winnerOrders := common.ObjArrToMapArr(obj["winnerorder"].([]interface{}))
-			if len(winnerOrders) > 0 {
-				winnerOrder := winnerOrders[0]
-				bi.Abstract.Default.WinnerInfos, bi.Abstract.Default.WinnerSeoMap = WinnerInfo(common.ObjToString(winnerOrder["entname"]), entIds, true)
-			}
-		} else if obj["s_winner"] != nil || obj["winner"] != nil {
-			//中标企业
-			winners := common.InterfaceToStr(obj["s_winner"])
-			if winners == "" {
-				winners = common.InterfaceToStr(obj["winner"])
-			}
-			bi.Abstract.Default.WinnerInfos, bi.Abstract.Default.WinnerSeoMap = WinnerInfo(winners, entIds, false)
-			if len(bi.Abstract.Default.WinnerInfos) > 0 {
-				bi.Abstract.Default.WinnerInfos[0].WinnerPerson = common.ObjToString(obj["winnerperson"])
-				bi.Abstract.Default.WinnerInfos[0].WinnerTel = common.ObjToString(obj["winnertel"])
-			}
-		}
-	}
-	//详情
-	bi.Detail.Detail = DetailFormat(strings.Trim(common.ObjToString(obj["detail"]), " "))
-	// p385调整为 除了从竞品爬虫到的新数据,不展示“查看原文链接”入口,其他公告都展示“查看原文链接”入口(包含客户管理系统-结构化数据,查看的标讯详情页)
-	//competehref字段来源:
-	infoFormat := common.IntAllDef(obj["infoformat"], 1)
-	obj["infoformat"] = infoFormat //信息类型,1代表标讯,2代表拟建,3代表产权
-	//href="#"为竞品
-	href := common.ObjToString(obj["href"])
-	//竞品及剑鱼信息发布的招标信息,不显示查看原文
-	if href != "" && href != "#" && common.ObjToString(obj["site"]) != consts.JyTxt {
-		bi.Detail.OriginalShow = true
-	}
-	//附件
-	if obj["projectinfo"] != nil {
-		projectInfo := common.ObjToMap(obj["projectinfo"])
-		if projectInfo != nil && (*projectInfo)["attachments"] != nil {
-			attachments := common.ObjToMap((*projectInfo)["attachments"])
-			for _, attachment := range *attachments {
-				at := common.ObjToMap(attachment)
-				bi.Detail.Attachments = append(bi.Detail.Attachments, entity.Attachment{
-					FileName: common.ObjToString((*at)["filename"]),
-					FileType: common.ObjToString((*at)["ftype"]),
-					FileSize: common.ObjToString((*at)["size"]),
-				})
-			}
-		}
-	}
-	return bi
+    var (
+        bi = &entity.BidInfo{
+            BaseInfo: &entity.BidBaseInfo{},
+            Abstract: &entity.Abstract{},
+            Detail:   &entity.DetailInfo{},
+            CanRead:  true,
+        }
+    )
+    //基本信息
+    bi.BaseInfo.Id = encrypt.EncodeArticleId2ByCheck(id)
+    industry := common.ObjToString(obj["s_subscopeclass"])
+    if industry != "" {
+        industry = strings.Replace(industry, "它", "他", -1)
+        industry = strings.Split(industry, ",")[0]
+    }
+    bi.BaseInfo.Industry = industry
+    title := common.ObjToString(obj["title"])
+    if len([]rune(title)) > dc.Config.TitleSize {
+        title = fmt.Sprintf("%s...", string([]rune(title)[:dc.Config.TitleSize]))
+    }
+    bi.BaseInfo.Title = title
+    bi.BaseInfo.Area = common.ObjToString(obj["area"])
+    bi.BaseInfo.Purchasing = common.ObjToString(obj["purchasing"])
+    bi.BaseInfo.ProjectName = common.ObjToString(obj["projectname"])
+    bi.BaseInfo.ProjectCode = common.ObjToString(obj["projectcode"])
+    bi.BaseInfo.City = common.ObjToString(obj["city"])
+    bi.BaseInfo.BuyerClass = common.ObjToString(obj["buyerclass"])
+    bi.BaseInfo.District = common.ObjToString(obj["district"])
+    bi.BaseInfo.Site = common.ObjToString(obj["site"])
+    bi.BaseInfo.SubType = common.ObjToString(obj["subtype"])
+    bi.BaseInfo.TopType = common.ObjToString(obj["toptype"])
+    if bi.BaseInfo.SubType == "" {
+        bi.BaseInfo.SubType = bi.BaseInfo.TopType
+    }
+    bi.BaseInfo.BidAmount = common.Int64All(obj["bidamount"])
+    bi.BaseInfo.Budget = common.Int64All(obj["budget"])
+    bi.BaseInfo.PublishTime = common.Int64All(obj["publishtime"])
+    bi.BaseInfo.BuyerSeoId = EsSeoId(false, common.InterfaceToStr(obj["buyer"]))
+    bi.BaseInfo.RecommendedService = common.IntAll(obj["recommended_service"])
+    //摘要
+    switch bi.BaseInfo.SubType {
+    case "拟建":
+        bi.Abstract.Proposed = &entity.Proposed{}
+        bi.Abstract.Proposed.ProjectName = bi.BaseInfo.ProjectName
+        bi.Abstract.Proposed.Area = bi.BaseInfo.Area
+        bi.Abstract.Proposed.Buyer = common.ObjToString(obj["owner"])
+        if bi.Abstract.Proposed.Buyer != "" {
+            bi.Abstract.Proposed.BuyerPortraitShow = true // len(GetEntInfo(strings.Split(bi.Abstract.Proposed.Buyer, ","))) > 0
+        }
+        bi.Abstract.Proposed.BuyerClass = bi.BaseInfo.BuyerClass
+        bi.Abstract.Proposed.TotalInvestment = common.InterfaceToStr(obj["total_investment"])
+        bi.Abstract.Proposed.ProjectPeriod = common.ObjToString(obj["projectperiod"])
+        bi.Abstract.Proposed.Address = common.ObjToString(obj["projectaddr"])
+        bi.Abstract.Proposed.ApproveDept = common.ObjToString(obj["approvedept"])
+        bi.Abstract.Proposed.ApproveContent = common.ObjToString(obj["approvecontent"])
+        bi.Abstract.Proposed.ApproveCode = common.ObjToString(obj["approvecode"])
+        bi.Abstract.Proposed.ApprovalNumber = common.ObjToString(obj["approvenumber"])
+        bi.Abstract.Proposed.ApproveTime = common.ObjToString(obj["approvetime"])
+        bi.Abstract.Proposed.ApproveStatus = common.ObjToString(obj["approvestatus"])
+        bi.Abstract.Proposed.Content = common.ObjToString(obj["project_scale"])
+    default:
+        bi.Abstract.Default = &entity.Default{}
+        bi.Abstract.Default.Buyer = common.ObjToString(obj["buyer"])
+        if bi.Abstract.Default.Buyer != "" {
+            bi.Abstract.Default.BuyerPortraitShow = true // len(GetEntInfo(strings.Split(bi.Abstract.Default.Buyer, ","))) > 0
+        }
+        //判断是否公开联系人信息
+        if common.Int64All(obj["buyerhint"]) != 2 {
+            bi.Abstract.Default.BuyerPerson = common.ObjToString(obj["buyerperson"])
+            bi.Abstract.Default.BuyerTel = common.ObjToString(obj["buyertel"])
+            //ContactInfo(common.ObjToString(obj["buyerperson"]), common.ObjToString(obj["buyertel"]))
+        }
+        bi.Abstract.Default.Agency = common.ObjToString(obj["agency"])
+        bi.Abstract.Default.AgencyPerson = common.ObjToString(obj["agencyperson"])
+        bi.Abstract.Default.AgencyTel = common.ObjToString(obj["agencytel"])
+        bi.Abstract.Default.SignEndTime = common.Int64All(obj["signendtime"])
+        bi.Abstract.Default.BidEndTime = common.Int64All(obj["bidendtime"])
+        bi.Abstract.Default.BidAmount = common.Float64All(obj["bidamount"])
+        entIdList, _ := obj["entidlist"].([]interface{})
+        entIds := common.ObjArrToStringArr(entIdList)
+        if obj["winnerorder"] != nil {
+            //中标候选人
+            winnerOrders := common.ObjArrToMapArr(obj["winnerorder"].([]interface{}))
+            if len(winnerOrders) > 0 {
+                winnerOrder := winnerOrders[0]
+                bi.Abstract.Default.WinnerInfos, bi.Abstract.Default.WinnerSeoMap = WinnerInfo(common.ObjToString(winnerOrder["entname"]), entIds, true)
+            }
+        } else if obj["s_winner"] != nil || obj["winner"] != nil {
+            //中标企业
+            winners := common.InterfaceToStr(obj["s_winner"])
+            if winners == "" {
+                winners = common.InterfaceToStr(obj["winner"])
+            }
+            bi.Abstract.Default.WinnerInfos, bi.Abstract.Default.WinnerSeoMap = WinnerInfo(winners, entIds, false)
+            if len(bi.Abstract.Default.WinnerInfos) > 0 {
+                bi.Abstract.Default.WinnerInfos[0].WinnerPerson = common.ObjToString(obj["winnerperson"])
+                bi.Abstract.Default.WinnerInfos[0].WinnerTel = common.ObjToString(obj["winnertel"])
+            }
+        }
+    }
+    //详情
+    bi.Detail.Detail = DetailFormat(strings.Trim(common.ObjToString(obj["detail"]), " "))
+    // p385调整为 除了从竞品爬虫到的新数据,不展示“查看原文链接”入口,其他公告都展示“查看原文链接”入口(包含客户管理系统-结构化数据,查看的标讯详情页)
+    //competehref字段来源:
+    infoFormat := common.IntAllDef(obj["infoformat"], 1)
+    obj["infoformat"] = infoFormat //信息类型,1代表标讯,2代表拟建,3代表产权
+    //href="#"为竞品
+    href := common.ObjToString(obj["href"])
+    //竞品及剑鱼信息发布的招标信息,不显示查看原文
+    if href != "" && href != "#" && common.ObjToString(obj["site"]) != consts.JyTxt {
+        bi.Detail.OriginalShow = true
+    }
+    //附件
+    if obj["projectinfo"] != nil {
+        projectInfo := common.ObjToMap(obj["projectinfo"])
+        if projectInfo != nil && (*projectInfo)["attachments"] != nil {
+            attachments := common.ObjToMap((*projectInfo)["attachments"])
+            for _, attachment := range *attachments {
+                at := common.ObjToMap(attachment)
+                bi.Detail.Attachments = append(bi.Detail.Attachments, entity.Attachment{
+                    FileName: common.ObjToString((*at)["filename"]),
+                    FileType: common.ObjToString((*at)["ftype"]),
+                    FileSize: common.ObjToString((*at)["size"]),
+                })
+            }
+        }
+    }
+    return bi
 }
 
 // 详情
 func DetailFormat(detail string) (fd string) {
-	if detail != "" {
-		//detail字段 缺少标签 处理
-		for _, v := range dc.Config.DetailElement {
-			var intOpen = strings.Count(detail, "<"+v)
-			var intClose = strings.Count(detail, "</"+v+">")
-			if intOpen >= intClose {
-				for di := 0; di < (intOpen - intClose); di++ {
-					detail += "</" + v + ">"
-				}
-			} else {
-				for di := 0; di < (intClose - intOpen); di++ {
-					detail = "<" + v + ">" + detail
-				}
-			}
-		}
-		fd = detail
-	}
-	return
+    if detail != "" {
+        //detail字段 缺少标签 处理
+        for _, v := range dc.Config.DetailElement {
+            var intOpen = strings.Count(detail, "<"+v)
+            var intClose = strings.Count(detail, "</"+v+">")
+            if intOpen >= intClose {
+                for di := 0; di < (intOpen - intClose); di++ {
+                    detail += "</" + v + ">"
+                }
+            } else {
+                for di := 0; di < (intClose - intOpen); di++ {
+                    detail = "<" + v + ">" + detail
+                }
+            }
+        }
+        fd = detail
+    }
+    return
 }
 
 // 联系人/联系方式
 func ContactInfo(name, link string) (str string) {
-	if name != "" && link != "" {
-		str = fmt.Sprintf("%s/%s", name, link)
-	} else if name == "" && link != "" {
-		str = link
-	} else if name != "" && link == "" {
-		str = name
-	}
-	return
+    if name != "" && link != "" {
+        str = fmt.Sprintf("%s/%s", name, link)
+    } else if name == "" && link != "" {
+        str = link
+    } else if name != "" && link == "" {
+        str = name
+    }
+    return
 }
 
 // 企业信息
 func WinnerInfo(winners string, winnerIds []string, candidate bool) (wis []entity.WinnerInfo, wsm map[string]interface{}) {
-	if winners == "" {
-		return
-	}
-	wsm = map[string]interface{}{}
-	winnerArr := strings.Split(winners, ",")
-	if len(winnerIds) != len(winnerArr) {
-		for _, v := range strings.Split(winners, ",") {
-			if v == "-" || v == "" {
-				continue
-			}
-			//临时更改为企业名称查询企业id
-			rData := elastic.Get("qyxy", "qyxy", fmt.Sprintf(`{"query":{"bool":{"should":[{"term":{"company_name":"%s"}},{"term":{"hname":"%s"}}],"minimum_should_match":1}},"_source":["name","_id","nseo_id","capital","company_phone"],"size":1}`, v, v))
-			if rData != nil && len(*rData) == 1 {
-				if entId := common.ObjToString((*rData)[0]["_id"]); entId != "" {
-					wis = append(wis, entity.WinnerInfo{
-						Winner:      v,
-						WinnerId:    encrypt.EncodeArticleId2ByCheck(entId),
-						IsCandidate: candidate,
-					})
-					wsm[v] = (*rData)[0]["nseo_id"]
-				}
-			}
-		}
-	} else {
-		for k, v := range winnerIds {
-			winnerId := common.ObjToString(v)
-			if winnerId == "-" || winnerId == "" {
-				continue
-			}
-			wis = append(wis, entity.WinnerInfo{
-				Winner:      winnerArr[k],
-				WinnerId:    encrypt.EncodeArticleId2ByCheck(winnerId),
-				IsCandidate: candidate,
-			})
-			wsm[winnerArr[k]] = EsSeoId(true, winnerId)
-		}
-	}
-	return
+    if winners == "" {
+        return
+    }
+    wsm = map[string]interface{}{}
+    winnerArr := strings.Split(winners, ",")
+    if len(winnerIds) != len(winnerArr) {
+        for _, v := range strings.Split(winners, ",") {
+            if v == "-" || v == "" {
+                continue
+            }
+            //临时更改为企业名称查询企业id
+            rData := elastic.Get("qyxy", "qyxy", fmt.Sprintf(`{"query":{"bool":{"should":[{"term":{"company_name":"%s"}},{"term":{"hname":"%s"}}],"minimum_should_match":1}},"_source":["name","_id","nseo_id","capital","company_phone"],"size":1}`, v, v))
+            if rData != nil && len(*rData) == 1 {
+                if entId := common.ObjToString((*rData)[0]["_id"]); entId != "" {
+                    wis = append(wis, entity.WinnerInfo{
+                        Winner:      v,
+                        WinnerId:    encrypt.EncodeArticleId2ByCheck(entId),
+                        IsCandidate: candidate,
+                    })
+                    wsm[v] = (*rData)[0]["nseo_id"]
+                }
+            }
+        }
+    } else {
+        for k, v := range winnerIds {
+            winnerId := common.ObjToString(v)
+            if winnerId == "-" || winnerId == "" {
+                continue
+            }
+            wis = append(wis, entity.WinnerInfo{
+                Winner:      winnerArr[k],
+                WinnerId:    encrypt.EncodeArticleId2ByCheck(winnerId),
+                IsCandidate: candidate,
+            })
+            wsm[winnerArr[k]] = EsSeoId(true, winnerId)
+        }
+    }
+    return
 }
 
 // 采购单位 中标企业 seo 信息
 func EsSeoId(isWinner bool, idName string) string {
-	if idName == "" {
-		return idName
-	}
-	var seoId string
-	redisKey := fmt.Sprintf("getSeoId_%v_%s", isWinner, idName)
-	seoId = redis.GetStr(consts.RedisNewOther, redisKey)
-	if seoId != "" {
-		return seoId
-	}
+    if idName == "" {
+        return idName
+    }
+    var seoId string
+    redisKey := fmt.Sprintf("getSeoId_%v_%s", isWinner, idName)
+    seoId = redis.GetStr(consts.RedisNewOther, redisKey)
+    if seoId != "" {
+        return seoId
+    }
 
-	if isWinner {
-		winnerSeo := elastic.GetById("qyxy", "qyxy", idName)
-		if winnerSeo != nil && len(*winnerSeo) > 0 {
-			seoId = common.InterfaceToStr((*winnerSeo)[0]["nseo_id"])
-		}
-	} else {
-		q := fmt.Sprintf(`{"query": {"bool": {"must": [{"match": {"buyer_name": "%s"}}]}},"from": 0,"size": 1,"_source":["seo_id"]}`, idName)
-		winnerSeo := elastic.Get("buyer", "buyer", q)
-		if winnerSeo != nil && len(*winnerSeo) > 0 {
-			seoId = common.InterfaceToStr((*winnerSeo)[0]["seo_id"])
-		}
-	}
-	if seoId != "" {
-		redis.Put("newother", redisKey, seoId, -1)
-	}
-	return seoId
+    if isWinner {
+        winnerSeo := elastic.GetById("qyxy", "qyxy", idName)
+        if winnerSeo != nil && len(*winnerSeo) > 0 {
+            seoId = common.InterfaceToStr((*winnerSeo)[0]["nseo_id"])
+        }
+    } else {
+        q := fmt.Sprintf(`{"query": {"bool": {"must": [{"match": {"buyer_name": "%s"}}]}},"from": 0,"size": 1,"_source":["seo_id"]}`, idName)
+        winnerSeo := elastic.Get("buyer", "buyer", q)
+        if winnerSeo != nil && len(*winnerSeo) > 0 {
+            seoId = common.InterfaceToStr((*winnerSeo)[0]["seo_id"])
+        }
+    }
+    if seoId != "" {
+        redis.Put("newother", redisKey, seoId, -1)
+    }
+    return seoId
 }
 
 // 手机号
 func NumberCodeFormat(bi *entity.BidInfo) {
-	//采购电话中标单位电话置空
-	if bi.Abstract.Default.BuyerPerson != "" {
-		bi.Abstract.Default.BuyerPerson = "freeView"
-		bi.Abstract.Default.BuyerTel = ""
-	}
-	if len(bi.Abstract.Default.WinnerInfos) > 0 {
-		bi.Abstract.Default.WinnerInfos[0].WinnerPerson = "freeView"
-		bi.Abstract.Default.WinnerInfos[0].WinnerTel = ""
-	}
-	//正文电话 手机号 邮箱处理
-	if bi.Detail.Detail != "" {
-		//手机号
-		detail := regexp.MustCompile("1[345789]{1}\\d{9}").ReplaceAllString(bi.Detail.Detail, `<span class="freeView">点击查看</span>`)
-		//项目代码
-		code := bi.BaseInfo.ProjectCode
-		if code != "" {
-			detail = strings.ReplaceAll(detail, code, "*********")
-		}
-		//座机
-		landlineRegexp := regexp.MustCompile("((0\\d{2,3})-)(\\d{7,8})(-(\\d{3,}))?")
-		detail = landlineRegexp.ReplaceAllString(detail, `<span class="freeView">点击查看</span>`)
-		landlineRegexp400 := regexp.MustCompile("((400)-)(\\d{3,4}-)(\\d{3,})")
-		detail = landlineRegexp400.ReplaceAllString(detail, `<span class="freeView">点击查看</span>`)
-		//邮箱
-		mailboxRegexp := regexp.MustCompile("([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)")
-		detail = mailboxRegexp.ReplaceAllString(detail, `<span class="freeView">点击查看</span>`)
-		bi.Detail.Detail = strings.ReplaceAll(strings.ReplaceAll(detail, `<span class="freeView">点击查看</span><span class="freeView">点击查看</span>`, `<span class="freeView">点击查看</span>`), "*********", code)
-	}
+    //采购电话中标单位电话置空
+    if bi.Abstract.Default.BuyerPerson != "" {
+        bi.Abstract.Default.BuyerPerson = "freeView"
+        bi.Abstract.Default.BuyerTel = ""
+    }
+    if len(bi.Abstract.Default.WinnerInfos) > 0 {
+        bi.Abstract.Default.WinnerInfos[0].WinnerPerson = "freeView"
+        bi.Abstract.Default.WinnerInfos[0].WinnerTel = ""
+    }
+    //正文电话 手机号 邮箱处理
+    if bi.Detail.Detail != "" {
+        //手机号
+        detail := regexp.MustCompile("1[345789]{1}\\d{9}").ReplaceAllString(bi.Detail.Detail, `<span class="freeView">点击查看</span>`)
+        //项目代码
+        code := bi.BaseInfo.ProjectCode
+        if code != "" {
+            detail = strings.ReplaceAll(detail, code, "*********")
+        }
+        //座机
+        landlineRegexp := regexp.MustCompile("((0\\d{2,3})-)(\\d{7,8})(-(\\d{3,}))?")
+        detail = landlineRegexp.ReplaceAllString(detail, `<span class="freeView">点击查看</span>`)
+        landlineRegexp400 := regexp.MustCompile("((400)-)(\\d{3,4}-)(\\d{3,})")
+        detail = landlineRegexp400.ReplaceAllString(detail, `<span class="freeView">点击查看</span>`)
+        //邮箱
+        mailboxRegexp := regexp.MustCompile("([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)")
+        detail = mailboxRegexp.ReplaceAllString(detail, `<span class="freeView">点击查看</span>`)
+        bi.Detail.Detail = strings.ReplaceAll(strings.ReplaceAll(detail, `<span class="freeView">点击查看</span><span class="freeView">点击查看</span>`, `<span class="freeView">点击查看</span>`), "*********", code)
+    }
 }
 
 // 关键词
 func KeyWordHandle(obj map[string]interface{}) string {
-	keywordArr := []string{}
-	owner := common.InterfaceToStr(obj["owner"])
-	buyer := common.InterfaceToStr(obj["buyer"])
-	if buyer == "" {
-		buyer = owner
-	}
-	if buyer != "" && buyer != dc.Config.DetailMosaicTxt {
-		keywordArr = append(keywordArr, buyer)
-	}
-	if common.InterfaceToStr(obj["s_winner"]) != "" && common.InterfaceToStr(obj["s_winner"]) != dc.Config.DetailMosaicTxt {
-		keywordArr = append(keywordArr, common.InterfaceToStr(obj["s_winner"]))
-	}
-	if obj["purchasinglist"] != nil && obj["purchasinglist"] != "" {
-		i := 0
-		for _, v := range gconv.SliceMap(obj["purchasinglist"]) {
-			if i == 5 {
-				break
-			}
-			if common.InterfaceToStr(v["itemname"]) != "" && common.InterfaceToStr(obj["s_winner"]) != dc.Config.DetailMosaicTxt {
-				keywordArr = append(keywordArr, common.InterfaceToStr(v["itemname"]))
-				i++
-			}
-		}
-	}
-	if common.InterfaceToStr(obj["subtype"]) != "" && common.InterfaceToStr(obj["subtype"]) != "其它" {
-		keywordArr = append(keywordArr, consts.TypeCodeMap[common.InterfaceToStr(obj["subtype"])])
-	}
-	if common.InterfaceToStr(obj["area"]) != "" {
-		keywordArr = append(keywordArr, common.InterfaceToStr(obj["area"])+"招标")
-	}
-	if common.InterfaceToStr(obj["city"]) != "" {
-		keywordArr = append(keywordArr, common.InterfaceToStr(obj["city"])+"招标")
-	}
-	keywordArr = append(keywordArr, "剑鱼标讯")
-	keyword := strings.Join(keywordArr, ",")
-	return keyword
+    keywordArr := []string{}
+    owner := common.InterfaceToStr(obj["owner"])
+    buyer := common.InterfaceToStr(obj["buyer"])
+    if buyer == "" {
+        buyer = owner
+    }
+    if buyer != "" && buyer != dc.Config.DetailMosaicTxt {
+        keywordArr = append(keywordArr, buyer)
+    }
+    if common.InterfaceToStr(obj["s_winner"]) != "" && common.InterfaceToStr(obj["s_winner"]) != dc.Config.DetailMosaicTxt {
+        keywordArr = append(keywordArr, common.InterfaceToStr(obj["s_winner"]))
+    }
+    if obj["purchasinglist"] != nil && obj["purchasinglist"] != "" {
+        i := 0
+        for _, v := range gconv.SliceMap(obj["purchasinglist"]) {
+            if i == 5 {
+                break
+            }
+            if common.InterfaceToStr(v["itemname"]) != "" && common.InterfaceToStr(obj["s_winner"]) != dc.Config.DetailMosaicTxt {
+                keywordArr = append(keywordArr, common.InterfaceToStr(v["itemname"]))
+                i++
+            }
+        }
+    }
+    if common.InterfaceToStr(obj["subtype"]) != "" && common.InterfaceToStr(obj["subtype"]) != "其它" {
+        keywordArr = append(keywordArr, consts.TypeCodeMap[common.InterfaceToStr(obj["subtype"])])
+    }
+    if common.InterfaceToStr(obj["area"]) != "" {
+        keywordArr = append(keywordArr, common.InterfaceToStr(obj["area"])+"招标")
+    }
+    if common.InterfaceToStr(obj["city"]) != "" {
+        keywordArr = append(keywordArr, common.InterfaceToStr(obj["city"])+"招标")
+    }
+    keywordArr = append(keywordArr, "剑鱼标讯")
+    keyword := strings.Join(keywordArr, ",")
+    return keyword
 }
 
 // 描述
 func DescriptionHandle(stype string, obj map[string]interface{}) string {
-	description := ""
-	publishtime := common.Int64All(obj["l_publishtime"])
-	if publishtime == 0 {
-		publishtime = common.Int64All(obj["publishtime"])
-	}
-	pushTime := time.Unix(publishtime, 0)
-	title := common.InterfaceToStr(obj["title"])
-	owner := common.InterfaceToStr(obj["owner"])
-	buyer := common.InterfaceToStr(obj["buyer"])
-	if buyer == "" {
-		buyer = owner
-	}
-	s_winner := common.InterfaceToStr(obj["s_winner"])
-	area := common.InterfaceToStr(obj["area"])
-	city := common.InterfaceToStr(obj["city"])
-	if stype == "bdprivate" {
-		//bdprivate
-		//{项目标题},采购单位:{采购单位名称},成交供应商:{中标企业名称},公告日期:{公告日期}。
-		descriptionArr := []string{}
-		if title != "" {
-			descriptionArr = append(descriptionArr, title)
-		}
-		if buyer != "" {
-			descriptionArr = append(descriptionArr, fmt.Sprintf("采购单位:%s", buyer))
-		}
-		if s_winner != "" {
-			descriptionArr = append(descriptionArr, fmt.Sprintf("成交供应商:%s", s_winner))
-		}
-		if publishtime != 0 {
-			descriptionArr = append(descriptionArr, fmt.Sprintf("公告日期:%s", pushTime.Format("2006年01月02日")))
-		}
-		descriptionArr = append(descriptionArr, "查看该项目信息详情请访问剑鱼标讯官网。")
-		description = strings.Join(descriptionArr, ",")
-	} else {
-		//descriptionStr = "%s,项目所属地区是%s%s,项目采购单位是%s,项目发布时间是%s"
-		descriptionArr := []string{}
-		if title != "" {
-			descriptionArr = append(descriptionArr, title)
-		}
-		if area != "" || city != "" {
-			descriptionArr = append(descriptionArr, fmt.Sprintf("项目所属地区是%s%s", area, city))
-		}
-		if buyer != "" {
-			descriptionArr = append(descriptionArr, fmt.Sprintf("项目采购单位是%s", buyer))
-		}
-		if publishtime != 0 {
-			descriptionArr = append(descriptionArr, fmt.Sprintf("项目发布时间是%s", pushTime.Format("2006年01月02日")))
-		}
-		descriptionArr = append(descriptionArr, "查看该项目信息详情请访问剑鱼标讯官网。")
-		description = strings.Join(descriptionArr, ",")
-	}
-	return description
+    description := ""
+    publishtime := common.Int64All(obj["l_publishtime"])
+    if publishtime == 0 {
+        publishtime = common.Int64All(obj["publishtime"])
+    }
+    pushTime := time.Unix(publishtime, 0)
+    title := common.InterfaceToStr(obj["title"])
+    owner := common.InterfaceToStr(obj["owner"])
+    buyer := common.InterfaceToStr(obj["buyer"])
+    if buyer == "" {
+        buyer = owner
+    }
+    s_winner := common.InterfaceToStr(obj["s_winner"])
+    area := common.InterfaceToStr(obj["area"])
+    city := common.InterfaceToStr(obj["city"])
+    if stype == "bdprivate" {
+        //bdprivate
+        //{项目标题},采购单位:{采购单位名称},成交供应商:{中标企业名称},公告日期:{公告日期}。
+        descriptionArr := []string{}
+        if title != "" {
+            descriptionArr = append(descriptionArr, title)
+        }
+        if buyer != "" {
+            descriptionArr = append(descriptionArr, fmt.Sprintf("采购单位:%s", buyer))
+        }
+        if s_winner != "" {
+            descriptionArr = append(descriptionArr, fmt.Sprintf("成交供应商:%s", s_winner))
+        }
+        if publishtime != 0 {
+            descriptionArr = append(descriptionArr, fmt.Sprintf("公告日期:%s", pushTime.Format("2006年01月02日")))
+        }
+        descriptionArr = append(descriptionArr, "查看该项目信息详情请访问剑鱼标讯官网。")
+        description = strings.Join(descriptionArr, ",")
+    } else {
+        //descriptionStr = "%s,项目所属地区是%s%s,项目采购单位是%s,项目发布时间是%s"
+        descriptionArr := []string{}
+        if title != "" {
+            descriptionArr = append(descriptionArr, title)
+        }
+        if area != "" || city != "" {
+            descriptionArr = append(descriptionArr, fmt.Sprintf("项目所属地区是%s%s", area, city))
+        }
+        if buyer != "" {
+            descriptionArr = append(descriptionArr, fmt.Sprintf("项目采购单位是%s", buyer))
+        }
+        if publishtime != 0 {
+            descriptionArr = append(descriptionArr, fmt.Sprintf("项目发布时间是%s", pushTime.Format("2006年01月02日")))
+        }
+        descriptionArr = append(descriptionArr, "查看该项目信息详情请访问剑鱼标讯官网。")
+        description = strings.Join(descriptionArr, ",")
+    }
+    return description
 }

+ 7 - 0
src/jfw/modules/publicapply/src/detail/entity/config.go

@@ -10,4 +10,11 @@ type Config struct {
 	TokenExpireTime    int64
 	TermValidity       int64
 	BidServices        []Service
+	RestrictionSwitch  bool
+	Restrictions       map[string]reqLimit
+}
+
+type reqLimit struct {
+	DoPool   int `json:"doPool"`
+	WaitPool int `json:"waitPool"`
 }

+ 66 - 0
src/jfw/modules/publicapply/src/detail/restriction/restriction.go

@@ -0,0 +1,66 @@
+package restriction
+
+import (
+    "context"
+    "fmt"
+    "log"
+    "sync"
+    "time"
+)
+
+var (
+	ReqLimitMap  = map[string]*ReqLimit{}
+	reqLimitLock *sync.Mutex
+)
+
+type ReqLimit struct {
+	DoPool   chan struct{}
+	WaitPool chan struct{}
+}
+
+// -2 等待池已满
+// -1 超时
+// 1:可以执行查询
+func (r *ReqLimit) Limit(ctx context.Context) int {
+	ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
+	defer cancel()
+	select {
+	case <-r.WaitPool:
+		defer func() {
+			r.WaitPool <- struct{}{}
+		}()
+		select {
+		case <-r.DoPool:
+			return 1
+		case <-ctx.Done(): //超时
+			return -1
+		}
+	default:
+		return -2
+	}
+}
+
+// 回收
+func (r *ReqLimit) Release() {
+	r.DoPool <- struct{}{}
+}
+
+func ReqCheck(key string) (err error) {
+	reqLimitLock.Lock()
+	baseInfoLimit := ReqLimitMap[key]
+	reqLimitLock.Unlock()
+	if baseInfoLimit != nil {
+		if no := baseInfoLimit.Limit(context.Background()); no == 1 {
+			defer baseInfoLimit.Release()
+		} else {
+			if no == -2 {
+				err = fmt.Errorf("当前请求过于频繁,请稍后再试")
+			} else if no == -1 {
+				err = fmt.Errorf("当前请求超时,请稍后再试")
+			}
+			log.Println(fmt.Sprintf("%s err: %s", key, err.Error()))
+			return
+		}
+	}
+	return
+}