Browse Source

标讯三级页

renjiaojiao 9 months ago
parent
commit
62dc491888

+ 7 - 0
go.mod

@@ -24,8 +24,10 @@ require (
 	bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.15-0.20230925060020-8e4db0f1e13e // indirect
 	github.com/BurntSushi/toml v1.2.0 // indirect
 	github.com/ClickHouse/clickhouse-go/v2 v2.2.0 // indirect
+	github.com/RoaringBitmap/roaring v1.5.0 // indirect
 	github.com/andybalholm/cascadia v1.3.1 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/bits-and-blooms/bitset v1.2.0 // indirect
 	github.com/cenkalti/backoff/v4 v4.2.1 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/clbanning/mxj/v2 v2.7.0 // indirect
@@ -70,6 +72,7 @@ require (
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
+	github.com/mschoch/smat v0.2.0 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
 	github.com/nsqio/go-nsq v1.1.0 // indirect
 	github.com/olekukonko/tablewriter v0.0.5 // indirect
@@ -88,11 +91,15 @@ require (
 	github.com/rivo/uniseg v0.4.4 // indirect
 	github.com/shopspring/decimal v1.3.1 // indirect
 	github.com/spaolacci/murmur3 v1.1.0 // indirect
+	github.com/tealeg/xlsx v1.0.5 // indirect
+	github.com/thinxer/go-word2vec v0.0.0-20150917053916-5c19ec7379ed // indirect
 	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
 	github.com/xdg-go/scram v1.1.1 // indirect
 	github.com/xdg-go/stringprep v1.0.3 // indirect
+	github.com/yl2chen/cidranger v1.0.2 // indirect
 	github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
 	github.com/zeromicro/go-zero v1.5.3 // indirect
+	github.com/ziutek/blas v0.0.0-20190227122918-da4ca23e90bb // indirect
 	go.etcd.io/etcd/api/v3 v3.5.9 // indirect
 	go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
 	go.etcd.io/etcd/client/v3 v3.5.9 // indirect

+ 10 - 0
go.sum

@@ -77,6 +77,7 @@ github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAc
 github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
 github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/RoaringBitmap/roaring v1.5.0 h1:V0VCSiHjroItEYCM3guC8T83ehi5QMt3oM9EefTTOms=
 github.com/RoaringBitmap/roaring v1.5.0/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE=
 github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
 github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs=
@@ -111,6 +112,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
 github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
 github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
 github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
@@ -599,6 +601,7 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6f
 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
 github.com/mozillazg/go-pinyin v0.20.0 h1:BtR3DsxpApHfKReaPO1fCqF4pThRwH9uwvXzm+GnMFQ=
 github.com/mozillazg/go-pinyin v0.20.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc=
+github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
 github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
@@ -773,6 +776,10 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
 github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
 github.com/tal-tech/go-zero v1.1.5/go.mod h1:LbN0C7/rbl2+LUWTSUYx5leXmgedeMWjt1jc3/8/zFA=
+github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
+github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM=
+github.com/thinxer/go-word2vec v0.0.0-20150917053916-5c19ec7379ed h1:1+oKuPuDQ4AbN1WRMFxl9WQClH80GuZ81X/4FsOshjI=
+github.com/thinxer/go-word2vec v0.0.0-20150917053916-5c19ec7379ed/go.mod h1:WE5pZgSp3RwicfhHQmOJOexA0n4AKTzBqmnSu7R8Nbk=
 github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
@@ -797,6 +804,7 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhe
 github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY=
+github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
 github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
@@ -815,6 +823,8 @@ github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxt
 github.com/zeromicro/go-zero v1.3.5/go.mod h1:wh4o794b7Ul3W0k35Pw9nc3iB4O0OpaQTMQz/PJc1bc=
 github.com/zeromicro/go-zero v1.5.3 h1:9poyd+raeL7gSMUu6P19N7bssTppieR2j7Oos2j1yFQ=
 github.com/zeromicro/go-zero v1.5.3/go.mod h1:dmoBpgJTxt9KWmgrNGpv06XxZRPXMakrxUVgROFAR3g=
+github.com/ziutek/blas v0.0.0-20190227122918-da4ca23e90bb h1:uWiILQloLUVdtPYr1ZZo2zqtlpzo4G8vUpglo/Fs2H8=
+github.com/ziutek/blas v0.0.0-20190227122918-da4ca23e90bb/go.mod h1:J3xKssoVdrwZ2E29fIox/EKxOZWimS7AZ4fOTCFkOLo=
 github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
 go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
 go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698/go.mod h1:YoUyTScD3Vcv2RBm3eGVOq7i1ULiz3OuXoQFWOirmAM=

+ 4 - 4
internal/cmd/cmd.go

@@ -80,10 +80,10 @@ var (
 				group.GET("/dw/p{pageNum}", controller.EnterpriseList)     //采购单位列表
 				group.GET("/dw/{seoId}.html", controller.EnterpriseDetail) //采购单位详情
 
-				group.GET("/qy/", controller.EnterpriseList)                        //中标企业列表
-				group.GET("/qy/p{pageNum}", controller.EnterpriseList)              //中标企业列表
-				group.GET("/qy/{seoId}.html", controller.EnterpriseDetail)          //中标企业详情
-				group.GET("/nologin/content/{bxId}.html", controller.DetailHandler) //标讯详情
+				group.GET("/qy/", controller.EnterpriseList)                         //中标企业列表
+				group.GET("/qy/p{pageNum}", controller.EnterpriseList)               //中标企业列表
+				group.GET("/qy/{seoId}.html", controller.EnterpriseDetail)           //中标企业详情
+				group.GET("/nologin/content/{bidId}.html", controller.DetailHandler) //标讯详情
 
 			})
 			s.AddStaticPath("/jyseo", "/resource/staticres") //静态资源

+ 55 - 0
internal/controller/bidDetail.go

@@ -0,0 +1,55 @@
+package controller
+
+import (
+	util "app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/encrypt"
+	"fmt"
+	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/net/ghttp"
+	"jyseo/internal/service"
+	"jyseo/utility"
+	"strings"
+)
+
+func DetailHandler(r *ghttp.Request) {
+	bidId := r.Get("bidId").String()
+	isLogin := utility.JySessionLoginEd(r)
+	if isLogin {
+		service.HtmlRender.NotFound(r)
+		return
+	}
+	sids := encrypt.CommonDecodeArticle("content", bidId)
+	if len(sids) == 0 || (len(sids) > 0 && sids[0] == "") {
+		r.Response.RedirectTo(fmt.Sprintf("/front/notFind?t=%d", service.DecodeErr), 302)
+		return
+	}
+	//白名单
+	var isWhiteIp bool
+	ips := strings.Split(util.GetIp(r.Request), ",")
+	if len(ips) > 0 {
+		isWhiteIp = service.IpList.Match(ips[0])
+	}
+	canRead := true
+	bidData := service.GetBidInfo(sids[0], "content", isWhiteIp)
+	if bidData == nil || len(bidData) <= 0 {
+		r.Response.RedirectTo(fmt.Sprintf("/front/notFind?t=%d", service.DecodeErr), 302)
+		return
+		//return s.Redirect(getErrPageUrl(isMobile, QueryErr), 302)
+	}
+	// p397 未登录不能查看拟建项目
+	if !isWhiteIp && (bidData["subtype"] == "采购意向" || bidData["subtype"] == "拟建") { //未登录拟建 采购意向 遮罩
+		canRead = false
+	}
+
+	//最新招投标
+	//newBidInfoList := service.GetNewBidInfo(bidId, strings.Join(gconv.Strings(bidData["s_subscopeclass"]), ","), gconv.String(bidData["area"]), gconv.String(bidData["city"]))
+	//招投标攻略
+	industryInfoList := service.GetBiddingStrategy(10)
+	service.HtmlRender.Render(r, "detail.html",
+		g.Map{
+			"bidData": bidData,
+			//"newBidInfoList":   newBidInfoList,
+			"industryInfoList": industryInfoList,
+			"canRead":          canRead,
+		})
+}

+ 0 - 12
internal/controller/detail.go

@@ -1,12 +0,0 @@
-package controller
-
-import (
-	"github.com/gogf/gf/v2/frame/g"
-	"github.com/gogf/gf/v2/net/ghttp"
-	"jyseo/internal/service"
-)
-
-func DetailHandler(r *ghttp.Request) {
-	service.HtmlRender.Render(r, "detail.html",
-		g.Map{})
-}

+ 520 - 0
internal/service/bidDetail.go

@@ -0,0 +1,520 @@
+package service
+
+import (
+	util "app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/date"
+	"app.yhyue.com/moapp/jybase/encrypt"
+	elastic "app.yhyue.com/moapp/jybase/esv7"
+	"app.yhyue.com/moapp/jybase/ipmatch"
+	"app.yhyue.com/moapp/jybase/mongodb"
+	"app.yhyue.com/moapp/jypkg/common/src/qfw/util/bidsearch"
+	"app.yhyue.com/moapp/jypkg/public"
+	"context"
+	"fmt"
+	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/util/gconv"
+	"go.mongodb.org/mongo-driver/bson"
+	"html/template"
+	"jyseo/utility"
+	"regexp"
+	"strings"
+	"sync"
+	"time"
+)
+
+const (
+	DecodeErr = iota + 1
+	CacheTime = 60 * 60 * 8
+)
+
+var (
+	bidSearchField   = `"_id","title","publishtime","toptype","subtype","type","area","dataweight","city","s_subscopeclass","bidamount","budget","buyerclass","spidercode","site"`
+	IpList           *ipmatch.WhiteIp
+	IpInitLock       sync.RWMutex //锁
+	detailNeedMosaic map[string]interface{}
+	TypeCodeMap      = map[string]string{
+		"拟建":   "拟建项目",
+		"采购意向": "采购意向",
+		"预告":   "招标预告",
+		"预审":   "资格预审",
+		"预审结果": "资格预审结果",
+		"论证意见": "论证意见",
+		"需求公示": "需求公示",
+		"招标":   "公开招标",
+		"邀标":   "邀请招标",
+		"询价":   "询价采购",
+		"竞谈":   "竞争性谈判",
+		"单一":   "单一来源采购",
+		"竞价":   "竞价公告",
+		"变更":   "变更公告",
+		"中标":   "中标公示",
+		"成交":   "成交公告",
+		"废标":   "废标公告",
+		"流标":   "流标公告",
+		"合同":   "合同公告信息",
+		"验收":   "验收公告信息",
+		"违规":   "违规信息",
+	}
+)
+
+func init() {
+	IpInitLock.Lock()
+	defer IpInitLock.Unlock()
+	data, err := g.DB("tidb").Query(context.Background(), "select ip,ip_type,is_white from base_service.black_white where is_white = 1")
+	if err == nil && !data.IsEmpty() {
+		//log.Info("加载白名单")
+		var ips []ipmatch.IpParameter
+		for _, v := range data.List() {
+			var ipData ipmatch.IpParameter
+			ipData.Ip = util.InterfaceToStr(v["ip"])
+			ipData.IpType = util.IntAll(v["ip_type"])
+			ipData.IsWhite = util.IntAll(v["is_white"])
+			ips = append(ips, ipData)
+		}
+		IpList = ipmatch.NewRb(ips)
+		return
+	}
+	IpList = ipmatch.NewRb(nil)
+}
+
+// pc三级页跳转
+// 20170821增加查询字段s_subscopeclass
+func GetBidInfo(bidId, content string, isWhiteIp bool) (resData map[string]interface{}) {
+	bidCacheKey := fmt.Sprintf("jypcdetail_nologin_%s_%s_%v", "content", bidId, isWhiteIp)
+	cacheData, _ := g.Redis("limitation").Get(context.Background(), bidCacheKey)
+	if !cacheData.IsNil() && len(cacheData.Map()) > 0 {
+		return cacheData.Map()
+	}
+	defer util.Catch()
+	if len(bidId) > 5 {
+		if ok, bidData := FindBiding(bidId, content, 0); ok {
+			var purchasing = bidData["purchasing"]
+			if purchasing != nil && purchasing != "" {
+				bidData["purchasing"] = util.ObjToString(purchasing)
+			}
+			titleStr := util.ObjToString(bidData["title"])
+			if len([]rune(titleStr)) > 100 {
+				titleStr = string([]rune(titleStr)[:100]) + "..."
+			}
+			//titleTmp := util.If(len([]rune(titleStr)) > 100, string([]rune(titleStr)[:100])+"...", string(titleStr)).(string)
+			bidData["title"] = public.ClearHtml.ReplaceAllString(titleStr, "")
+			finalType := gconv.String(bidData["subtype"])
+			if finalType == "" {
+				finalType = util.ObjToString(bidData["toptype"])
+			}
+			if finalType == "" {
+				finalType = util.ObjToString(bidData["type"])
+				switch finalType {
+				case "bid":
+					finalType = "中标"
+				case "tender":
+					finalType = "招标"
+				default:
+					finalType = ""
+				}
+			}
+			bidData["stypeadd"] = GetBidTypeCode(finalType)
+			href := strings.Replace(gconv.String(bidData["href"]), "\n", "", -1)
+			if href != "" && !strings.HasPrefix(href, "http") {
+				href = "http://" + href
+			}
+			bidData["url"] = href
+			bidData["buyerSeoId"] = EsSeoId(false, util.InterfaceToStr(bidData["buyer"]))
+
+			bidData["agency"] = ""
+			if bidData["publishtime"] != nil {
+				bidData["publishtimeShorDate"] = time.Unix(util.Int64All(bidData["publishtime"]), 0).Format(date.Date_Short_Layout)
+			}
+			if !isWhiteIp { //非白名单用户
+				bidData = Filter(bidData)
+			}
+			bidData["description"] = DescriptionHandle("nologin", bidData)
+			bidData["keywords"] = KeyWordHandle(bidData)
+			g.Redis("limitation").SetEX(context.Background(), bidCacheKey, bidData, 60*2)
+			resData = bidData
+		}
+	}
+	return resData
+}
+
+// wx pc obj字段统一处理
+func FindBiding(sid, content string, lent int) (t bool, obj map[string]interface{}) {
+	brobj, ok := utility.MG.DB("bidding").Find("bidding_rec", bson.M{"s_id": sid}, `{"l_recoverydate":-1}`, nil, false, 0, 1)
+	if ok && (*brobj) != nil && len(*brobj) == 1 && (*brobj)[0] != nil {
+		obj = (*brobj)[0]
+	} else {
+		aobj, ok := utility.MG.DB("bidding").FindById(g.Cfg().MustGet(context.Background(), "mongodb.bidding.collection").String(), sid, nil)
+		if ok && (aobj == nil || *aobj == nil || len(*aobj) == 0) {
+			aobj, ok = utility.MG.DB("bidding").FindById(g.Cfg().MustGet(context.Background(), "mongodb.bidding.collection_back").String(), sid, nil)
+		}
+		obj = *aobj
+	}
+	if ok && obj != nil && len(obj) > lent {
+		t = true
+		if content != "indexcontent" && (gconv.String(obj["subtype"]) == "拟建" || gconv.String(obj["subtype"]) == "采购意向") {
+			if lent == 0 {
+				//delete(obj, "detail")
+				//delete(obj, "projectinfo")
+				goto env
+			}
+			for k, _ := range obj {
+				if k != "title" && k != "area" && k != "detail" && k != "projecttype" && k != "approvecity" && k != "procurementlist" && k != "projectinfo" && k != "subtype" && k != "toptype" && k != "publishtime" && k != "budget" && k != "bidamount" && k != "site" && k != "spidercode" && k != "recommended_service" &&
+					k != "owner" && k != "total_investment" && k != "projectaddr" && k != "projectperiod" && k != "approvedept" && k != "approvecontent" && k != "approvecode" && k != "approvenumber" && k != "approvetime" && k != "approvestatus" && k != "project_scale" && k != "projectname" {
+					delete(obj, k)
+				}
+			}
+		}
+	env:
+		obj["_id"] = encrypt.EncodeArticleId2ByCheck(sid)
+		infoformat := util.IntAllDef(obj["infoformat"], 1)
+		obj["infoformat"] = infoformat
+		// p385调整为 除了从竞品爬虫到的新数据,不展示“查看原文链接”入口,其他公告都展示“查看原文链接”入口(包含客户管理系统-结构化数据,查看的标讯详情页)
+		// 精准字段(竞争对手的地址) 或  拟建项目
+		//competehref字段来源:
+		//1、竞品采集 href="#" competehref=原网址
+		//2、2021-11-01后新增的爬虫 href=原网址 competehref="#"
+		if gconv.String(obj["href"]) == "#" || infoformat == 2 || gconv.String(obj["site"]) == "剑鱼信息发布平台" {
+			delete(obj, "href")
+			delete(obj, "competehref")
+		}
+		if strings.Trim(gconv.String(obj["detail"]), " ") == "" {
+			obj["detail"] = ""
+		} else if g.Cfg().MustGet(cxt, "detailElement").Strings() != nil {
+			//detail字段 缺少标签 处理
+			var arrTags = g.Cfg().MustGet(cxt, "detailElement").Strings()
+			var _detail = gconv.String(obj["detail"])
+			for _, v := range arrTags {
+				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
+					}
+				}
+			}
+			//seo清除正文h1标签
+			obj["detail"] = removeHTMLTagUsingRegex(_detail, "h1")
+		}
+	}
+	return
+}
+
+func GetBidTypeCode(stp string) string {
+	stypeArr := g.Cfg("global").MustGet(cxt, "stype").Maps()
+	var tpadd = ""
+	if stp != "" {
+		for _, v := range stypeArr {
+			if stp == gconv.String(v["name"]) {
+				tpadd = gconv.String(v["code"])
+			}
+		}
+	}
+	return tpadd
+}
+
+// 未登录用户进行数据过滤 name 配置文件
+func Filter(obj map[string]interface{}) map[string]interface{} {
+	detail := fmt.Sprint(obj["detail"])
+	mosaicText := fmt.Sprintf(`<span style="color:#2ABED1;">%s</span>`, g.Cfg("global").MustGet(context.Background(), "detailMosaic").String())
+	detailText := fmt.Sprintf(`<span class="noLoginMosaic" style="color: #2ABED1;">%s</span>`, g.Cfg("global").MustGet(context.Background(), "detailMosaic").String())
+	if detailNeedMosaic == nil {
+		detailNeedMosaic = g.Cfg("global").MustGet(context.Background(), "detailNeedMosaic").Map()
+	}
+	for dk, dv := range detailNeedMosaic {
+		if !dv.(bool) {
+			continue
+		}
+		if obj["package"] != nil {
+			pk := util.ObjToMap(obj["package"])
+			for _, pv := range *pk {
+				if pv != nil {
+					if page := util.ObjToMap(pv); page != nil {
+						if (*page)[dk] != nil {
+							(*page)[dk] = mosaicText
+						}
+						delete(*page, "text")
+					}
+				}
+			}
+		}
+		//if util.ObjToString(obj[dk]) != "" {
+		//	detail = strings.ReplaceAll(detail, util.ObjToString(obj[dk]), detailText)
+		//}
+		if util.InterfaceToStr(obj[dk]) != "" {
+			value, b := obj[dk].(float64)
+			if b {
+				replaceStr := fmt.Sprintf("%v", int64(value))
+				detail = strings.ReplaceAll(detail, replaceStr, detailText)
+			} else {
+				detail = strings.ReplaceAll(detail, util.InterfaceToStr(obj[dk]), detailText)
+			}
+		}
+		//中标企业信息
+		if dk == "winnerMap" {
+			winnerNewMap := map[string]interface{}{}
+			if obj[dk] != nil {
+				winnerMap := util.ObjToMap(obj[dk])
+				for _, wv := range *winnerMap {
+					winnerNewMap[mosaicText] = wv
+				}
+			}
+			obj[dk] = winnerNewMap
+		} else {
+			obj[dk] = mosaicText
+		}
+	}
+	obj["detail"] = detail
+	return obj
+}
+
+func removeHTMLTagUsingRegex(htmlText, tag string) string {
+	if strings.Index(htmlText, tag) == -1 {
+		return htmlText
+	}
+	re := regexp.MustCompile(fmt.Sprintf(`<%s.*?>(.*?)</%s>`, tag, tag))
+	cleanedText := re.ReplaceAllString(htmlText, "${1}")
+	return cleanedText
+}
+
+func DescriptionHandle(stype string, obj map[string]interface{}) string {
+	description := ""
+	publishtime := util.Int64All(obj["l_publishtime"])
+	if publishtime == 0 {
+		publishtime = util.Int64All(obj["publishtime"])
+	}
+	pushTime := time.Unix(publishtime, 0)
+	title := util.InterfaceToStr(obj["title"])
+	owner := util.InterfaceToStr(obj["owner"])
+	buyer := util.InterfaceToStr(obj["buyer"])
+	if buyer == "" {
+		buyer = owner
+	}
+	s_winner := util.InterfaceToStr(obj["s_winner"])
+	area := util.InterfaceToStr(obj["area"])
+	city := util.InterfaceToStr(obj["city"])
+	if stype == "bdprivate" {
+		//bdprivate
+		//{项目标题},采购单位:{采购单位名称},成交供应商:{中标企业名称},公告日期:{公告日期}。
+		descriptionArr := []string{}
+		if title != "" {
+			descriptionArr = append(descriptionArr, utility.StrLimitRune(title, g.Cfg().MustGet(context.TODO(), "seo.description.titleLimit", 48).Int()))
+		}
+		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, utility.StrLimitRune(title, g.Cfg().MustGet(context.TODO(), "seo.description.titleLimit", 48).Int()))
+		}
+		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
+}
+
+func EsSeoId(isWinner bool, idName string) string {
+	if idName == "" {
+		return idName
+	}
+	var seoId string
+	redisKey := fmt.Sprintf("getSeoId_%v_%s", isWinner, idName)
+	gv, _ := g.Redis("newother").Get(context.Background(), redisKey)
+	if gv.IsEmpty() && gv.String() != "" {
+		return gv.String()
+	}
+
+	if isWinner {
+		winnerSeo := elastic.GetById("qyxy", "qyxy", idName)
+		if winnerSeo != nil && len(*winnerSeo) > 0 {
+			seoId = gconv.String((*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 = gconv.String((*winnerSeo)[0]["seo_id"])
+		}
+	}
+	if seoId != "" {
+		g.Redis("newother").SetEX(context.Background(), redisKey, seoId, -1)
+	}
+	return seoId
+}
+
+func KeyWordHandle(obj map[string]interface{}) string {
+	keywordArr := []string{}
+	owner := util.InterfaceToStr(obj["owner"])
+	buyer := util.InterfaceToStr(obj["buyer"])
+	if buyer == "" {
+		buyer = owner
+	}
+	if buyer != "" && buyer != g.Cfg("global").MustGet(context.TODO(), "detailMosaicTxt", "略").String() {
+		keywordArr = append(keywordArr, buyer)
+	}
+	if util.InterfaceToStr(obj["s_winner"]) != "" && util.InterfaceToStr(obj["s_winner"]) != g.Cfg("global").MustGet(context.TODO(), "detailMosaicTxt", "略").String() {
+		keywordArr = append(keywordArr, util.InterfaceToStr(obj["s_winner"]))
+	}
+	if obj["purchasinglist"] != nil && obj["purchasinglist"] != "" {
+		i := 0
+		for _, v := range gconv.SliceMap(obj["purchasinglist"]) {
+			if i == 5 {
+				break
+			}
+			if util.InterfaceToStr(v["itemname"]) != "" && util.InterfaceToStr(obj["s_winner"]) != g.Cfg("global").MustGet(context.TODO(), "detailMosaicTxt", "略").String() {
+				keywordArr = append(keywordArr, util.InterfaceToStr(v["itemname"]))
+				i++
+			}
+		}
+	}
+	if util.InterfaceToStr(obj["subtype"]) != "" && util.InterfaceToStr(obj["subtype"]) != "其它" {
+		keywordArr = append(keywordArr, TypeCodeMap[util.InterfaceToStr(obj["subtype"])])
+	}
+	if util.InterfaceToStr(obj["area"]) != "" {
+		keywordArr = append(keywordArr, util.InterfaceToStr(obj["area"])+"招标")
+	}
+	if util.InterfaceToStr(obj["city"]) != "" {
+		keywordArr = append(keywordArr, util.InterfaceToStr(obj["city"])+"招标")
+	}
+	keywordArr = append(keywordArr, "剑鱼标讯")
+	keyword := strings.Join(keywordArr, ",")
+	return keyword
+}
+
+// 招投标攻略
+func GetBiddingStrategy(pageSize int) (res []map[string]interface{}) {
+	chKey := fmt.Sprintf("bidDetail_BiddingStrategy")
+	gv, _ := g.Redis().Get(context.Background(), chKey)
+	if !gv.IsNil() && len(gv.Maps()) > 0 {
+		res = gv.Maps()
+		return
+	}
+	queryMap := map[string]interface{}{
+		"i_status": 1,
+	}
+	total := utility.MG.DB().Count("content", queryMap)
+	if total == 0 {
+		return nil
+	}
+	data, _ := utility.MG.DB().Find("content", queryMap, `{"releasetime":-1}`, `{"s_title":1,"releasetime":1,"s_pic":1,"s_pic1":1,"l_createdate":1,"_id":1,"s_author":1,"i_viewnum":1}`, false, 0, pageSize)
+	res = []map[string]interface{}{}
+	if data != nil && len(*data) > 0 {
+		for _, m := range *data {
+			s_title, _ := m["s_title"].(string)
+			m["s_title"] = template.HTML(s_title)
+			tmpdate1, _ := m["releasetime"]
+			m["releasetime"] = util.TimeDiff(time.Unix(util.Int64All(tmpdate1), 0))
+			reltime := time.Unix(util.Int64All(tmpdate1), 0)
+			m["time"] = reltime.Format("2006-01-02") //首页展示
+			m["_id"] = se.EncodeString(mongodb.BsonIdToSId(m["_id"]))
+			m["url"] = fmt.Sprintf("/jyblog/%s.html", gconv.String(m["_id"]))
+			res = append(res, m)
+		}
+		g.Redis().SetEX(context.Background(), chKey, res, CacheTime)
+	}
+	return res
+}
+
+// 获取最新招标信息
+func GetNewBidInfo(bidId, industry, area, city string) (list []map[string]interface{}) {
+	var (
+		redisKey   = fmt.Sprintf("pcindex_newArticle_%s", bidId)
+		redisKeySL = fmt.Sprintf("pcindex_newArticle_second_level_%s", bidId) //二级缓存
+		redisLock  = &sync.Mutex{}
+		ri         int
+		rn         = 3
+	)
+	var newBidInfos = func() (list []map[string]interface{}) {
+		// p397 未登录详情页最新招投标信息去掉拟建
+		var (
+			now         = time.Now()
+			startTime   = fmt.Sprint(time.Date(now.Year(), now.Month(), now.Day()-7, now.Hour(), now.Minute(), now.Second(), 0, time.Local).Unix()) //最近7天
+			endTime     = fmt.Sprint(now.Unix())
+			publishTime = fmt.Sprintf("%s_%s", startTime, endTime)
+		)
+		_, _, lists := bidsearch.GetPcBidSearchData("", area, city, publishTime, "招标预告,招标公告,招标结果,招标信用信息", industry, "", "", "", "", "", "", "", 1, false, nil, bidSearchField, "", false, false, "", 50, "")
+		if lists != nil && len(*lists) > 0 {
+			if len(*lists) > 10 {
+				*lists = (*lists)[:10]
+			}
+			for _, v := range *lists {
+				v["_id"] = encrypt.CommonEncodeArticle("content", v["_id"].(string))
+				delete(v, "toptype")
+				delete(v, "s_subscopeclass")
+				tmpdate := v["publishtime"]
+				v["publishtime"] = gconv.Int64(tmpdate.(float64))
+				v["date"] = time.Unix(gconv.Int64(tmpdate.(float64)), 0).Format(date.Date_Short_Layout)
+				if v["budget"] != nil {
+					v["budget"] = utility.ConversionMoeny(v["budget"])
+				} else if v["bidamount"] != nil {
+					v["budget"] = utility.ConversionMoeny(v["bidamount"])
+				}
+			}
+			list = *lists
+		}
+		return
+	}
+	var bidInfosByCache = func(rk string) (list []map[string]interface{}) {
+		gv, _ := g.Redis().Get(context.Background(), rk)
+		if !gv.IsNil() && len(gv.Maps()) > 0 {
+			list = gv.Maps()
+		}
+		return
+	}
+	var bidInfosToCache = func(list []map[string]interface{}) {
+		if err := g.Redis().SetEX(context.Background(), redisKey, list, CacheTime); err != nil {
+			g.Log().Errorf(context.Background(), "最新招投标数据 存储redis err:%v", err)
+		}
+		if err := g.Redis().SetEX(context.Background(), redisKeySL, list, -1); err != nil {
+			g.Log().Errorf(context.Background(), "最新招投标二级数据 存储redis err:%v", err)
+		}
+		//redis.Put("seoCache", redisKey, list, cacheTime)
+		//ok := redis.Put("seoCache", redisKeySL, list, -1)
+		//log.Println(redisKeySL, "--00--", ok)
+	}
+	list = bidInfosByCache(redisKey)
+	if len(list) == 0 {
+		list = bidInfosByCache(redisKeySL)
+		if len(list) == 0 {
+			list = newBidInfos()
+			bidInfosToCache(list)
+		} else {
+			go func() {
+				for {
+					if redisLock.TryLock() {
+						bidInfosToCache(newBidInfos())
+						redisLock.Unlock()
+					}
+					ri++
+					if len(list) > 0 || ri >= rn {
+						break
+					}
+					time.Sleep(100 * time.Millisecond)
+				}
+			}()
+		}
+	}
+	return list
+}

+ 29 - 12
manifest/config/config.yaml

@@ -17,31 +17,40 @@ viewer:
   autoencode: true
 
 database:
-#  default:
-#    link: "clickhouse:jianyu_appl:Cli3#fkh4ouSe@tcp(127.0.0.1:9000)/jyseo?dial_timeout=2000ms&max_execution_time=60"
-#    debug: true
+  #  default:
+  #    link: "clickhouse:jianyu_appl:Cli3#fkh4ouSe@tcp(127.0.0.1:9000)/jyseo?dial_timeout=2000ms&max_execution_time=60"
+  #    debug: true
   default:
     link: "clickhouse:jytop:pwdTopJy123@tcp(192.168.3.207:19000)/jyseo_test?dial_timeout=2000ms&max_execution_time=60"
-    debug: true
+#    debug: true
   tidb:
     link: "mysql:root:=PDT49#80Z!RVv52_z@tcp(192.168.3.14:4000)/Jianyu_subjectdb"
     #debug: true
 
 mongodb:
   default:
-    address: "192.168.3.206:27080"
+    address: "192.168.3.149:27180"
     size: 5
     dbName: qfw
     replSet: ""
     userName: ""
     password: ""
   log:
-    address: "192.168.3.206:27090"
+    address: "192.168.3.149:27190"
     size: 5
     dbName: "qfw"
     replSet: ""
     userName: "admin"
     password: "123456"
+  bidding:
+    address: "192.168.3.149:27102"
+    size: 5
+    dbName: "qfw_data"
+    replSet: ""
+    collection: "bidding"
+    collection_back: "bidding_back"
+    userName: "jyDevGroup"
+    password: "jy@DevGroup"
 
 elasticsearch:
   default:
@@ -64,14 +73,19 @@ powerCheckCenterKey: "powercheck.rpc" #权益校验中台
 
 redis:
   default: # 配置seo的redis
-    address: 127.0.0.1:6379
-    #address: 192.168.3.149:1712
+    #address: 127.0.0.1:6379
+    address: 192.168.3.149:1712
   other: # 广告位
-    #address: 192.168.3.149:1712
-    address: 127.0.0.1:6379
+    address: 192.168.3.149:1712
+    #address: 127.0.0.1:6379
   session: # session
-    #address: 192.168.3.149:1712
-    address: 127.0.0.1:6379
+    address: 192.168.3.149:1712
+    #address: 127.0.0.1:6379
+  limitation:
+    address: 192.168.3.149:1712
+  newother:
+    address: 192.168.3.149:1712
+
 
 listPageSetting:
   pageSize: 50   #列表每页数量
@@ -105,3 +119,6 @@ redisTime: 7
 portraitCount: 30
 
 pdfPhone: "13027620557"
+detailElement:
+  - table
+  - div

File diff suppressed because it is too large
+ 1 - 1
manifest/config/global.yaml


+ 1 - 0
resource/template/pc/detail.html

@@ -3,6 +3,7 @@
 <head>
     <meta charset="UTF-8">
     <title>Title</title>
+    <h1>{{$global.canRead}}</h1>
 </head>
 <body>
 

+ 46 - 0
utility/util.go

@@ -1,6 +1,7 @@
 package utility
 
 import (
+	util "app.yhyue.com/moapp/jybase/common"
 	"app.yhyue.com/moapp/jybase/encrypt"
 	"context"
 	"fmt"
@@ -146,3 +147,48 @@ func GetJySessionVal(r *ghttp.Request) (hasLogin bool, sessVal map[string]interf
 	}
 	return
 }
+
+func StrLimitRune(str string, length int, suffix ...string) string {
+	runes := []rune(str)
+	if len(runes) < length {
+		return str
+	}
+	suffixStr := "..."
+	if len(suffix) > 0 {
+		suffixStr = suffix[0]
+	}
+	return string(runes[0:length]) + suffixStr
+}
+
+// 金额转化   金额:0-万元以下单位为元  ,万元以上至亿元以下单位为万元 ,亿元以上单位为亿元。保留 小数点后 2 位,不进行四舍五入。
+func ConversionMoeny(i_money interface{}) string {
+	m := ""
+	if reflect.TypeOf(i_money).Name() == "float64" {
+		m = strconv.FormatFloat(util.Float64All(i_money), 'f', -1, 64)
+	} else {
+		m = util.ObjToString(i_money)
+	}
+	if m == "" {
+		return m
+	}
+	m_arr := strings.Split(m, ".")
+	m_1 := m_arr[0]
+	len_m1 := len([]rune(m_1))
+	if len_m1 >= 9 {
+		m = m_1[0:len_m1-8] + "." + m_1[len_m1-8:len_m1-6] + "亿元"
+	} else if len_m1 >= 5 {
+		m = m_1[0:len_m1-4] + "." + m_1[len_m1-4:len_m1-2] + "万元"
+	} else {
+		if len(m_arr) == 1 {
+			return m + ".00元"
+		}
+		m_2 := m_arr[1]
+		if len([]rune(m_2)) > 1 {
+			m_2 = m_2[0:2]
+		} else {
+			m_2 = m_2[0:1] + "0"
+		}
+		m = m_1 + "." + m_2 + "元"
+	}
+	return m
+}

Some files were not shown because too many files changed in this diff