Bladeren bron

wip:移动端seo提交

wangkaiyue 1 jaar geleden
bovenliggende
commit
88d7b1898b
40 gewijzigde bestanden met toevoegingen van 4477 en 55 verwijderingen
  1. 2 5
      go.mod
  2. 4 6
      go.sum
  3. 9 2
      internal/cmd/cmd.go
  4. 11 10
      internal/controller/area.go
  5. 15 0
      internal/controller/index.go
  6. 48 0
      internal/controller/industry.go
  7. 3 2
      internal/controller/stype.go
  8. 120 0
      internal/service/industryStruct.go
  9. 23 15
      internal/service/paging.go
  10. 31 13
      internal/service/queryStruct.go
  11. 7 0
      internal/tags/init.go
  12. 1 0
      main.go
  13. 3 0
      manifest/config/config.yaml
  14. 841 0
      resource/staticres/mobile/css/tags-module-common.css
  15. 104 0
      resource/staticres/mobile/css/tags-strategy.css
  16. 2217 0
      resource/staticres/mobile/js/common.js
  17. 57 0
      resource/staticres/mobile/js/index.js
  18. 203 0
      resource/staticres/mobile/js/tag-common.js
  19. 95 0
      resource/template/mobile/area_index.html
  20. 65 0
      resource/template/mobile/area_list.html
  21. 109 0
      resource/template/mobile/components/baiducc.html
  22. 40 0
      resource/template/mobile/components/tag-area-nav.html
  23. 24 0
      resource/template/mobile/components/tag-card-bidding-info-list.html
  24. 20 0
      resource/template/mobile/components/tag-card-bidding-title.html
  25. 25 0
      resource/template/mobile/components/tag-card-text-list.html
  26. 15 0
      resource/template/mobile/components/tag-footer-common-assets.html
  27. 30 0
      resource/template/mobile/components/tag-footer.html
  28. 10 0
      resource/template/mobile/components/tag-header-common-assets.html
  29. 6 0
      resource/template/mobile/components/tag-header.html
  30. 7 0
      resource/template/mobile/components/tag-info-type-nav.html
  31. 17 0
      resource/template/mobile/components/tag-meta.html
  32. 29 0
      resource/template/mobile/components/tag-pagination.html
  33. 9 0
      resource/template/mobile/components/tag-register-login-group.html
  34. 16 0
      resource/template/mobile/components/tag-swiper-list.html
  35. 86 0
      resource/template/mobile/index.html
  36. 44 0
      resource/template/mobile/industry_index.html
  37. 58 0
      resource/template/mobile/industry_list.html
  38. 59 0
      resource/template/mobile/sType_list.html
  39. 2 2
      resource/template/pc/components/seo-pagination.html
  40. 12 0
      utility/util.go

+ 2 - 5
go.mod

@@ -5,12 +5,12 @@ go 1.19
 require (
 	app.yhyue.com/moapp/jybase v0.0.0-20230727083622-4dfc804ea6cf
 	github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.5.2
+	github.com/gogf/gf/contrib/drivers/mysql/v2 v2.5.2
 	github.com/gogf/gf/contrib/nosql/redis/v2 v2.5.2
 	github.com/gogf/gf/v2 v2.5.2
 )
 
 require (
-	app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d // indirect
 	github.com/BurntSushi/toml v1.2.0 // indirect
 	github.com/ClickHouse/clickhouse-go/v2 v2.2.0 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
@@ -20,21 +20,18 @@ require (
 	github.com/fsnotify/fsnotify v1.6.0 // indirect
 	github.com/go-logr/logr v1.2.4 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/go-sql-driver/mysql v1.7.1 // indirect
 	github.com/go-stack/stack v1.8.0 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
 	github.com/google/uuid v1.3.0 // indirect
 	github.com/gorilla/websocket v1.5.0 // indirect
 	github.com/grokify/html-strip-tags-go v0.0.1 // indirect
-	github.com/josharian/intern v1.0.0 // indirect
 	github.com/klauspost/compress v1.13.6 // indirect
 	github.com/magiconair/properties v1.8.6 // indirect
-	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.19 // indirect
 	github.com/mattn/go-runewidth v0.0.15 // indirect
 	github.com/olekukonko/tablewriter v0.0.5 // indirect
-	github.com/olivere/elastic v6.2.37+incompatible // indirect
-	github.com/olivere/elastic/v7 v7.0.22 // indirect
 	github.com/paulmach/orb v0.7.1 // indirect
 	github.com/pierrec/lz4/v4 v4.1.15 // indirect
 	github.com/pkg/errors v0.9.1 // indirect

+ 4 - 6
go.sum

@@ -1,4 +1,3 @@
-app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d h1:WPsYuuptAd3UEgN+jPzpnsDe/OvcshDUUtOTZPYGSJ8=
 app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d/go.mod h1:91/lSD/hS+ckMVP3WdidRzDhC60lLMdyce9QHy0cSMA=
 app.yhyue.com/moapp/jybase v0.0.0-20230727083622-4dfc804ea6cf h1:/Tk5haITmGc5c3/y6VxyycIy/LBWO7aYlxTiHKxmzv0=
 app.yhyue.com/moapp/jybase v0.0.0-20230727083622-4dfc804ea6cf/go.mod h1:D40Ae0rQilH8Hc5o2Vtt04Tjh/DNEFpcS3/WkJMPJb8=
@@ -124,7 +123,6 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
 github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
 github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
 github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
-github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -161,12 +159,16 @@ github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq
 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
+github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.5.2 h1:QwHoniewNRrQVcRE47yzpVG2l9kfqn+W9VSL91nkaxo=
 github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.5.2/go.mod h1:ihKUdWof54li5HwlW2H9qYqIxoJn0KAs1WvD8Ve9dHk=
+github.com/gogf/gf/contrib/drivers/mysql/v2 v2.5.2 h1:tFQP3/4Ivsx9ZkXXbHPIGn+TCiEW+0pQ2elwsafACNM=
+github.com/gogf/gf/contrib/drivers/mysql/v2 v2.5.2/go.mod h1:k9TrNZlYVBPNPYeqJ2uac0aqcJh75CHk7mWNYpRmrk4=
 github.com/gogf/gf/contrib/nosql/redis/v2 v2.5.2 h1:JzRIXB5J6vvnJGJmh7RfT8ntjXsn2jYXJf1+Q6oFe+A=
 github.com/gogf/gf/contrib/nosql/redis/v2 v2.5.2/go.mod h1:vLNtPgfInF5cXlcjLhVZxijIXD30+IiVjN6hP9sjjhY=
 github.com/gogf/gf/v2 v2.5.2 h1:fACJE7DJH6iTGHGhgiNY1uuZIZtr2IqQkJ52E+wBnt8=
@@ -279,7 +281,6 @@ github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
-github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -313,7 +314,6 @@ github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -349,9 +349,7 @@ github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
-github.com/olivere/elastic v6.2.37+incompatible h1:UfSGJem5czY+x/LqxgeCBgjDn6St+z8OnsCuxwD3L0U=
 github.com/olivere/elastic v6.2.37+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8=
-github.com/olivere/elastic/v7 v7.0.22 h1:esBA6JJwvYgfms0EVlH7Z+9J4oQ/WUADF2y/nCNDw7s=
 github.com/olivere/elastic/v7 v7.0.22/go.mod h1:VDexNy9NjmtAkrjNoI7tImv7FR4tf5zUA3ickqu5Pc8=
 github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=

+ 9 - 2
internal/cmd/cmd.go

@@ -19,11 +19,18 @@ var (
 		Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
 			s := g.Server()
 			s.Group("/", func(group *ghttp.RouterGroup) {
+				group.GET("/list/index.html", controller.IndexHandler) //首页
+
 				group.GET("/list/{type}/{areaCode}.html", controller.AreaIndexHandler)            //地区首页
 				group.GET("/list/{type}/{areaCode}_{sId}/", controller.AreaPageHandler)           //地区列表页面
 				group.GET("/list/{type}/{areaCode}_{sId}/p{pageNum}", controller.AreaPageHandler) //地区列表页面
-				group.GET("/list/stype/{sType}.html", controller.STypePageHandler)                //信息类型
-				group.GET("/list/stype/{sType}/p{pageNum}", controller.STypePageHandler)          //信息类型
+
+				group.GET("/list/stype/{sType}.html", controller.STypePageHandler)       //信息类型
+				group.GET("/list/stype/{sType}/p{pageNum}", controller.STypePageHandler) //信息类型
+
+				group.GET("/tags/industry/all.html", controller.IndustryIndexHandler)                                                         //行业首页
+				group.GET("/tags/industry/{industryClassId}_{areaCode}_{sTypeId}_{keyWordId}.html", controller.IndustryListHandler)           //行业列表
+				group.GET("/tags/industry/{industryClassId}_{areaCode}_{sTypeId}_{keyWordId}_{pageNum}.html", controller.IndustryListHandler) //行业列表
 			})
 			s.AddStaticPath("/jyseo", "/resource/staticres") //静态资源
 			s.Run()

+ 11 - 10
internal/controller/area.go

@@ -6,25 +6,26 @@ import (
 	"github.com/gogf/gf/v2/net/ghttp"
 	"github.com/gogf/gf/v2/util/gconv"
 	"jyseo/internal/service"
+	"jyseo/utility"
 )
 
-//var mobileReg = regexp.MustCompile("(?i)(Android|Mobile|Phone)")
-
 // AreaIndexHandler 地区站首页
 func AreaIndexHandler(r *ghttp.Request) {
 	areaCode := r.Get("areaCode").String()
 	areaType := r.Get("type").String()
+
 	node := service.JySeoAreaRoot.GetNodeByCode(areaCode)
+
 	if node == nil || !(areaType == "area" || areaType == "city") {
 		service.HtmlRender.RenderError(r, fmt.Errorf("页面不存在"))
 		return
 	}
-	service.HtmlRender.Render(r, "pc/area_index.html", g.Map{
-		"areaType": areaType,
-		"tdk":      service.JySeoTdk.GetAreaIndexTdk(r.Context(), node.Name),
-		"page":     "AreaIndexHandler",
-		"areaNode": node,
-	})
+	service.HtmlRender.Render(r, utility.GetCommonRenderPatch(r.Request.UserAgent(), "area_index.html"),
+		g.Map{
+			"areaType": areaType,
+			"areaNode": node,
+			"tdk":      service.JySeoTdk.GetAreaIndexTdk(r.Context(), node.Name),
+		})
 }
 
 // AreaPageHandler 地区列表页面
@@ -48,7 +49,7 @@ func AreaPageHandler(r *ghttp.Request) {
 		service.HtmlRender.RenderError(r, fmt.Errorf("获取列表数据异常"))
 		return
 	}
-	service.HtmlRender.Render(r, "pc/area_list.html",
+	service.HtmlRender.Render(r, utility.GetCommonRenderPatch(r.Request.UserAgent(), "area_list.html"),
 		g.Map{
 			"areaType":   areaType,
 			"areaNode":   areaNode,
@@ -57,7 +58,7 @@ func AreaPageHandler(r *ghttp.Request) {
 			"list":       rData.List,
 			"pageSize":   service.SettingPageSize,
 			"tdk":        service.JySeoTdk.GetAreaSTypeListTdk(r.Context(), sTypeNode.Code, areaNode.Name),
-			"pagination": service.PaggingHtml(pageNum, gconv.Int(rData.Total), fmt.Sprintf("/list/%s/%s_%s/p%s", areaType, areaCode, sId, "%d")),
+			"pagination": service.GetLetterPaging(pageNum, gconv.Int(rData.Total), fmt.Sprintf("/list/%s/%s_%s/p%s", areaType, areaCode, sId, "%d")),
 		},
 	)
 }

+ 15 - 0
internal/controller/index.go

@@ -0,0 +1,15 @@
+package controller
+
+import (
+	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/net/ghttp"
+	"jyseo/internal/service"
+	"jyseo/utility"
+)
+
+func IndexHandler(r *ghttp.Request) {
+	service.HtmlRender.Render(r, utility.GetCommonRenderPatch(r.Request.UserAgent(), "index.html"),
+		g.Map{
+			"tdk": service.JySeoTdk.GetAreaIndexTdk(r.Context(), ""),
+		})
+}

+ 48 - 0
internal/controller/industry.go

@@ -0,0 +1,48 @@
+package controller
+
+import (
+	"fmt"
+	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/net/ghttp"
+	"github.com/gogf/gf/v2/util/gconv"
+	"jyseo/internal/service"
+	"jyseo/utility"
+)
+
+func IndustryIndexHandler(r *ghttp.Request) {
+	service.HtmlRender.Render(r, utility.GetCommonRenderPatch(r.Request.UserAgent(), "industry_index.html"),
+		g.Map{
+			"industryList": service.JySeoIndustryRoot.GetIndustry(),
+			//"tdk":      service.JySeoTdk.GetSTypeTdk(r.Context(), sNode.Code),
+		},
+	)
+}
+
+func IndustryListHandler(r *ghttp.Request) {
+	keyWordId := r.Get("keyWordId").Int64()
+	industryClassId := r.Get("industryClassId").Int()
+	areaCode := r.Get("areaCode").String()
+	sTypeId := r.Get("sTypeId").String()
+	pageNum := r.Get("pageNum", 1).Int() //页码
+
+	keyWordStruct := service.JySeoIndustryRoot.GetKeyWordsById(keyWordId)
+	if keyWordStruct == nil {
+		service.HtmlRender.RenderError(r, fmt.Errorf("页面不存在"))
+		return
+	}
+	rData, err := service.NewBiddingQuery().EquipKeyWord(keyWordStruct.KeyWord).GetBidListList(r.Context(), pageNum)
+	if err != nil {
+		g.Log().Errorf(r.Context(), err.Error())
+		service.HtmlRender.RenderError(r, fmt.Errorf("获取列表数据异常"))
+		return
+	}
+	service.HtmlRender.Render(r, utility.GetCommonRenderPatch(r.Request.UserAgent(), "industry_list.html"),
+		g.Map{
+			//"tdk":      service.JySeoTdk.GetSTypeTdk(r.Context(), sNode.Code),
+			"keywordsNode": keyWordStruct,
+			"industryList": service.JySeoIndustryRoot.GetIndustry(),
+			"list":         rData.List,
+			"pagination":   service.GetLetterPaging(pageNum, gconv.Int(rData.Total), fmt.Sprintf("/tags/industry/%d_%s_%s_%d_%s.html", industryClassId, areaCode, sTypeId, keyWordId, "%d")),
+		},
+	)
+}

+ 3 - 2
internal/controller/stype.go

@@ -6,6 +6,7 @@ import (
 	"github.com/gogf/gf/v2/net/ghttp"
 	"github.com/gogf/gf/v2/util/gconv"
 	"jyseo/internal/service"
+	"jyseo/utility"
 )
 
 func STypePageHandler(r *ghttp.Request) {
@@ -28,7 +29,7 @@ func STypePageHandler(r *ghttp.Request) {
 		rNode = sNode.PNode
 		nodeList = sNode.PNode.Child
 	}
-	service.HtmlRender.Render(r, "pc/sType_list.html",
+	service.HtmlRender.Render(r, utility.GetCommonRenderPatch(r.Request.UserAgent(), "sType_list.html"),
 		g.Map{
 			"sTypeNode":  sNode,
 			"list":       rData.List,
@@ -37,7 +38,7 @@ func STypePageHandler(r *ghttp.Request) {
 			"pageNum":    pageNum,
 			"pageSize":   service.SettingPageSize,
 			"tdk":        service.JySeoTdk.GetSTypeTdk(r.Context(), sNode.Code),
-			"pagination": service.PaggingHtml(pageNum, gconv.Int(rData.Total), fmt.Sprintf("/list/stype/%s/p%s", sType, "%d")),
+			"pagination": service.GetLetterPaging(pageNum, gconv.Int(rData.Total), fmt.Sprintf("/list/stype/%s/p%s", sType, "%d")),
 		},
 	)
 }

+ 120 - 0
internal/service/industryStruct.go

@@ -0,0 +1,120 @@
+package service
+
+import (
+	"context"
+	"fmt"
+	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/os/gctx"
+	"github.com/gogf/gf/v2/util/gconv"
+	"github.com/gogf/gf/v2/util/grand"
+)
+
+var (
+	JySeoIndustryRoot *industryRoot = &industryRoot{}
+)
+
+type (
+	industryRoot struct {
+		allKeywords      []*industryKeywords
+		allIndustry      []*industryStruct
+		treeIndustry     map[string]*industryStruct
+		keyWordIdMapping map[int64]*industryKeywords
+	}
+
+	industryStruct struct {
+		Class   string //一级分类
+		ClassId int64  //一级分类id
+		//Url     string
+		List []*industryKeywords
+	}
+
+	industryKeywords struct {
+		Class     string //一级分类
+		ClassId   int64  //一级分类id
+		KeyWordId int64  //关键词id
+		KeyWord   string //关键词
+		Url       string //地址
+	}
+)
+
+func init() {
+	JySeoIndustryRoot.initIndustry(gctx.New())
+}
+
+// GetIndustry 获取行业和行业下标的物
+func (iR *industryRoot) initIndustry(ctx context.Context) {
+	data, err := g.DB().Query(ctx, `select a.id,a.name,b.id class_id,b.name class_1 from seo_words.seo_industry a inner join  seo_words.seo_industry_class b on a.class_1=b.name and  a.class_2 !='药品'  order by a.class_1`)
+	if err != nil {
+		g.Log().Errorf(ctx, "初始化异常行业 %v", err)
+		return
+	}
+
+	treeIndustry, keyWordIdMapping := map[string]*industryStruct{}, map[int64]*industryKeywords{}
+	var allIndustryKeywords []*industryKeywords
+	var allIndustry []*industryStruct
+	if data.Len() > 0 && data.List() != nil {
+		for _, v := range data.List() {
+			kw := &industryKeywords{
+				Class:     gconv.String(v["class_1"]),
+				ClassId:   gconv.Int64(v["class_id"]),
+				KeyWordId: gconv.Int64(v["id"]),
+				KeyWord:   gconv.String(v["name"]),
+			}
+			kw.Url = fmt.Sprintf("/tags/industry/%d_all_all_%d.html", kw.ClassId, kw.KeyWordId)
+
+			if _, ok := treeIndustry[kw.Class]; !ok {
+				newIndustry := &industryStruct{
+					Class:   kw.Class,
+					ClassId: kw.ClassId,
+				}
+				allIndustry = append(allIndustry, newIndustry)
+				treeIndustry[kw.Class] = newIndustry
+			}
+			keyWordIdMapping[kw.KeyWordId] = kw
+			treeIndustry[kw.Class].List = append(treeIndustry[kw.Class].List, kw)
+			allIndustryKeywords = append(allIndustryKeywords, kw)
+		}
+	}
+	iR.treeIndustry = treeIndustry
+	iR.allIndustry = allIndustry
+	iR.allKeywords = allIndustryKeywords
+	iR.keyWordIdMapping = keyWordIdMapping
+}
+
+// GetEachIndustryRandomKeyWords 每个行业取num个少于等于5个字的标的物
+func (iR *industryRoot) GetEachIndustryRandomKeyWords(num int) []*industryStruct {
+	var rData []*industryStruct
+	for _, obj := range iR.allIndustry {
+		var tmp []*industryKeywords
+		selectEd, arrLen := map[int]bool{}, len(obj.List)
+		if num >= arrLen {
+			tmp = obj.List
+		} else {
+			for len(tmp) < num {
+				val := grand.Intn(arrLen)
+				if selectEd[val] {
+					continue
+				}
+				if len([]rune(obj.List[val].KeyWord)) > 5 {
+					continue
+				}
+				selectEd[val] = true
+				tmp = append(tmp, obj.List[val])
+			}
+		}
+		rData = append(rData, &industryStruct{
+			Class:   obj.Class,
+			ClassId: obj.ClassId,
+			List:    tmp,
+		})
+	}
+	return rData
+}
+
+func (iR *industryRoot) GetIndustry() []*industryStruct {
+	return iR.allIndustry
+}
+
+func (iR *industryRoot) GetKeyWordsById(id int64) *industryKeywords {
+	return iR.keyWordIdMapping[id]
+}

+ 23 - 15
internal/service/paging.go

@@ -2,10 +2,7 @@ package service
 
 import (
 	"fmt"
-	"math"
 	"strconv"
-
-	qu "app.yhyue.com/moapp/jybase/common"
 )
 
 const (
@@ -27,21 +24,32 @@ const (
 	currPrevNextSize = 2 //当前页前后多少页开始显示点点点
 )
 
-func GetLetterPaging(pageNum, pageSize, count int, urlFormat string) (pagingMap map[string]interface{}) {
-	if pageNum == 0 {
-		pageNum = 1
+type Pagination struct {
+	PagingHtml         string
+	PageNum, PageCount int
+	UrlFormat          string
+	PrevHref, NextHref string
+}
+
+func GetLetterPaging(currentPage, totalPage int, href string) (pagingMap *Pagination) {
+	if currentPage == 0 {
+		currentPage = 1
+	}
+	pagination := &Pagination{
+		PagingHtml: PaggingHtml(currentPage, totalPage, href),
+		PageNum:    currentPage,
+		PageCount:  totalPage,
+		UrlFormat:  href,
 	}
-	pagecount := int(math.Ceil(qu.Float64All(count) / float64(pageSize)))
-	paging := PaggingHtml(pageNum, pagecount, urlFormat)
 
-	pagingMap = map[string]interface{}{
-		"paging":    paging,
-		"pageNum":   pageNum,
-		"pageCount": pagecount,
-		"pageSize":  pageSize,
-		"urlFormat": urlFormat,
+	if currentPage > 1 {
+		pagination.PrevHref = fmt.Sprintf(href, currentPage-1)
+	}
+	if currentPage < totalPage {
+		pagination.NextHref = fmt.Sprintf(href, currentPage+1)
 	}
-	return
+
+	return pagination
 }
 
 func PaggingHtml(currentPage, totalPage int, href string) string {

+ 31 - 13
internal/service/queryStruct.go

@@ -74,39 +74,57 @@ func (query *SeoBiddingQuery) EquipSType(sTypeNode *STypeNode) *SeoBiddingQuery
 	return query
 }
 
+func (query *SeoBiddingQuery) EquipKeyWord(keyword string) *SeoBiddingQuery {
+	query.keys = keyword
+	return query
+}
+
 func (query *SeoBiddingQuery) getResult(ctx context.Context, total int) (int, []map[string]interface{}) {
 	var sql string
 	var values []interface{}
-
 	if query.district != "" {
-		sql += " AND district=? "
+		sql += " AND b.district=? "
 		values = append(values, query.district)
 	} else if query.city != "" {
-		sql += " AND city=? "
+		sql += " AND b.city=? "
 		values = append(values, query.city)
 	} else if query.area != "" {
-		sql += " AND area=? "
+		sql += " AND b.area=? "
 		values = append(values, query.area)
 	}
 
 	if query.topType != "" {
 		if val, _ := topTypeMap[query.topType]; val != "" {
-			sql += " AND toptype=? "
+			sql += " AND b.toptype=? "
 			values = append(values, val)
 		} else {
-			sql += " AND toptype=? "
+			sql += " AND b.toptype=? "
 			values = append(values, query.topType)
 		}
-	} else if query.subType != "" {
-		sql += " AND subtype=? "
+	} else if query.subType != "" && query.keys == "" {
+		sql += " AND b.subtype=? "
 		values = append(values, query.subType)
 	}
-	values = append(values, total)
-	res, err := g.DB("clickHouse").Query(ctx, "SELECT * FROM bidMsg WHERE 1=1 "+sql+" ORDER BY publish_time DESC limit 0,?", values...)
-	if err != nil {
-		return -1, nil
+
+	if query.keys == "" {
+		values = append(values, total)
+		res, err := g.DB("clickHouse").Query(ctx, "SELECT * FROM bidMsg b WHERE 1=1 "+sql+" ORDER BY b.publish_time DESC limit 0,?", values...)
+		if err != nil {
+			return -1, nil
+		}
+		return res.Len(), res.List()
+	} else {
+		if query.keys != "" {
+			sql += " AND b.keyword=? "
+			values = append(values, query.keys)
+		}
+		values = append(values, total, total)
+		res, err := g.DB("clickHouse").Query(ctx, "SELECT * FROM jyseo.bidMsg WHERE bid_id IN ( SELECT bid_id  FROM  jyseo.keywordsCore b WHERE 1=1 "+sql+" order by bid_id desc limit 0,? ) ORDER BY publish_time desc LIMIT 0, ?", values...)
+		if err != nil {
+			return -1, nil
+		}
+		return res.Len(), res.List()
 	}
-	return res.Len(), res.List()
 }
 
 func (query *SeoBiddingQuery) dataFormat(data []map[string]interface{}) (bList []*InfoList) {

+ 7 - 0
internal/tags/init.go

@@ -9,12 +9,18 @@ func init() {
 	g.View().BindFunc("Ad", service.Ad)
 	g.View().BindFunc("JyTopMenu", service.TopMenu)       // 0:剑鱼标讯官网 1:品牌网站 2:资讯
 	g.View().BindFunc("JyBottomLink", service.BottomLink) // 0:剑鱼标讯官网 1:品牌网站 2:资讯
+
 	// 读取配置文件
 	g.View().BindFunc("GetConfigArr", GetConfigArr)
 	g.View().BindFunc("GetConfigMap", GetConfigMap)
 	g.View().BindFunc("GetConfigVal", GetConfigVal)
 	g.View().BindFunc("Msg", Msg) //配置文件字符串,用于版本号控制
 	g.View().BindFunc("Cdn", Cdn) //静态资源
+
+	g.View().BindFunc("Cdn2", func() string { //开发环境使用,上线续删除
+		return "/jyseo"
+	}) //静态资源
+
 	// 工具类
 	g.View().BindFunc("ParseHtml", ParseHtml)
 	g.View().BindFunc("ParseHtmlAttr", ParseHtmlAttr)
@@ -27,6 +33,7 @@ func init() {
 	g.View().BindFunc("GetMiniTab", GetMiniTab) //查询Tab数据
 	g.View().BindFunc("GetSTypeParentNodes", service.JySeoSTypeRoot.GetParentNodes)
 	g.View().BindFunc("GetAreaNodeByCode", GetAreaNodeByCode)
+	g.View().BindFunc("GetEachIndustryRandomKeyWords", service.JySeoIndustryRoot.GetEachIndustryRandomKeyWords)
 
 }
 

+ 1 - 0
main.go

@@ -2,6 +2,7 @@ package main
 
 import (
 	_ "github.com/gogf/gf/contrib/drivers/clickhouse/v2"
+	_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
 	_ "github.com/gogf/gf/contrib/nosql/redis/v2"
 	"github.com/gogf/gf/v2/os/gctx"
 	"jyseo/internal/cmd"

+ 3 - 0
manifest/config/config.yaml

@@ -15,6 +15,9 @@ viewer:
   autoencode: true
 
 database:
+  default:
+    link: "mysql:root:=PDT49#80Z!RVv52_z@tcp(192.168.3.14:4000)/seo_words"
+    debug: true
   clickHouse:
     link: "clickhouse:jianyu_appl:Cli3#fkh4ouSe@tcp(cc-2zelp3xmkmsrtjhgp.public.clickhouse.ads.aliyuncs.com:9000)/jyseo?dial_timeout=2000ms&max_execution_time=60"
     debug: true

+ 841 - 0
resource/staticres/mobile/css/tags-module-common.css

@@ -0,0 +1,841 @@
+.mt12 {
+  margin-top: .24rem;
+}
+.fl {
+  float: left!important;
+}
+.fr {
+  float: right!important;
+}
+
+
+.loading-icon {
+  position: relative;
+  width: 30px;
+  height: 30px;
+  border: 2px solid #000;
+  border-top-color: rgba(0, 0, 0, 0.2);
+  border-right-color: rgba(0, 0, 0, 0.2);
+  border-bottom-color: rgba(0, 0, 0, 0.2);
+  border-radius: 100%;
+  animation: circle infinite 0.75s linear;
+}
+@keyframes circle {
+  0% {
+    transform: rotate(0);
+  }
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+.loading-wrapper {
+  position: fixed;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 100;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: transparent;
+}
+body.loading {
+  overflow: hidden;
+}
+
+
+/* tag-header */
+.page-header {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  z-index: 9;
+}
+.j-header.tag-header-container {
+  width: 100%;
+  padding: 0.2rem .32rem;
+  height: 2rem;
+  padding-top: calc(0.2rem + 0.88rem);
+  background-color: #2ABED1;
+}
+.j-header.jy-app-header.wx-header,
+.j-header.jy-app-header.h5-header {
+  padding: .2rem .32rem;
+  height: 1.12rem;
+}
+.search-container {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 .24rem;
+  width: 100%;
+  height: 100%;
+  border-radius: 0.16rem;
+}
+.search-container .search-input {
+  flex: 1;
+  margin-left: .16rem;
+  font-size: 0.28rem;
+  line-height: 0.48rem;
+  color: #C0C4CC;
+}
+.page-main {
+  padding-top: 2rem;
+}
+.wx-body .page-main,
+.h5-body .page-main {
+  padding-top: 1.12rem;
+}
+
+/* tag-header */
+
+/* seo button */
+.seo-button {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: .08rem .24rem;
+  font-size: .3rem;
+  line-height: .44rem;
+  border-radius: 0.08rem; 
+}
+.seo-button.radius {
+  border-radius: 0.36rem;
+}
+.seo-button.theme-main {
+  color: #fff;
+  background-color: #2ABED1;
+}
+/* seo button */
+/* nav button */
+.nav-button {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+  padding: 0.1rem 0.08rem;
+  height: 0.64rem;
+  color: #5F5E64;
+  font-size: 0.24rem;
+  line-height: 0.36rem;
+  border-radius: 0.08rem;
+  background-color: #F5F6F7;
+}
+.text-button {
+  color: #5F5E64;
+  font-size: 0.28rem;
+  line-height: 0.4rem;
+}
+/* nav button */
+
+/* tag-group */
+.tag-group .tag-item {
+  margin: 0.06rem 0;
+  margin-right: .16rem;
+}
+.tag-item {
+  display: inline-block;
+  box-sizing: border-box;
+  border-radius: .08rem;
+  padding: .02rem .16rem;
+  white-space: nowrap;
+  border: 1px solid transparent;
+  font-size: 0.24rem;
+  line-height: 0.36rem;
+  white-space: nowrap;
+}
+.tag-item.grey {
+  color: #5F5E64;
+  background: #F7F9FA;
+  border-color: rgba(0, 0, 0, 0.05);
+}
+.tag-item.grey.plain {
+  background: transparent;
+  border-color: #5F5E64;
+}
+.tag-item.main {
+  color: #2ABED1;
+  background: rgb(42,190,209,.1);
+  border-color: rgb(42,190,209,.1);
+}
+.tag-item.main.plain {
+  background: transparent;
+  border-color: #2ABED1;
+}
+.tag-item.orange.plain {
+  color: #FF9F40;
+  background: transparent;
+  border-color: #FF9F40;
+}
+.tag-item.red {
+  color: #fb483d;
+  background: rgba(251,72,61,.1);
+}
+.tag-item.red.plain {
+  background: transparent;
+  border-color: #fb483d;
+}
+/* tag-group */
+
+
+/* tag card common */
+.tag-card a {
+  color: inherit;
+  white-space: inherit;
+}
+.tag-card-hd {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: .32rem .32rem .12rem;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
+}
+.tag-card-title {
+  position: relative;
+  padding-left: 0.22rem;
+  font-size: 0.36rem;
+  line-height: 0.52rem;
+  color: #2ABED1;
+}
+.tag-card-title::before {
+  content: '';
+  position: absolute;
+  left: 0;
+  top: 50%;
+  width: 0.06rem;
+  height: 0.32rem;
+  border-radius: .22rem;
+  background-color: #2ABED1;
+  transform: translate(0,-50%);
+}
+.tag-card-actions {
+  color: #9B9CA3;
+  font-size: 0.28rem;
+  line-height: 0.4rem;
+}
+.tag-card-actions .icon-arrow-up {
+  width: .32rem;
+  height: .32rem;
+  transform: rotate(90deg);
+}
+.tag-card-actions a {
+  display: flex;
+  align-items: center;
+}
+.tag-card-i-content-list {
+  position: relative;
+  display: flex;
+  flex-wrap: wrap;
+  padding: .24rem .32rem;
+  padding-right: .16rem;
+}
+.tag-card .nav-button {
+  margin-right: 0.14rem;
+  margin-bottom: 0.16rem;
+}
+.tag-card .text-button {
+  margin-right: 0.24rem;
+  margin-bottom: 0.16rem;
+}
+/* tag card common */
+
+
+.tag-city-item {
+  width: 1.62rem;
+}
+.tag-city-item:nth-of-type(4n) {
+  margin-right: 0;
+}
+
+/* tag bidding card */
+.bidding-list:not(:first-of-type) {
+  margin-top: .24rem;
+}
+.bidding-list .tag-card-list {
+  padding: .24rem .32rem;
+}
+.bidding-list .tag-card-item {
+  white-space: nowrap;
+  color: #171826;
+  font-size: 0.28rem;
+  line-height: 0.4rem;
+}
+.bidding-list .tag-card-item:not(:last-of-type) {
+  margin-bottom: 0.16rem;
+}
+/* tag bidding card */
+
+
+/* bidding-info-list */
+.bidding-info-bd {
+  margin-top: .16rem;
+  /* margin-bottom: .12rem; */
+}
+.bidding-info-ft {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.bidding-info-list {
+  padding-left: .32rem;
+}
+.bidding-info-item {
+  padding: .32rem;
+  padding-left: 0;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
+}
+.bidding-info-title {
+  color: #171826;
+  font-size: 0.28rem;
+  line-height: 0.4rem;
+}
+.tag-item--time {
+  font-size: .24rem;
+  line-height: .36rem;
+  color: #9B9CA3;
+  white-space: nowrap;
+}
+.tag-group .tag-item--time {
+  margin-right: 0;
+  padding-left: 0;
+  padding-right: 0;
+}
+/* bidding-info-list */
+
+/* buyer-info-list */
+.buyer-info-list {
+  padding-left: .32rem;
+}
+.buyer-info-hd {
+  margin-right: .24rem; 
+}
+.buyer-info-bd {
+  max-width: 77%;
+  flex: 1;
+}
+.buyer-info-item {
+  padding: .32rem;
+  padding-left: 0;
+  display: flex;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
+}
+.ent-info-hd-icon,
+.buyer-info-hd-icon {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 1.28rem;
+  height: 1.28rem;
+  border-radius: 0.08rem;
+  flex-shrink: 0;
+  font-size: 0.32rem;
+  color: #fff;
+  padding: .24rem .12rem;
+  letter-spacing: .533vw;
+  text-align: center;
+  line-height: .4rem;
+  background-color: #2abed1;
+  opacity: .7;
+}
+.ent-info-hd-icon.bgc-default,
+.buyer-info-hd-icon.bgc-default {
+  background-color: #2cb7ca;
+}
+.ent-info-hd-icon.bgc-blue,
+.buyer-info-hd-icon.bgc-blue {
+  background-color: #58a1e7;
+}
+.ent-info-hd-icon.bgc-orange,
+.buyer-info-hd-icon.bgc-orange {
+  background-color: #f5af5c;
+}
+.ent-info-hd-icon.bgc-green,
+.buyer-info-hd-icon.bgc-green {
+  background-color: #51cea2;
+}
+.ent-info-title,
+.buyer-info-title {
+  color: #171826;
+  font-size: 0.32rem;
+  line-height: 0.48rem;
+}
+.ent-info-sub-title,
+.buyer-info-sub-title {
+  margin-top: .08rem;
+  color: #9B9CA3;
+  font-size: 0.24rem;
+  line-height: 0.36rem;
+}
+/* buyer-info-list */
+
+/* ent-info-list */
+.ent-info-list .tag-item {
+  padding: 0 0.08rem;
+}
+.ent-info-item {
+  margin-bottom: .16rem;
+  padding: .32rem;
+}
+.ent-info-hd {
+  display: flex;
+  padding-bottom: .24rem;
+}
+.ent-info-hd-r {
+  margin-left: .24rem;
+  max-width: 77%;
+  flex: 1;
+}
+.ent-info-bd,
+.ent-info-bd-r {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.ent-info-bd-l {
+  width: calc(1.28rem + 0.24rem);
+  flex-shrink: 0;
+}
+.ent-info-bd-r {
+  flex: 1;
+}
+.ent-info-bd-l,
+.ent-info-bd-r .ent-u-location,
+.ent-info-bd-r .j-icon {
+  padding-top: .24rem;
+}
+.ent-info-bd-r .ent-u-location {
+  margin-right: .32rem;
+  flex: 1;
+  color: #5F5E64;
+  font-size: 0.22rem;
+  line-height: 0.32rem;
+  border-top: 1px solid rgba(0, 0, 0, 0.08);
+}
+/* ent-info-list */
+
+
+/* tag-register-login */
+.register-login-container {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: .24rem .32rem;
+}
+.logo-img-wrapper {
+  display: inline-block;
+  width: 2.2rem;
+  height: 0.6rem;
+}
+.logo-img-wrapper img {
+  display: block;
+  width: 100%;
+}
+.header-title {
+  flex: 1;
+  margin: 0 .16rem;
+  color: #171826;
+  font-size: 0.28rem;
+  line-height: 0.36rem;
+}
+/* tag-register-login */
+
+/* tag-info-type-nav-list */
+.tag-info-type-nav-list {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 .32rem;
+  font-size: 0.3rem;
+  line-height: 0.44rem;
+  background-color: #2ABED1;
+}
+.tag-info-type-nav-list.dark-mode {
+  background-color: #015173;
+}
+.tag-info-type-nav-item {
+  padding: .24rem 0;
+}
+.tag-info-type-nav-item a {
+  color: #fff;
+}
+/* tag-info-type-nav-list */
+
+/* tag-area-nav-container */
+.tag-area-nav-container {
+  background-color: #EDFDFF;
+  white-space: nowrap;
+}
+.tag-area-nav-container.dark-mode .tag-area-nav-list-container.simple-area,
+.tag-area-nav-container.dark-mode .tag-area-nav-list-group {
+  border-bottom-color: #171826;
+}
+.tag-area-nav-list-container,
+.tag-area-nav-list {
+  display: flex;
+  align-items: center;
+}
+.tag-area-nav-list-container.simple-area {
+  padding: .22rem .32rem;
+  border-bottom: 1px solid #2ABED1;
+}
+.tag-area-nav-list-container.more-area {
+  align-items: flex-start;
+}
+.tag-area-nav-list-container.more-area:not(:last-of-type) {
+  margin-bottom: .16rem;
+}
+.tag-area-nav-list-group {
+  padding: .26rem .32rem;
+  border-bottom: 1px solid #2ABED1;
+}
+.more-area .tag-area-nav-list {
+  flex: 1;
+  flex-wrap: wrap;
+}
+.tag-area-nav-list a {
+  color: inherit;
+  line-height: inherit;
+}
+.tag-area-nav-list-title {
+  margin-right: .46rem;
+  color: #5F5E64;
+  font-size: 0.24rem;
+  line-height: 0.48rem;
+}
+.tag-area-nav-item {
+  color: #171826;
+  font-size: 0.28rem;
+  line-height: 0.48rem;
+}
+.tag-area-nav-item:not(:last-of-type) {
+  margin-right: .48rem;
+}
+/* tag-area-nav-container */
+
+/* tag-industry-nav */
+.tag-industry-hd-container {
+  overflow-x: scroll;
+}
+.tag-industry-item:first-of-type {
+  margin-left: .32rem;
+}
+.tag-industry-item:last-of-type {
+  margin-right: .32rem;
+}
+.tag-industry-hd-container {
+  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
+}
+.tag-industry-list {
+  display: flex;
+  flex-wrap: nowrap;
+  width: max-content;
+  font-size: 0.28rem;
+  line-height: 0.4rem;
+}
+.tag-industry-item {
+  display: inline-flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0.2rem 0;
+  margin-right: .4rem;
+  flex-shrink: 0;
+  white-space: nowrap;
+  border-bottom: 1px solid transparent;
+}
+.tag-industry-content-item {
+  min-width: 1.6rem;
+  max-width: 1.8rem;
+}
+.tag-industry-item.active {
+  color: #2ABED1;
+  border-color: #2ABED1;
+}
+/* tag-industry-nav */
+
+/* tag-card-text-list */
+.text-list-container:first-of-type {
+  margin-top: 0;
+}
+.text-list-container .tag-card-bd-content {
+  padding: 0.24rem 0.32rem;
+}
+.text-list-container .tag-card-i-content-list {
+  display: block;
+  padding: 0;
+}
+.tag-card-i-content-list.max-height {
+  max-height: 2.76rem;
+  overflow: hidden;
+}
+.text-list-container .action-group {
+  margin: 0;
+  text-align: right;
+}
+/* tag-card-text-list */
+
+/* tag-pagination */
+.tag-pagination {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  height: .96rem;
+  font-size: .28rem;
+  line-height: .4rem;
+  color: #5F5E64;
+}
+.tag-pagination-button {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 100%;
+  flex: 2;
+}
+.tag-pagination-page-num {
+  flex: 1;
+  color: #171826;
+}
+.tag-pagination-button a {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+}
+.tag-pagination .j-icon {
+  width: .32rem;
+  height: .32rem;
+}
+.tag-pagination-prev .icon-arrow-up {
+  margin-right: .16rem;
+  transform: rotateZ(-90deg);
+}
+.tag-pagination-next .icon-arrow-up {
+  margin-left: .16rem;
+  transform: rotateZ(90deg);
+}
+/* tag-pagination */
+
+
+
+/* tag-swiper */
+.tag-swiper-list-container {
+  padding-top: 0.08rem;
+  width: 100%;
+}
+.tag-swiper-item {
+  padding: .16rem .32rem;
+  border-radius: .16rem;
+  overflow: hidden;
+}
+.tag-swiper-item a {
+  display: inline-block;
+  width: 100%;
+  height: 100%;
+  border-radius: 0.16rem;
+  overflow: hidden;
+}
+.tag-swiper-item img {
+  display: block;
+  width: 100%;
+}
+.swiper-container-horizontal .swiper-custom-dot {
+  bottom: .28rem;
+}
+.swiper-pagination .swiper-pagination-bullet {
+  width: 0.08rem;
+  height: 0.08rem;
+  
+}
+.swiper-pagination .swiper-pagination-bullet-active {
+  background-color: #fff;
+}
+/* tag-swiper */
+
+
+/* tag-breadcrumb-navigation */
+.tag-breadcrumb-navigation {
+  padding: 0.08rem .32rem;
+  color: #5F5E64;
+  font-size: 0.2rem;
+  line-height: 0.28rem;
+}
+.tag-breadcrumb-navigation a {
+  color: inherit;
+}
+/* tag-breadcrumb-navigation */
+
+/* tag-footer */
+.tag-footer-container {
+  color: #fff;
+}
+.tag-footer-container a {
+  color: inherit;
+}
+.footer-card {
+  padding: .32rem;
+  padding-bottom: calc(.32rem + 1.08rem);
+  background-color: #5F5E64;
+}
+.footer-divider {
+  height: 1px;
+  background-color: rgba(255, 255, 255, 0.24);
+}
+.footer-button-group {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0.2rem .32rem;
+  background: rgba(0, 0, 0, 0.70);
+}
+.footer-button-group .seo-button {
+  padding: 0.12rem 0.68rem;
+}
+.footer-button-group .seo-button .j-icon {
+  margin-right: 0.08rem;
+  width: 0.4rem;
+  height: 0.4rem;
+}
+.footer-card-line {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.tel-container {
+  font-size: 0.28rem;
+  line-height: 0.4rem;
+}
+.bottom-navs {
+  margin-top: .16rem;
+  margin-bottom: .32rem;
+  color: rgba(255, 255, 255, 0.90);
+  font-size: 0.26rem;
+  line-height: 0.4rem;
+}
+.bottom-nav-link:first-of-type {
+  margin-right: 1.6rem;
+}
+.copyright {
+  margin-top: .32rem;
+}
+.tel-link {
+  margin-left: 0.32rem;
+  font-size: 0.36rem;
+  line-height: 0.52rem;
+}
+.tag-footer-container.fixed {
+  position: fixed;
+  width: 100%;
+  left: 0;
+  bottom: 0;
+  z-index: 99;
+}
+.tag-footer-container.fixed .footer-button-group {
+  background: rgba(0, 0, 0, 0.70);
+}
+/* tag-footer */
+
+/* back-to-top */
+.back-to-top {
+  position: fixed;
+  right: .32rem;
+  bottom: calc(1.12rem + 0.8rem);
+  width: .96rem;
+  height: .96rem;
+  background-color: rgba(0, 0, 0, 0.4);
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.back-to-top .j-icon {
+  width: .64rem;
+  height: .64rem;
+}
+/* back-to-top */
+.tag-strategy-nav-container {
+  /* padding: .16rem .32rem;
+  background: #fff; */
+}
+.tag-strategy-nav-container .tag-strategy-nav-list{
+  display: flex;
+  align-items: center;
+  flex-wrap: nowrap;
+  overflow-x: auto;
+  padding: .16rem .32rem;
+  background: #fff;
+}
+.tag-strategy-nav-container .tag-strategy-nav-list .tag-strategy-nav-item{
+  padding: .08rem .2rem;
+  margin-right: .16rem;
+  background: #F5F6F7;
+  border-radius: 0.08rem;
+  font-size: .28rem;
+  line-height: .4rem;
+  white-space: nowrap;
+}
+.tag-strategy-nav-list .tag-strategy-nav-item > a{
+  color: #171826;
+}
+.tag-strategy-nav-container .tag-strategy-nav-list .tag-strategy-nav-item.active{
+  background: #2ABED1;
+  color: #fff;
+}
+.tag-strategy-nav-list .tag-strategy-nav-item.active > a{
+  color: #fff;
+}
+.strategy-list:not(:first-child){
+  margin-top: 0.24rem;
+}
+.tag-card-strategy-item,
+.tag-card-strategy-item > a{
+  display: flex;
+  background: #fff;
+}
+.tag-card-strategy-item > a{
+  width: 100%;
+  padding: .32rem;
+}
+.tag-card-strategy-item .card-item-left{
+  width: 2.2rem;
+  height: 1.44rem;
+  border-radius: 0.08rem;
+  overflow: hidden;
+  flex-shrink: 0;
+}
+.tag-card-strategy-item .card-item-left > img{
+  width: 100%;
+  height: 100%;
+  object-fit: fill;
+}
+.tag-card-strategy-item .card-item-right{
+  flex: 1;
+  margin-left: .32rem;
+  width: calc(100% - 2.52rem);
+}
+.tag-card-strategy-item .card-item-right .item-title{
+  font-size: .3rem;
+  line-height: .44rem;
+  color: #171826;
+}
+.tag-card-strategy-item .card-item-right .item-desc{
+  margin-top: .04rem;
+  font-size: .26rem;
+  line-height: .4rem;
+  color: #5F5E64;
+}
+.tag-card-strategy-item .card-item-right .item-time{
+  margin-top: .16rem;
+  font-size: .24rem;
+  line-height: .36rem;
+  color: #9B9CA3;
+}
+
+.strategy-list-container .tag-card-bd{
+  border-top: 1px solid rgba(0, 0, 0, 0.08);
+  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
+}

+ 104 - 0
resource/staticres/mobile/css/tags-strategy.css

@@ -0,0 +1,104 @@
+.page-container-strategy{}
+.page-container-strategy .strategy-ad{
+  width: 100%;
+  height: 1.76rem;
+  padding: .32rem;
+  background: url(/jyapp/tags/img/strategy-ad-bg.png) no-repeat center;
+  background-size: 100% 100%;
+}
+.page-container-strategy .strategy-ad > h1{
+  font-size: .44rem;
+  line-height: .64rem;
+  color: #171826;
+}
+.page-container-strategy .strategy-ad > p{
+  margin-top: .08rem;
+  font-size: .28rem;
+  line-height: .4rem;
+  color: #5F5E64;
+}
+
+.page-container-strategy-details .strategy-list{
+  margin-top: .24rem;
+  margin-bottom: 0;
+}
+.strategy-details{
+  padding: .32rem;
+  background: #fff;
+}
+.strategy-details h1{
+  font-size: .4rem;
+  line-height: .6rem;
+  color: #171826;
+}
+.strategy-details .details-sub-title{
+  margin-top: .08rem;
+  font-size: .24rem;
+  line-height: .36rem;
+  color: #5F5E64;
+}
+.strategy-details .details-sub-title span:nth-child(1){
+  margin-right: .32rem;
+}
+.strategy-details .details-main{
+  margin-top: .32rem;
+  text-align: justify;
+  font-size: .24rem;
+  line-height: .4rem;
+  color: #171826;
+}
+.strategy-details .details-main img{
+  width: 100%;
+  height: auto;
+}
+.turn-page-container{
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: .96rem 0 .64rem;
+}
+.page-button{
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 1.92rem;
+  height: .64rem;
+  text-align: center;
+  color: #5F5E64;
+  font-size: .28rem;
+  line-height: .4rem;
+  border-radius: 0.08rem;
+  border: 1px solid rgba(0, 0, 0, 0.1);
+}
+.page-button.last-page{
+  margin-right: .64rem;
+}
+.page-button.next-page {
+  margin-right: .64rem;
+}
+
+.page-button.last-page .icon-arrow-right-gray{
+  transform: rotate(180deg);
+  width: .32rem;
+  height: .32rem;
+  margin-right: 0.08rem;
+}
+.page-button.next-page .icon-arrow-right-gray{
+  width: .32rem;
+  height: .32rem;
+  margin-left: 0.08rem;
+}
+
+.page-button.active{
+  background: #2ABED1;
+  color: #fff;
+  border: 0;
+}
+.page-button.last-page.active .icon-arrow-right-gray {
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAABeSURBVHgB7ZaxDYAwDARfTMAIbMRIjMJojGLcIKVIQ/NOojvJ9Z3k5iWAn0TEripSfuQ9eZfcNPKPUy468lsukCNHvrx80yiUvoAIIoiYNcI3yToR/lHaRNTNcliSFxcyeu3W54LGAAAAAElFTkSuQmCC);
+  transform: rotate(0deg);
+}
+.page-button.next-page.active .icon-arrow-right-gray {
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAABeSURBVHgB7ZaxDYAwDARfTMAIbMRIjMJojGLcIKVIQ/NOojvJ9Z3k5iWAn0TEripSfuQ9eZfcNPKPUy468lsukCNHvrx80yiUvoAIIoiYNcI3yToR/lHaRNTNcliSFxcyeu3W54LGAAAAAElFTkSuQmCC);
+  transform: rotate(180deg);
+}

+ 2217 - 0
resource/staticres/mobile/js/common.js

@@ -0,0 +1,2217 @@
+/*
+ * Date Format 1.2.3
+ * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
+ * MIT license
+ *
+ * Includes enhancements by Scott Trenda <scott.trenda.net>
+ * and Kris Kowal <cixar.com/~kris.kowal/>
+ *
+ * Accepts a date, a mask, or a date and a mask.
+ * Returns a formatted version of the given date.
+ * The date defaults to the current date/time.
+ * The mask defaults to dateFormat.masks.default.
+ */
+var dateFormat = function () {
+  var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
+    timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
+    timezoneClip = /[^-+\dA-Z]/g,
+    pad = function (val, len) {
+      val = String(val);
+      len = len || 2;
+      while (val.length < len) val = "0" + val;
+      return val;
+    };
+
+  // Regexes and supporting functions are cached through closure
+  return function (date, mask, utc) {
+    var dF = dateFormat;
+
+    // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
+    if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
+      mask = date;
+      date = undefined;
+    }
+
+    // Passing date through Date applies Date.parse, if necessary
+    date = date ? new Date(date) : new Date;
+    if (isNaN(date)) throw SyntaxError("invalid date");
+
+    mask = String(dF.masks[mask] || mask || dF.masks["default"]);
+
+    // Allow setting the utc argument via the mask
+    if (mask.slice(0, 4) == "UTC:") {
+      mask = mask.slice(4);
+      utc = true;
+    }
+
+    var _ = utc ? "getUTC" : "get",
+      d = date[_ + "Date"](),
+      D = date[_ + "Day"](),
+      m = date[_ + "Month"](),
+      y = date[_ + "FullYear"](),
+      H = date[_ + "Hours"](),
+      M = date[_ + "Minutes"](),
+      s = date[_ + "Seconds"](),
+      L = date[_ + "Milliseconds"](),
+      o = utc ? 0 : date.getTimezoneOffset(),
+      flags = {
+        d: d,
+        dd: pad(d),
+        ddd: dF.i18n.dayNames[D],
+        dddd: dF.i18n.dayNames[D + 7],
+        m: m + 1,
+        mm: pad(m + 1),
+        mmm: dF.i18n.monthNames[m],
+        mmmm: dF.i18n.monthNames[m + 12],
+        yy: String(y).slice(2),
+        yyyy: y,
+        h: H % 12 || 12,
+        hh: pad(H % 12 || 12),
+        H: H,
+        HH: pad(H),
+        M: M,
+        MM: pad(M),
+        s: s,
+        ss: pad(s),
+        l: pad(L, 3),
+        L: pad(L > 99 ? Math.round(L / 10) : L),
+        t: H < 12 ? "a" : "p",
+        tt: H < 12 ? "am" : "pm",
+        T: H < 12 ? "A" : "P",
+        TT: H < 12 ? "AM" : "PM",
+        Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
+        o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
+        S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
+      };
+
+    return mask.replace(token, function ($0) {
+      return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
+    });
+  };
+}();
+
+// Some common format strings
+dateFormat.masks = {
+  "default": "ddd mmm dd yyyy HH:MM:ss",
+  shortDate: "m/d/yy",
+  mediumDate: "mmm d, yyyy",
+  longDate: "mmmm d, yyyy",
+  fullDate: "dddd, mmmm d, yyyy",
+  shortTime: "h:MM TT",
+  mediumTime: "h:MM:ss TT",
+  longTime: "h:MM:ss TT Z",
+  isoDate: "yyyy-mm-dd",
+  isoTime: "HH:MM:ss",
+  isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
+  isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
+};
+
+// Internationalization strings
+dateFormat.i18n = {
+  dayNames: [
+    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+  ],
+  monthNames: [
+    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+    "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+  ]
+};
+
+// For convenience...
+Date.prototype.FormatEnhance = function (mask, utc) {
+  return dateFormat(this, mask, utc);
+};
+Date.prototype.Format = function (fmt) { //author: meizz
+  var o = {
+    "M+": this.getMonth() + 1, //月份
+    "d+": this.getDate(), //日
+    "h+": this.getHours(), //小时
+    "m+": this.getMinutes(), //分
+    "s+": this.getSeconds(), //秒
+    "q+": Math.floor((this.getMonth() + 3) / 3), //季度
+    "S": this.getMilliseconds() //毫秒
+  };
+  if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+  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;
+}
+
+//替换input中的非数字
+function rePlaceUnDigital (obj) {
+  if (/[^\d]/g.test(obj.value)) {
+    var pos = getCursorPos(obj);
+    var array = obj.value.split("");
+    for (var i in array) {
+      if (/[^\d]/g.test(array[i])) {
+        pos--;
+      }
+    }
+    obj.value = obj.value.replace(/[^\d]/g, '');
+    setCursorPos(obj, pos);
+  }
+}
+
+//替换input中的空格
+function rePlaceSpace (obj) {
+  if (obj.value.indexOf(' ') > -1) {
+    var pos = getCursorPos(obj);
+    var array = obj.value.split("");
+    for (var i in array) {
+      if (array[i] == " ") {
+        pos--;
+      }
+    }
+    obj.value = obj.value.replace(new RegExp(' ', 'gm'), '');
+    setCursorPos(obj, pos);
+  }
+}
+
+/**
+ * 设置光标在短连接输入框中的位置
+ * @param inpObj 输入框
+ * @param pos
+ */
+function setCursorPos (inpObj, pos) {
+  if (navigator.userAgent.indexOf("MSIE") > -1) {
+    var range = document.selection.createRange();
+    var textRange = inpObj.createTextRange();
+    textRange.moveStart('character', pos);
+    textRange.collapse();
+    textRange.select();
+  } else {
+    inpObj.setSelectionRange(pos, pos);
+  }
+}
+
+/**
+ * 获取光标在短连接输入框中的位置
+ * @param inpObj 输入框
+ */
+function getCursorPos (inpObj) {
+  if (navigator.userAgent.indexOf("MSIE") > -1) { // IE
+    var range = document.selection.createRange();
+    range.text = '';
+    range.setEndPoint('StartToStart', inpObj.createTextRange());
+    return range.text.length;
+  } else {
+    return inpObj.selectionStart;
+  }
+}
+
+//获取cookie
+function getCookie (name) {
+  var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
+  if (arr = document.cookie.match(reg))
+    return unescape(arr[2]);
+  else
+    return null;
+}
+
+/**
+ * 正则表达式实现endWith效果函数
+ * @param str 要判断的字符
+ **/
+String.prototype.endWith = function (str) {
+  var reg = new RegExp(str + "$");
+  return reg.test(this);
+}
+/**
+ * 正则表达式实现startWith效果函数
+ * @param str 要判断的字符
+ **/
+String.prototype.startWith = function (str) {
+  var reg = new RegExp("^" + str);
+  return reg.test(this);
+}
+
+/* ios input bugs*/
+function fixIOSInputBugs () {
+  var windowHeight = window.innerHeight
+
+  function checkHeightForIOS (e) {
+    var windowFocusHeight = window.innerHeight
+    if (windowHeight == windowFocusHeight) {
+      return
+    }
+    if (e.target.hasClass('searchinput') || e.currentTarget.hasClass('searchinput')) {
+      return
+    }
+    var currentPosition;
+    var speed = 1; //页面滚动距离
+    currentPosition = document.documentElement.scrollTop || document.body.scrollTop;
+    currentPosition -= speed;
+    window.scrollTo(0, currentPosition); //页面向上滚动
+    currentPosition += speed; //speed变量
+    window.scrollTo(0, currentPosition); //页面向下滚动
+  }
+
+  $("body").on('click', '#recList', function (e) {
+    checkHeightForIOS(e)
+  })
+  $("body").on('click', '.inputDiv', function (e) {
+    checkHeightForIOS(e)
+  })
+  $("body").on('blur', 'input', function (e) {
+    //		checkHeightForIOS(e)
+  })
+}
+
+//动态加载css
+function addCssByLink (url) {
+  var links = document.getElementsByTagName('link')
+  for (var i = 0; i < links.length; i++) {
+    if (links[i].href && links[i].href.indexOf(url) > -1) {
+      return;
+    }
+  }
+  var doc = document;
+  var link = doc.createElement("link");
+  link.setAttribute("rel", "stylesheet");
+  link.setAttribute("type", "text/css");
+  link.setAttribute("href", url);
+  var heads = doc.getElementsByTagName("head");
+  if (heads.length)
+    heads[0].appendChild(link);
+  else
+    doc.documentElement.appendChild(link);
+}
+
+//动态加载js
+function loadJS (url, success) {
+  var scripts = document.getElementsByTagName('script')
+  for (var i = 0; i < scripts.length; i++) {
+    if (scripts[i].src && scripts[i].src.indexOf(url) > -1) {
+      if (success) success();
+      return;
+    }
+  }
+  var domScript = document.createElement('script');
+  domScript.src = url;
+  success = success || function () {
+  };
+  domScript.onload = domScript.onreadystatechange = function () {
+    if (!this.readyState || 'loaded' === this.readyState || 'complete' === this.readyState) {
+      success();
+      this.onload = this.onreadystatechange = null;
+      //this.parentNode.removeChild(this);
+    }
+  }
+  document.getElementsByTagName('head')[0].appendChild(domScript);
+}
+
+//判断对象是否为空对象{}
+function isNullObj (obj) {
+  for (var i in obj) {
+    if (obj.hasOwnProperty(i)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+var JyObjMessage = new Object();
+
+// $env, $envs的辅助函数
+window.utilsEnv = {
+  // 获取当前是android或者ios
+  androidOrIOS: function () {
+    var u = navigator.userAgent.toLowerCase()
+    var agent = null
+    if (/iphone|ipod|ipad|ios/.test(u)) {
+      agent = 'ios'
+    } else if (/(Android)/i.test(u)) {
+      agent = 'android'
+    }
+    return agent
+  },
+  getIsH5HostName: function () {
+    var hostname = location.hostname.toLowerCase()
+    return hostname.indexOf('h5') !== -1
+  },
+  // 是否是在app里面运行
+  getIsInTheAppContainer: function () {
+    // 判断是否在app环境下
+    var inApp = false
+    var u = navigator.userAgent.toLowerCase()
+    if (u.indexOf('jianyuapp') !== -1) {
+      inApp = true
+      return inApp
+    }
+    try {
+      if (this.androidOrIOS() === 'ios') {
+        var iniOSApp = typeof window.webkit.messageHandlers.skipAppointTab.postMessage === 'function'
+        inApp = iniOSApp
+      } else {
+        var inAndroidApp = typeof window.JyObj !== 'undefined'
+        inApp = inAndroidApp
+      }
+    } catch (e) {
+      console.warn(e)
+      inApp = false
+    }
+    return inApp
+  },
+  getPlatformEnvs: function () {
+    var inWX = navigator.userAgent.toLowerCase().indexOf('micromessenger') !== -1
+    var inApp = this.getIsInTheAppContainer()
+    var platformOS = this.androidOrIOS()
+    var getPlatform = function () {
+      var h5host = window.utilsEnv.getIsH5HostName()
+      if (inApp) {
+        return 'app'
+      } else if (h5host) {
+        return 'h5'
+      } else if (inWX) {
+        return 'wx'
+      } else {
+        return 'h5'
+      }
+    }
+    var platform = getPlatform()
+    return {
+      platformOS: platformOS,
+      platform: platform,
+      inApp: inApp,
+      inWX: inWX
+    }
+  }
+}
+utilsEnv.platformEnvs = utilsEnv.getPlatformEnvs()
+
+/**
+ * 提供模拟默认客户端函数,避免报错
+ */
+function mockAppFn () {
+  if (utilsEnv.platformEnvs.inApp) return
+  // 非APP环境下,提供默认函数
+  window.JyObj = {
+    mock: true,
+    //获取经纬度
+    getLLitude: function () {
+      return ''
+    },
+    /*跳转到指定的webview
+     * name 对应的值:
+     *   search:搜索 subscribe:订阅 box:百宝箱 me:我的 message:消息
+     */
+    skipAppointTab: function (name) {},
+    /*刷新指定的webview
+     * name 对应的值:
+     *   search:搜索 subscribe:订阅 box:百宝箱 me:我的 message:消息
+     * type 对应的值:
+     *   0:当前页 1:一级页面
+     */
+    refreshAppointTab: function (name, type) {},
+    skipCameraWithParam: function (type) {},
+    // 底部导航消息总数方法
+    sendMsgCount: function (num) {},
+    // 新打开相册客户端方法
+    skipAlbumWithParam: function (type) {},
+    savePic: function (imgbase64) {},
+    //读取复制内容
+    readRight: function () {},
+    //写入复制内容
+    wirteRight: function (txt) {},
+    //清除复制内容
+    clearRight: function () {},
+    //拨打电话
+    callPhone: function (phone) {},
+    //抖音or快手其他应用appName:应用名称;appLink:应用链接
+    openOtherAppLinks: function (appName, appLink) {},
+    //调用接口修改消息通知的打开数
+    openActivityPage: function (url, rectype, openid) {},
+    //清除 JyObjMessage
+    clearMessage: function () {},
+    //隐藏显示底部菜单栏 0:隐藏;1:显示
+    hiddenBottom: function (val) {},
+    //微信登录
+    loginByWeixin: function () {},
+    //分享功能
+    share: function (type, title, content, link) {},
+    //保存用户token
+    saveUserToken: function (val) {},
+    //获取用户token
+    getUserToken: function () {},
+    //移除用户token
+    removeUserToken: function () {},
+    //查看开关状态 是否接受消息
+    checkNoticePermission: function () {},
+    //打开接受消息开关
+    openSystemNotification: function () {},
+    //获取极光推送id
+    getPushRid: function () {},
+    //跳转外部链接
+    openExternalLink: function (url, title) {},
+    //获取当前版本号
+    getVersion: function () {},
+    alert: function (content) {},
+    //是否安装了微信
+    isInstallWeixin: function () {},
+    //登录加密
+    getCipherText: function (val) {},
+    //刷新首页和订阅页面
+    checkLab: function () {},
+    //登录成功后向客户端传参
+    loginSuccess: function (status) {},
+    //客户端登录页面点击返回 跳转到搜索首页
+    backUrl: function (val) {},
+    //清空通知栏消息
+    clearPushMessage: function () {},
+    //隐藏小红点
+    hideRedSpotOnMenu: function (menu) {},
+    //显示小红点
+    showRedSpotOnMenu: function (menu) {},
+    //微信支付
+    wxPay: function (order) {},
+    //支付宝支付
+    aliPay: function (order) {},
+    //获取原生的推送id
+    getOtherPushRid: function () {},
+    //获取手机型号
+    getPhoneBrand: function () {},
+    //获取定位
+    getLocation: function () {},
+    //切换菜单
+    chooseTab: function (indexTab) {},
+    //打开照相机
+    skipCamera: function () {},
+    //打开相册
+    skipAlbum: function () {},
+    //点击返回调用
+    judgeIsHidden: function (referer) {},
+    //返回值 处理
+    IosCall: function (functionName, args) {},
+    //查看定位开关状态 是否开启
+    checkLocationPermission: function () {},
+    //ios附件下载
+    //filename 文件名称不带后缀 【文件名称中不能带“/”否则会解析为多个目录】
+    //filetype 文件类型:doc word excel 等等
+    //fileurl 文件链接
+    //filesize 文件大小 字符串
+    //doc 、docx、excel 、xls 、 xlsxppt 、 pptx、 pdf、 txt、png 、PNG、jpg 、JPG 暂定这些为常见类型~支持在线预览+下载+转存
+    //其他类型仅支持下载+转存
+    downLoadFile: function (filename,filetype,fileurl,filesize) {},
+  }
+}
+
+// 部分h5浏览器(华为、荣耀)页面返回不刷新兼容
+function fixSomeH5BackRefresh () {
+  if (utilsEnv.platformEnvs.platform !== 'h5') return
+  const ua = navigator.userAgent.toLowerCase()
+  // 判断是不是华为/荣耀浏览器
+  const huawei = ua.includes('huawei') || ua.includes('honor')
+  if (huawei) {
+    window.addEventListener('visibilitychange', function () {
+      const v = document.visibilityState
+      if (v === 'hidden') {
+        // do something
+      } else if (v === 'visible') {
+        location.reload()
+      }
+    })
+  }
+}
+
+/**
+ * @date 2023-1-29
+ * 用于快速实现移动端引流相关调整,在App代码基础移植适配H5
+ */
+mockAppFn()
+fixSomeH5BackRefresh() // 华为、荣耀h5浏览器在页面返回不刷新兼容
+
+$(function () {
+  if (mySysIsIos() && utilsEnv.platformEnvs.inApp) {
+    window.JyObj = {
+      //获取经纬度
+      getLLitude: function () {
+        return JyObj.IosCall("getLLitude")
+      },
+      /*跳转到指定的webview
+       * name 对应的值:
+       *   search:搜索 subscribe:订阅 box:百宝箱 me:我的 message:消息
+       */
+      skipAppointTab: function (name) {
+        JyObjMessage.name = name
+        window.webkit.messageHandlers.skipAppointTab.postMessage(JyObjMessage)
+        JyObj.clearMessage()
+      },
+      /*刷新指定的webview
+       * name 对应的值:
+       *   search:搜索 subscribe:订阅 box:百宝箱 me:我的 message:消息
+       * type 对应的值:
+       *   0:当前页 1:一级页面
+       */
+      refreshAppointTab: function (name, type) {
+        JyObjMessage.name = name
+        JyObjMessage.type = type
+        window.webkit.messageHandlers.refreshAppointTab.postMessage(JyObjMessage)
+        JyObj.clearMessage()
+      },
+      skipCameraWithParam: function (type) {
+        JyObjMessage.type = type
+        window.webkit.messageHandlers.skipCameraWithParam.postMessage(JyObjMessage)
+        JyObj.clearMessage()
+      },
+      // 底部导航消息总数方法
+      sendMsgCount: function (num) {
+        JyObjMessage.num = num
+        window.webkit.messageHandlers.sendMsgCount.postMessage(JyObjMessage)
+        JyObj.clearMessage()
+      },
+      // 新打开相册客户端方法
+      skipAlbumWithParam: function (type) {
+        JyObjMessage.type = type
+        window.webkit.messageHandlers.skipAlbumWithParam.postMessage(JyObjMessage)
+        JyObj.clearMessage()
+      },
+      savePic: function (imgbase64) {
+        JyObjMessage.imgbase64 = imgbase64
+        window.webkit.messageHandlers.savePic.postMessage(JyObjMessage)
+        JyObj.clearMessage()
+      },
+      //读取复制内容
+      readRight: function () {
+        return window.webkit.messageHandlers.readRight.postMessage(JyObjMessage);
+      },
+      //写入复制内容
+      wirteRight: function (txt) {
+        JyObjMessage["txt"] = txt;
+        window.webkit.messageHandlers.wirteRight.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //清除复制内容
+      clearRight: function () {
+        window.webkit.messageHandlers.clearRight.postMessage(JyObjMessage);
+      },
+      //拨打电话
+      callPhone: function (phone) {
+        JyObjMessage["phone"] = phone;
+        window.webkit.messageHandlers.callPhone.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //抖音or快手其他应用appName:应用名称;appLink:应用链接
+      openOtherAppLinks: function (appName, appLink) {
+        JyObjMessage["appName"] = appName;
+        JyObjMessage["appLink"] = appLink;
+        window.webkit.messageHandlers.openOtherAppLinks.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //调用接口修改消息通知的打开数
+      openActivityPage: function (url, rectype, openid) {
+        JyObjMessage["url"] = url;
+        JyObjMessage["rectype"] = rectype;
+        JyObjMessage["openid"] = openid;
+        window.webkit.messageHandlers.openActivityPage.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //清除 JyObjMessage
+      clearMessage: function () {
+        JyObjMessage = new Object();
+      },
+      //隐藏显示底部菜单栏 0:隐藏;1:显示
+      hiddenBottom: function (val) {
+        JyObjMessage["hidden"] = val;
+        window.webkit.messageHandlers.hiddenBottom.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //微信登录
+      loginByWeixin: function () {
+        window.webkit.messageHandlers.loginByWeixin.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //分享功能
+      share: function (type, title, content, link) {
+        JyObjMessage["type"] = type
+        JyObjMessage["title"] = title
+        JyObjMessage["content"] = content
+        JyObjMessage["link"] = link
+        window.webkit.messageHandlers.share.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //保存用户token
+      saveUserToken: function (val) {
+        JyObjMessage["token"] = val;
+        window.webkit.messageHandlers.saveUserToken.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //获取用户token
+      getUserToken: function () {
+        return JyObj.IosCall("getUserToken")
+      },
+      //移除用户token
+      removeUserToken: function () {
+        window.webkit.messageHandlers.removeUserToken.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //查看开关状态 是否接受消息
+      checkNoticePermission: function () {
+        return JyObj.IosCall("checkNoticePermission")
+      },
+      //打开接受消息开关
+      openSystemNotification: function () {
+        window.webkit.messageHandlers.openSystemNotification.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //获取极光推送id
+      getPushRid: function () {
+        return JyObj.IosCall("getPushRid")
+      },
+      //跳转外部链接
+      openExternalLink: function (url, title) {
+        JyObjMessage["url"] = url
+        JyObjMessage["title"] = title
+        window.webkit.messageHandlers.openExternalLink.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //获取当前版本号
+      getVersion: function () {
+        return JyObj.IosCall("getVersion")
+      },
+      alert: function (content) {
+        JyObjMessage["content"] = content
+        window.webkit.messageHandlers.alert.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //是否安装了微信
+      isInstallWeixin: function () {
+        return JyObj.IosCall("isInstallWeixin")
+      },
+      //登录加密
+      getCipherText: function (val) {
+        JyObjMessage["phone"] = val
+        return JyObj.IosCall("getCipherText", JyObjMessage)
+      },
+      //刷新首页和订阅页面
+      checkLab: function () {
+        window.webkit.messageHandlers.checkLab.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //登录成功后向客户端传参
+      loginSuccess: function (status) {
+        JyObjMessage["status"] = status
+        window.webkit.messageHandlers.loginSuccess.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //客户端登录页面点击返回 跳转到搜索首页
+      backUrl: function (val) {
+        JyObjMessage["status"] = val;
+        window.webkit.messageHandlers.backUrl.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //清空通知栏消息
+      clearPushMessage: function () {
+        window.webkit.messageHandlers.clearPushMessage.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //隐藏小红点
+      hideRedSpotOnMenu: function (menu) {
+        JyObjMessage["menu"] = menu;
+        window.webkit.messageHandlers.hideRedSpotOnMenu.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //显示小红点
+      showRedSpotOnMenu: function (menu) {
+        JyObjMessage["menu"] = menu;
+        window.webkit.messageHandlers.showRedSpotOnMenu.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //微信支付
+      wxPay: function (order) {
+        JyObjMessage["order"] = order;
+        window.webkit.messageHandlers.wxPay.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //支付宝支付
+      aliPay: function (order) {
+        JyObjMessage["order"] = order;
+        window.webkit.messageHandlers.aliPay.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //获取原生的推送id
+      getOtherPushRid: function () {
+        return JyObj.IosCall("getOtherPushRid")
+      },
+      //获取手机型号
+      getPhoneBrand: function () {
+        return JyObj.IosCall("getPhoneBrand")
+      },
+      //获取定位
+      getLocation: function () {
+        return JyObj.IosCall("getLocation")
+      },
+      //切换菜单
+      chooseTab: function (indexTab) {
+        JyObjMessage["indexTab"] = indexTab;
+        window.webkit.messageHandlers.chooseTab.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //打开照相机
+      skipCamera: function () {
+        window.webkit.messageHandlers.skipCamera.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //打开相册
+      skipAlbum: function () {
+        window.webkit.messageHandlers.skipAlbum.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //点击返回调用
+      judgeIsHidden: function (referer) {
+        JyObjMessage["referer"] = referer;
+        window.webkit.messageHandlers.judgeIsHidden.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+      //返回值 处理
+      IosCall: function (functionName, args) {
+        if (args != "" && args != undefined) {
+          JyObj.clearMessage();
+        }
+        var payload = { "jsName": functionName, "arguments": args };
+        var res = prompt(JSON.stringify(payload));
+        if (res != "") {
+          var resObj = JSON.parse(res)
+          var type = resObj.type
+          switch (type) {
+            case "int":
+              return parseInt(resObj.value)
+            case "string":
+              return resObj.value
+            case "bool":
+              if (resObj.value == "true") {
+                return true
+              }
+              return false
+            default:
+              return ""
+          }
+        }
+        return ""
+      },
+      //查看定位开关状态 是否开启
+      checkLocationPermission: function () {
+        return JyObj.IosCall("checkLocationPermission")
+      },
+      //ios附件下载
+      //filename 文件名称不带后缀 【文件名称中不能带“/”否则会解析为多个目录】
+      //filetype 文件类型:doc word excel 等等
+      //fileurl 文件链接
+      //filesize 文件大小 字符串
+      //doc 、docx、excel 、xls 、 xlsxppt 、 pptx、 pdf、 txt、png 、PNG、jpg 、JPG 暂定这些为常见类型~支持在线预览+下载+转存
+      //其他类型仅支持下载+转存
+      downLoadFile: function (filename,filetype,fileurl,filesize) {
+        if ( filename != "" ) {
+          filename = filename.replace(/\//g,"")
+        }
+        JyObjMessage["filename"] = filename;
+        JyObjMessage["filetype"] = filetype;
+        JyObjMessage["fileurl"] = fileurl;
+        JyObjMessage["filesize"] = filesize;
+        window.webkit.messageHandlers.downLoadFile.postMessage(JyObjMessage);
+        JyObj.clearMessage();
+      },
+    }
+    fixIOSInputBugs()
+  }
+  if (isIphoneX()) {
+    // $(".app-layout-header").css("padding-top"," 40px");//标题
+    $(".app-back.jyapp-icon.jyapp-icon-zuojiantou").css("padding-top", " 40px");//返回
+    $(".header-share").css("padding-top", " 40px");//分享
+    // $(".app-layout-content-a, .app-layout-content-b").css("top","64px");//正文
+    $(".feedback-nav").css("top", "85px");//意见反馈
+    $(".setpage .noticehead").css("top", "85px");//关注项目
+    $(".app-back.jyapp-icon.jyapp-icon-zuojiantou").addClass("jyapp-icon-zuojiantou-x");//登录
+    $("#header.reg").css("padding-top", "50px");//注册
+    $("#header.reg").css("height", "4.92rem");//注册
+    // $("#header.header-login").css("height", "4.92rem");//注册
+    try {
+      iphoneXInit();
+    } catch (e) {
+    }
+  }
+  //自定义tap
+  $(document).on("touchstart", function (e) {
+    var $target = $(e.target);
+    $target.data("isMoved", 0);
+    $target.data("startTime", Date.now());
+  });
+  $(document).on("touchmove", function (e) {
+    var $target = $(e.target);
+    $target.data("isMoved", 1);
+  });
+  $(document).on("touchend", function (e) {
+    var $target = $(e.target);
+    var startTime = $target.data("startTime");
+    if (Date.now() - startTime > 200) {
+      return;
+    }
+    if ($target.data("isMoved") == 1) {
+      return;
+    }
+    $target.trigger("tap", e);
+  });
+  $(".app-layout-header .app-back").unbind("click").on("click", function () {
+    if (typeof (clickBack) == "function") {
+      clickBack();
+    } else {
+      try {
+        afterClickBack();
+      } catch (e) { }
+      //可以自定义返回url,不过是跳转的方式
+      if (typeof (backUrl) != "undefined" && backUrl != null) {
+        if (typeof (backUrl) == "string") {
+          window.location.href = backUrl;
+        } else if (typeof (backUrl) == "number") {
+          try {
+            if (!mySysIsIos() && JyObj.getVersion() >= "2.9.9") {
+              JyObj.backUrl("")
+            }
+          } catch (error) {}
+          window.history.go(backUrl);
+        }
+      } else {
+        try {
+          if (!mySysIsIos() && JyObj.getVersion() >= "2.9.9") {
+            JyObj.backUrl("")
+          }
+        } catch (error) {}
+        window.history.back();
+      }
+    }
+  });
+  //	$(".app-layout-footer li").on("tap",function(){
+  //		if($(this).hasClass("active")){
+  //			return;
+  //		}
+  //		switch(this.id){
+  //			case "navbar-search":
+  //				if(sessionStorage){
+  //					sessionStorage.mainSearchReload = "1";
+  //				}
+  //				autoLogin("/jyapp/jylab/mainSearch");
+  //				break;
+  //			case "navbar-subscribe":
+  //				autoLogin("/jyapp/wxkeyset/keyset/index");
+  //				break;
+  //			case "navbar-laboratory":
+  //				autoLogin("/jyapp/jylab/index");
+  //				break;
+  //			case "navbar-me":
+  //				autoLogin("/jyapp/free/me");
+  //				break;
+  //		}
+  //	});
+  //	if(!mySysIsIos()){
+  try {
+    if (location.href.indexOf('/follow/set/list') == -1) {
+      afterPageInit();
+    }
+    //发送渠道统计
+    sendChannelSign();
+  } catch (e) {
+  }
+  //	}
+  window.checkTabTimerId = setInterval(function () {
+    if (localStorage.chooseTab != undefined) {
+      try {
+        JyObj.hiddenBottom("1");
+        JyObj.chooseTab(parseInt(localStorage.chooseTab));
+        localStorage.removeItem("chooseTab");
+      } catch (e) {
+      }
+    }
+    if (localStorage.reloadTab == "1" && window.location.pathname == "/jyapp/swordfish/historypush") {
+      localStorage.removeItem("reloadTab");
+      window.location.reload();
+    }
+  }, 1000);
+  //
+  externalLinks();
+});
+
+
+function externalLinks() {
+  //是否有外部链接需要访问(一般是广告位登录后跳转外部链接)
+  var externalLinks = localStorage.getItem("noLoginExternalLinks");
+  if(externalLinks!=""&&externalLinks!=undefined&&externalLinks!="null"){
+    if (window.location.pathname.indexOf("jylab/mainSearch")>0){
+      setTimeout(function () {
+        localStorage.removeItem('noLoginExternalLinks');
+        window.location.href=externalLinks;
+        //JyObj.openExternalLink(externalLinks,"剑鱼");
+      }, 1000);
+    }
+  }
+}
+var EasyAlert = {
+  timeout: null,
+  waitTime: 1000,
+  show: function (text, css, waitTime) {
+    if (this.timeout != null) {
+      clearTimeout(this.timeout);
+      this.hide();
+      this.timeout = null;
+    }
+    var thisClass = this;
+    this.timeout = setTimeout(function () {
+      thisClass.hide();
+      thisClass.timeout = null;
+    }, waitTime ? waitTime : this.waitTime);
+    $("body").append('<div class="easyalert" id="easyAlert">' + text + '</div>');
+    if (typeof (css) != "undefined") {
+      $("#easyAlert").css(css);
+    }
+    $("#easyAlert").css({
+      "left": "50%",
+      "margin-top": -($("#easyAlert").outerHeight() / 2),
+      "margin-left": -($("#easyAlert").outerWidth() / 2)
+    }).show();
+  },
+  hide: function () {
+    $("#easyAlert").remove();
+  }
+}
+var EasyPopup = function (id) {
+  this.id = id;
+  var thisClass = this;
+  document.getElementById(id).onclick = function (e) {
+    if (e.target.id == id) {
+      thisClass.hide();
+    }
+  }
+  this.show = function () {
+    $("#" + this.id).fadeIn();
+    var mainObj = $("#" + id + ">div:first");
+    mainObj.css({ "margin-top": -(mainObj.outerHeight() / 2) });
+  },
+    this.hide = function () {
+      $("#" + this.id).fadeOut();
+    }
+}
+var Verification = {
+  //手机号验证
+  isPhone: function (value) {
+    return /^[1][3-9][0-9]{9}$/.test(value);
+  }
+}
+
+//深信服用户开了一批特殊规则的手机号
+var CreatePhone = {
+  //自己创建的手机号验证[格式为100xxxxxxxx]
+  isPhone: function (value) {
+    return /^[1][0][0][0-9]{8}$/.test(value);
+  }
+}
+// 部分页面没有全局工具函数
+if (typeof utils !== 'object') {
+  utils = {}
+}
+Date.prototype.pattern = function (fmt) {
+  if (!fmt) return ''
+  var o = {
+    'y+': this.getFullYear(),
+    'M+': this.getMonth() + 1, // 月份
+    'd+': this.getDate(), // 日
+    // 12小时制
+    'h+': this.getHours() % 12 == 0 ? 12 : this.getHours() % 12, // 小时
+    // 24小时制
+    'H+': this.getHours(), // 小时
+    'm+': this.getMinutes(), // 分
+    's+': this.getSeconds(), // 秒
+    'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
+    'S': this.getMilliseconds(), // 毫秒
+    'E+': this.getDay(), // 周
+  };
+  var week = {
+    '0': '日',
+    '1': '一',
+    '2': '二',
+    '3': '三',
+    '4': '四',
+    '5': '五',
+    '6': '六'
+  };
+  if (/(y+)/.test(fmt)) {
+    fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length));
+  }
+  if (/(E+)/.test(fmt)) {
+    fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? '星期' : '周') : '') + week[
+    this.getDay() + '']);
+  }
+  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;
+}
+utils.dateFromNow = function (originTime, useOld) {
+  if (!originTime) return
+  // 原始时间 - 传入的时间戳
+  var originTimeStamp = +new Date(originTime)
+  // 当前时间戳
+  var nowTimeStamp = +new Date()
+  // 时间戳相差多少
+  var diffTimeStamp = nowTimeStamp - originTimeStamp
+
+  var postfix = diffTimeStamp > 0 ? '前' : '后'
+  // 求绝对值 ms(毫秒)
+  var diffTimeStampAbsMs = Math.abs(diffTimeStamp)
+  var diffTimeStampAbsS = Math.round(diffTimeStampAbsMs / 1000)
+
+  // 10天的秒数
+  var days11 = 11 * 24 * 60 * 60
+  // var dataMap = {
+  //     zh: ['年', '个月', '星期', '天', '小时', '分钟', '秒'],
+  //     number: [365*24*60*60, 30*24*60*60, 7*24*60*60, 24*60*60, 60*60, 60, 1]
+  // }
+  var dataMap = {
+    zh: ['天', '小时', '分钟', '秒'],
+    number: [24 * 60 * 60, 60 * 60, 60, 1]
+  }
+
+  var timeString = ''
+  // 10天前
+  var tenDaysAgo = diffTimeStampAbsS > days11
+  // 是否是当天
+  var isCurrentDay = new Date(originTimeStamp).pattern('yyyy.MM.dd') === new Date().pattern('yyyy.MM.dd')
+
+  var condition = !isCurrentDay
+  if (useOld) {
+    condition = tenDaysAgo
+  }
+
+  if (condition) {
+    // 不是当天,则使用正常日期显示
+    var originDate = new Date(originTimeStamp)
+    var nowDate = new Date()
+    // 是否同年
+    var sameYear = originDate.getFullYear() === nowDate.getFullYear()
+    // 如果是当年,则不显示年
+    var patternString = sameYear ? 'MM-dd' : 'yyyy-MM-dd'
+    timeString = originDate.pattern(patternString)
+  } else {
+    for (var i = 0; i < dataMap.number.length; i++) {
+      var inm = Math.floor(diffTimeStampAbsS / dataMap.number[i])
+      if (inm != 0) {
+        timeString = inm + dataMap.zh[i] + postfix
+        break
+      }
+    }
+  }
+  return timeString
+}
+//计算时差
+function timeDiff (date) {
+  var date1 = date;//开始时间
+  var date2 = new Date();//结束时间
+  var date3 = date2.getTime() - date1.getTime();//时间差的毫秒数
+  //计算出相差天数
+  var days = Math.floor(date3 / (24 * 3600 * 1000));
+  //计算出小时数
+  var leave1 = date3 % (24 * 3600 * 1000);//计算天数后剩余的毫秒数
+  var hours = Math.floor(leave1 / (3600 * 1000));
+  //计算相差分钟数
+  var leave2 = leave1 % (3600 * 1000);//计算小时数后剩余的毫秒数
+  var minutes = Math.floor(leave2 / (60 * 1000));
+  //计算相差秒数
+  var td = "30秒前";
+  if (days > 0) {
+    if (days > 10) {
+      var date1year = date1.getFullYear();
+      var date2year = date2.getFullYear();
+      var date1month = date1.getMonth() + 1;
+      var date1day = date1.getDate();
+      if (date1month < 10) {
+        date1month = "0" + date1month;
+      }
+      if (date1day < 10) {
+        date1day = "0" + date1day;
+      }
+      if (date1year < date2year) {
+        td = date1.getFullYear() + "-" + date1month + "-" + date1day;
+      } else {
+        td = date1month + "-" + date1day;
+      }
+    } else {
+      td = days + "天前"
+    }
+  } else if (hours > 0) {
+    td = hours + "小时前";
+  } else if (minutes > 0) {
+    td = minutes + "分钟前";
+  }
+  return td;
+}
+
+function newredirect (zbadd, link, sid, sds, index) {
+  if (link != null && typeof (link) != "undefined") {
+    link = link.replace(/\n/g, "");
+    if (!/^http/.test(link)) {
+      link = "http://" + link
+    }
+  }
+  var pt = ""
+  if (index == 1) {
+    pt = "projectMatch=项目匹配"
+  }
+  if (sds) {
+    window.location.href = "/jyapp/article/content/" + sid + ".html?keywords=" + encodeURIComponent(sds) + pt;
+  } else {
+    window.location.href = "/jyapp/article/content/" + sid + ".html?" + pt;
+  }
+}
+
+function pcredirect (link, sid) {
+  window.open("/pcdetail/" + sid + ".html");
+}
+
+var isNumber = /^[0-9]+$/
+var isLetter = /^[a-zA-Z]+$/
+function isRegExp (value) {
+  return Object.prototype.toString.call(value) === '[object RegExp]'
+}
+function keyWordHighlight (value, oldChars, newChar) {
+  if(typeof(oldChars) == "undefined" || oldChars == null || typeof(newChar) == "undefined" || newChar == null || newChar == ""){
+    return value;
+  }
+  var array = [];
+  if(oldChars instanceof Array){
+    array = oldChars.concat();
+  }else{
+    array.push(oldChars);
+  }
+
+  // 非字符串替换集合
+  var notStrReplacer = []
+  for (var i = 0; i < array.length; i++) {
+    if (!array[i]) {
+      continue
+    } else {
+      if (isRegExp(array[i])) {
+        // 正则直接替换
+        // 注意:该正则中必须包含至少一个分组匹配,分组中的内容用来替换
+        notStrReplacer.push(array[i])
+        array[i] = ''
+      } else {
+        // 字符串替换
+        array[i] = array[i].replace(/([\$\(\)\*\+\.\[\]\?\/\\\^\{\}\|])/g, '\\$1').replace(/\s+/g, '')
+      }
+
+      // array[i] = array[i].replace(/\$/g,"\\$");
+      // array[i] = array[i].replace(/\(/g,"\\(");
+      // array[i] = array[i].replace(/\)/g,"\\)");
+      // array[i] = array[i].replace(/\*/g,"\\*");
+      // array[i] = array[i].replace(/\+/g,"\\+");
+      // array[i] = array[i].replace(/\./g,"\\.");
+      // array[i] = array[i].replace(/\[/g,"\\[");
+      // array[i] = array[i].replace(/\]/g,"\\]");
+      // array[i] = array[i].replace(/\?/g,"\\?");
+      // array[i] = array[i].replace(/\\/g,"\\");
+      // array[i] = array[i].replace(/\//g,"\\/");
+      // array[i] = array[i].replace(/\^/g,"\\^");
+      // array[i] = array[i].replace(/\{/g,"\\{");
+      // array[i] = array[i].replace(/\}/g,"\\}");
+      // array[i] = array[i].replace(/\|/g,"\\|");
+    }
+  }
+
+  // 数组去空
+  var lastArr = []
+  array.forEach(function (item) {
+    if (item) {
+      lastArr.push(item)
+    }
+  })
+  if (lastArr.length === 0 && notStrReplacer.length === 0) {
+    return value
+  }
+  lastArr = lastArr.sort(function (a, b) {
+    return b.length - a.length
+  })
+
+  if (notStrReplacer.length) {
+    for (var j = 0; j < notStrReplacer.length; j++) {
+      // 正则替换
+      value = value.replace(notStrReplacer[j], newChar)
+    }
+  }
+  if (lastArr.length) {
+    value = value.replace(new RegExp('(' + lastArr.join('|') + ')', 'gmi'), newChar)
+  }
+
+  return value
+}
+
+function getWxVersion () {
+  var wechatInfo = navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
+  if (!wechatInfo) {
+    return null;
+  }
+  return wechatInfo[1];
+}
+
+/**
+ * 设置光标在短连接输入框中的位置
+ * @param inpObj 输入框
+ * @param pos
+ */
+function setCursorPos (inpObj, pos) {
+  if (navigator.userAgent.indexOf("MSIE") > -1) {
+    var range = document.selection.createRange();
+    var textRange = inpObj.createTextRange();
+    textRange.moveStart('character', pos);
+    textRange.collapse();
+    textRange.select();
+  } else {
+    inpObj.setSelectionRange(pos, pos);
+  }
+}
+
+/**
+ * 获取光标在短连接输入框中的位置
+ * @param inpObj 输入框
+ */
+function getCursorPos (inpObj) {
+  if (navigator.userAgent.indexOf("MSIE") > -1) { // IE
+    var range = document.selection.createRange();
+    range.text = '';
+    range.setEndPoint('StartToStart', inpObj.createTextRange());
+    return range.text.length;
+  } else {
+    return inpObj.selectionStart;
+  }
+}
+
+//获取url中参数
+function getUrlParam (name, type) {
+  var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
+  var r = window.location.search.substr(1).match(reg);
+  if (r != null)
+    if (typeof (type) == "function") {
+      return type(r[2]);
+    } else {
+      return unescape(r[2]);
+    }
+  return null;
+}
+
+//自动登录
+function autoLogin (url, callBack) {
+  var sign = "";
+  try {
+    sign = JyObj.getUserToken();
+  } catch (e) {
+  }
+  if (sign == "" || sign == null || typeof (sign) == "undefined") {
+    if (callBack != null && typeof (callBack) != "undefined") {
+      callBack(null);
+    } else if (url != null && typeof (url) != "undefined") {
+      if (url === 'back') {
+        window.location.href = "/jyapp/free/login?to=back";
+      } else {
+        window.location.href = "/jyapp/free/login?url=" + encodeURIComponent(url);
+      }
+    }
+    return;
+  }
+  if (url != null && typeof (url) != "undefined") {
+    if (url === 'back') {
+      window.location.href = "/jyapp/free/login?sign=" + sign + "&to=back"
+    } else {
+      window.location.href = "/jyapp/free/login?sign=" + sign + "&url=" + encodeURIComponent(url);
+    }
+    return
+  }
+  $.ajax({
+    url: "/jyapp/free/login?t=" + new Date().getTime(),
+    type: "post",
+    data: { reqType: "signLogin", sign: sign },
+    dataType: "json",
+    success: function (r) {
+      //有回调函数不跳转
+      if (callBack != null && typeof (callBack) != "undefined") {
+        callBack(r.userInfo);
+        return;
+      }
+    },
+    error: function () {
+      //alert("服务器连接超时!");
+    }
+  });
+}
+
+// ios or android
+function msgAndroidOrIOS () {
+  var u = navigator.userAgent.toLowerCase()
+  var agent = null;
+  if (/iphone|ipod|ipad|ios/.test(u)) {
+    agent = 'ios'
+  } else if (/(Android)/i.test(u)) {
+    agent = 'android'
+  }
+  return agent
+}
+// 私信未读数量
+function kfData(acync, num) {
+  $.ajax({
+    type: 'POST',
+    url: '/jyapi/message/messageCount',
+    async: acync || false,
+    data: JSON.stringify({userType: 2}),
+    contentType: 'application/json',
+    success: function (res) {
+      localStorage.setItem('isMsgNum', num + res.count)
+    }
+  })
+}
+
+/**
+ * 检查当前是否是 tabbar 页面
+ * @returns {boolean}
+ */
+function checkNowInTabbarPage () {
+  var tabbarPages = [
+    '/jyapp/jylab/mainSearch',
+    '/jyapp/swordfish/historypush',
+    '/jyapp/frontPage/messageCenter/sess/index',
+    '/jyapp/jylab/index',
+    '/jyapp/free/me'
+  ]
+  return tabbarPages.some(function (v) {
+    return location.href.indexOf(v) > -1
+  })
+}
+
+// 底部导航消息总数
+function checkMsgCount(acync, str, callback) {
+  $.ajax({
+    type: 'GET',
+    url: '/jymessageCenter/getCount?t=' + Date.now(),
+    async: acync || false,
+    success: function (r) {
+      var num = 0
+      if (r.error_code === 0) {
+        num = r.data.count
+        try {
+          JyObj.sendMsgCount(num)
+        } catch (e) {
+          console.log(e)
+        }
+      }
+      if (str == 1) {
+        var isMsg = localStorage.getItem('isMsgNum')
+        if (num !== Number(isMsg)) {
+          kfData(acync, num)
+        }
+      } else {
+        kfData(acync, num)
+      }
+
+      callback && callback()
+    }
+  })
+}
+
+function keepQuest() {
+  var appType = msgAndroidOrIOS(), timer = null
+  if (appType == 'ios' || appType == 'android') {
+    clearInterval(timer)
+    timer = setInterval(() => {
+      checkMsgCount(true, 1)
+    }, 300000)
+  }
+}
+
+/**
+ * 检查是否需要前往新用户兴趣设置
+ * @returns {boolean}
+ */
+function checkNeedGoNewUserSettingPage () {
+  // 同步请求判断是否新用户,需要跳转兴趣设置页面
+  var goPage
+  $.ajax({
+    type: 'post',
+    async: false,
+    url: '/salesLeads/appIsNewUerSales',
+    success: function (res) {
+      if (res && res.data) {
+        goPage = '/jy_mobile/uersales/newuser'
+      }
+    }
+  })
+  if (goPage) {
+    locationReplace(goPage)
+    return true
+  }
+  return false
+}
+
+/**
+ * 检查是否需要绑定手机号
+ * @returns {*}
+ */
+function checkNeedGoBindPhonePage () {
+  var userPhone
+  $.ajax({
+    url: "/jypay/user/getAccountInfo?t=" + Date.now(),
+    type: "GET",
+    async: false,
+    success: function(res){
+      if(res.error_code == 0 && res.data){
+        userPhone = res.data.phone;
+      }
+    }
+  })
+  if (!userPhone) {
+    locationReplace('/jyapp/account/phone/bind?mode=mergeBind')
+    return true
+  }
+  return false
+}
+
+function loginSuccess (result, loginType) {
+  // 清除缓存
+  clearObjKeyForRegFn(sessionStorage, /-login-clear/)
+  clearObjKeyForRegFn(localStorage, /-login-clear/)
+
+  // 清除订阅页面缓存
+  sessionStorage.removeItem('$data-historypush')
+  JyObj.refreshAppointTab('subscribe', 1)
+
+  JyObj.saveUserToken(result.sign);
+  // 数据包默认选中企业需请求默认企业接口
+  try {
+    window.onlyUserID =JyObj.getUserToken()
+    if (window.onlyUserID) {
+      function getCookieValue(name) {
+        var result = document.cookie.match("(^|[^;]+)\\s*" + name + "\\s*=\\s*([^;]+)")
+        return result ? result.pop() : ""
+      }
+
+      window.onlyUserID = getCookieValue('SESSIONID')
+    }
+
+    // 消息总数方法
+    checkMsgCount(true, 0);
+  } catch (e) {
+    console.log('获取ID失败')
+  }
+  if (JSON.stringify(window.onlyUserID) != localStorage.getItem('MobileWebAppForOnlyID')) {
+    localStorage.setItem('MobileWebAppForOnlyID', JSON.stringify(window.onlyUserID))
+    $.ajax({
+      type: 'get',
+      url: '/entbase/ent/mySelectent?t=' + new Date().getTime()
+    })
+  }
+  // 当前为新用户(即注册)--跳转设置密码页
+   if(result.userInfo && result.userInfo.isNewUser) {
+     var href ="/jyapp/free/setPwd";
+     window.location.href = href;
+     return
+   }
+
+  if (loginType === 'is-wx') {
+    // 检查是否绑定手机号
+    var isGoBindPhone = checkNeedGoBindPhonePage()
+    if (isGoBindPhone) {
+      return
+    }
+  }
+
+  // 检查是否需要前往新用户兴趣设置
+  var isStopNext = checkNeedGoNewUserSettingPage()
+  if (isStopNext) {
+    return
+  }
+
+  //分销跳转
+  if (getUrlParam("DisUrl") != null) {
+    afterLoginSuccess("", true);
+    locationReplace(getUrlParam("DisUrl"));
+    return
+  }
+  //
+  if (getUrlParam("to") === "back") {
+    //		sessionStorage.reloadHomePage=true;
+    if (sessionStorage && getUrlParam("back") !== "index") {
+      afterLoginSuccess("", true);
+      window.history.back();
+    } else {
+      afterLoginSuccess("S", false);//提示app定位搜索菜单
+      //window.location.href = "/jyapp/jylab/mainSearch";
+      location.replace("/jyapp/jylab/mainSearch");
+    }
+    return
+  } else {
+    window.history.back()
+  }
+  //
+  var callBackUrl = getUrlParam("url", decodeURIComponent);
+  if (callBackUrl != null) {
+    afterLoginSuccess("", true);
+    //window.location.href = callBackUrl;
+    locationReplace(callBackUrl);
+    return
+  }
+  //
+  callBackUrl = getUrlParam("out", decodeURIComponent);
+  if (callBackUrl != null) {
+    afterLoginSuccess("", true);
+    localStorage.setItem("noLoginExternalLinks", callBackUrl);
+    window.history.back();
+    //访问外部链接
+    //JyObj.openExternalLink(callBackUrl);
+    return
+  }
+  //
+  if (sessionStorage) {
+    sessionStorage.mainSearchReload = "1";
+  }
+  afterLoginSuccess("S", false);
+  //window.location.href = "/jyapp/jylab/mainSearch";
+  //location.replace("/jyapp/jylab/mainSearch");
+
+}
+
+//2020-05-30 android replace失效
+function locationReplace (url) {
+  if (history.replaceState) {
+    history.replaceState(null, document.title, url);
+    history.go(0);
+  } else {
+    location.replace(url);
+  }
+}
+
+function afterLoginSuccess (type, canBack) {
+  if (!canBack) {
+    prohibitBack();
+    localStorage.reLogin = "1";
+  }
+  try {
+    JyObj.refreshAppointTab('me', 1)
+  } catch (e) {
+    console.log(e)
+  }
+  JyObj.loginSuccess(type);
+}
+
+//ios JyObj对象加载完成回调
+function afterPageInit () {
+  setInterval(function () {
+    redSpotOnMenu();
+  }, 600000);
+  try {
+    afterJyObjInit();
+    latlongitude();//记录用户经纬度
+  } catch (e) {}
+  $.post("/jyapp/free/afterPageLoadToCheck?t=" + new Date().getTime(), {
+    sign: JyObj.getUserToken(),
+    rid: JyObj.getPushRid(),
+    oid: getOtherPushId(),
+    phoneType: getPhoneType(),
+    version: JyObj.getVersion(),
+    isIos: mySysIsIos()
+  }, function (r) {
+    if (mySysIsIos() && r.isNeedUpdate > 0) {
+      //if(r.webdomain.indexOf("https")>-1){
+      //ios客户端 因为证书问题加载https域名 需要验证证书等一系列操作
+      //	r.webdomain = r.webdomain.replace("https","http")
+      //}
+      //以后版本
+      if (r.isNeedUpdate == 2) {
+        //JyObj.openExternalLink(r.webdomain + "/jyapp/free/staticPage/update.html", "-1");
+        JyObj.openExternalLink(window.location.protocol+"//"+window.location.host+"/jyapp/free/goToUpdate?mustupdate=1", "-1");
+      }else if(localStorage.onceTipUpdate != "1"){
+        sessionStorage.onceTipUpdate = "1";
+        localStorage.onceTipUpdate = "1";
+        //JyObj.openExternalLink(r.webdomain + "/jyapp/free/staticPage/update.html", "去更新");
+        JyObj.openExternalLink(window.location.protocol+"//"+window.location.host+"/jyapp/free/goToUpdate?mustupdate=1", "去更新");
+      }
+      return;
+    }
+    if (r.status == -3) {
+      if (mySysIsIos()) {
+        window.location.href = "/jyapp/free/login?flag=kicked&back=index";
+      } else {
+        localStorage.setItem("isKicked", "1");
+        JyObj.backUrl("H");
+      }
+    } else if (r.status == 1) {
+      if (r.sign != "") {
+        JyObj.saveUserToken(r.sign);
+      }
+    }
+  });
+  //记录推送id
+  savePushIdMsg();
+}
+
+function compareVersion (curVersion, upVersion) {
+  v1 = curVersion.split(".");
+  v2 = upVersion.split(".");
+  var maxlen = v1.length > v2.length ? v1.length : v2.length;
+  for (var i = 0; i < maxlen; i++) {
+    if (v1[i] == v2[i]) {
+      continue
+    }
+    if (v1[i] == undefined) {
+      v1[i] = -1;
+    }
+    if (v2[i] == undefined) {
+      v2[i] = -1;
+    }
+    if (parseInt(v1[i]) < parseInt(v2[i])) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+  return false;
+}
+
+function redSpotOnMenu () {
+  var doAjax = true;
+  if (localStorage.redSpotLastAjaxTime &&
+    new Date().getTime() - parseInt(localStorage.redSpotLastAjaxTime) < 1000 * 60) {
+    doAjax = false;
+  }
+  if (!doAjax && localStorage.redSpotRes) {
+    try {
+      var lastAjaxRes = JSON.parse(localStorage.redSpotRes)
+      redSpotBackFuc(lastAjaxRes, "false")
+      return
+    } catch (e) {
+      console.log("redSpotOnMenu", e)
+    }
+  }
+  $.post("/jyapp/free/showRedSpotOnMenu?t=" + new Date().getTime(), null, redSpotBackFuc);
+}
+
+function redSpotBackFuc (r, flag) {
+  var noticeCount = r.notice;
+  //JyObj.getUnReadMessageCount("");
+  // #fix 修复三级页同步请求导致页面白屏时间过长
+  checkMsgCount(true, 0)
+  // message红点
+  if (noticeCount > 0) {
+    $(".trigger-div-notice .dot-red").show()
+  } else {
+    $(".trigger-div-notice .dot-red").hide()
+  }
+  // 项目关注红点
+  if (r.follow_project > 0) {
+    $(".project-follow .dot-red").show()
+  } else {
+    $(".project-follow .dot-red").hide()
+  }
+  // 企业关注红点
+  if (r.follow_ent > 0) {
+    $(".ent-follow .dot-red").show();
+  } else {
+    $(".listTwo .redspot").hide();
+  }
+  try {
+    if (r.my == 0) {
+      JyObj.hideRedSpotOnMenu("my");
+    } else {
+      JyObj.showRedSpotOnMenu("my");
+    }
+    if (r.subscribe == 0) {
+      JyObj.hideRedSpotOnMenu("subscribe");
+    } else {
+      JyObj.showRedSpotOnMenu("subscribe");
+    }
+    if (r.my == 0 && r.subscribe == 0) {
+      //清空通知栏消息
+      JyObj.clearPushMessage("");
+    }
+  } catch (e) {
+  }
+
+  if (flag == "success") {
+    localStorage.redSpotLastAjaxTime = new Date().getTime();
+    localStorage.redSpotRes = JSON.stringify(r);
+  }
+}
+
+//
+function setLiActive (obj) {
+  $(obj).addClass("jyapp-li-active");
+  setTimeout(function () {
+    $(obj).removeClass("jyapp-li-active");
+  }, 500);
+}
+
+function mySysIsIos () {
+  //ios终端
+  var flag1 = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
+  var flag2 = !!navigator.userAgent.match(/\(M[^;]+; Intel Mac OS X/);
+  return flag1 || flag2
+}
+
+function clearObjKeyForRegFn (obj, reg) {
+  if (obj) {
+    for(var k in obj) {
+      if (reg.test(k)) {
+        obj.removeItem(k)
+      }
+    }
+  }
+}
+
+function clearRefreshStorage (isKicked) {
+  //清除小红点缓存
+  localStorage.removeItem("redSpotLastAjaxTime");
+  // 清除缓存
+  clearObjKeyForRegFn(sessionStorage, /-login-clear/)
+  clearObjKeyForRegFn(localStorage, /-login-clear/)
+  //清除token
+  try {
+    $.cookie('SESSIONID', '', { expires: -1, path: '/' })
+  } catch (e) {
+    console.warn(e)
+  }
+  //订阅设置页面缓存
+  sessionStorage.removeItem('$data-historypush')
+  // 退出登录清除首页商机管理权限缓存
+  sessionStorage.removeItem("setEntStatus")
+  sessionStorage.removeItem("userMergeFlag");
+  // 刷新首页
+  try {
+    JyObj.refreshAppointTab('search', 1)
+    JyObj.refreshAppointTab('subscribe', 1)
+    JyObj.hiddenBottom(0)
+  } catch (e) {
+    console.warn(e)
+  }
+  if (!isKicked) {
+    window.location.href = "/jyapp/free/login?back=index&flag=quit";
+  }
+}
+
+function appQuit (isKicked) {
+  var sign = JyObj.getUserToken();
+  //隐藏小红点
+  try {
+    JyObj.removeUserToken();
+    JyObj.hideRedSpotOnMenu("my");
+    JyObj.hideRedSpotOnMenu("subscribe");
+  } catch (e) {
+  }
+  $.ajax({
+    url: "/jyapp/free/signOut?t=" + new Date().getTime(),
+    type: "post",
+    data: { isKicked: isKicked, sign: sign },
+    dataType: "json",
+    success: function () {
+      clearRefreshStorage(isKicked)
+    },
+    error: function () {
+      clearRefreshStorage(isKicked)
+    }
+  });
+}
+
+//随机获取分享文案
+var ShareText = [
+  "我和投标伙伴都在用剑鱼标讯找项目,推荐你也试试",
+  "我用剑鱼标讯免费查到超多招标信息,推荐你也试试",
+  "我收到了剑鱼标讯免费推送的招标信息,推荐你也试试",
+  "发现了一个投标神器,推荐你也试试"
+]
+
+function getShareText () {
+  return ShareText[randomNum(0, ShareText.length - 1)];
+}
+
+function randomNum (Min, Max) {
+  var Range = Max - Min;
+  var Rand = Math.random();
+  var num = Min + Math.round(Rand * Range);
+  return num;
+}
+
+function getCipherText (phone) {
+  return encodeURIComponent(JyObj.getCipherText(phone));
+}
+
+function getChannel () {
+  var channel = ""
+  try {
+    channel = JyObj.getChannel();
+  } catch (e) {
+  }
+  return channel
+}
+
+function getDeviceId () {
+  var deviceId = ""
+  try {
+    deviceId = JyObj.getIdentity();
+  } catch (e) {
+  }
+  return deviceId
+}
+
+function getPhoneType () {
+  var phoneType = "";
+  try {
+    phoneType = JyObj.getPhoneBrand();
+  } catch (e) {
+  }
+  return phoneType;
+}
+
+function getOtherPushId () {
+  var otherPushId = "";
+  try {
+    otherPushId = JyObj.getOtherPushRid();
+  } catch (e) {
+  }
+  return otherPushId;
+}
+
+function prohibitBack () {
+  try {
+    //禁止后退
+    JyObj.prohibitBack();
+  } catch (e) {
+  }
+}
+
+function sendChannelSign () {
+  var first = localStorage.getItem("channelSigned")
+  if (first == "1") {
+    return
+  }
+  try {
+    var sign = getChannel();
+    var id = getDeviceId();
+    if (sign == "" || id == "") {
+      return
+    }
+    $.post("/jyapp/free/channelSign", { "sign": sign, "id": id }, function (data) {
+      if (data.success) {
+        localStorage.setItem("channelSigned", "1")
+      }
+    })
+  } catch (err) {
+    alert(err)
+  }
+}
+
+function savePushIdMsg () {
+  var sign = JyObj.getUserToken();
+  var save = sessionStorage.getItem("savePush")
+  if (!(sign == "" || sign == undefined) || save == "1") {
+    sessionStorage.setItem("savePush", "1")//每次打开只执行一次
+    return;
+  }
+  sessionStorage.setItem("savePush", "1")//每次打开只执行一次
+  try {
+    var interval = setInterval(function () {
+      var id = getDeviceId();
+      var phoneType = getPhoneType();
+      var rid = JyObj.getPushRid();
+      var oid = getOtherPushId();
+      var channel = getChannel();
+      if (mySysIsIos()) {
+        phoneType = "ios";
+        channel = "ios";
+      }
+      if (rid == "" || rid == undefined) {
+        return
+      }
+      $.post("/jyapp/free/savePushIdMsg", {
+        "id": id,
+        "phoneType": phoneType,
+        "rid": rid,
+        "oid": oid,
+        "channel": channel
+      }, function (data) {
+        if (data.success) {
+          clearInterval(interval);
+        }
+      })
+    }, 1000)
+  } catch (err) {
+    alert(err)
+  }
+}
+
+function isIphoneX () {
+  return /iphone/gi.test(navigator.userAgent) && (screen.height >= 812)
+}
+
+function myDomain () {
+  return window.location.protocol + "//" + window.location.host;
+}
+
+/******* 获取url参数(正则)********/
+function getParam (name) {
+  var search = document.location.search;
+  // alert(search);
+  var pattern = new RegExp("[?&]" + name + "\=([^&]+)", "g");
+  var matcher = pattern.exec(search);
+  var items = null;
+  if (null != matcher) {
+    try {
+      items = decodeURIComponent(decodeURIComponent(matcher[1]));
+    } catch (e) {
+      try {
+        items = decodeURIComponent(matcher[1]);
+      } catch (e) {
+        items = matcher[1];
+      }
+    }
+  }
+  return items;
+};
+
+//格式化时间
+function formatDate (date, hms) {
+  if (date === null || date === "" || date === 0) {
+    return "-"
+  }
+  var date = new Date(date);
+  var YY = date.getFullYear() + '-';
+  var MM = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
+  var DD = (date.getDate() < 10 ? '0' + (date.getDate()) : date.getDate());
+  var hh = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
+  var mm = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
+  var ss = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds());
+  if (!hms) {
+    return YY + MM + DD + " " + hh + mm + ss
+  } else {
+    return YY + MM + DD
+  }
+}
+//客户端收到推送消息,调用此js方法
+function afterReceivePushMessage (type, url) {
+  try {
+    if(type == "bid" || (type == "bid" && url.indexOf("__member__") > -1)){
+      $.post("/publicapply/subscribe/vipSwitch",null,function(res){
+        if(res.error_code == 0) {
+          if(res.data.vt == 'm' && url.indexOf("__member__") > -1) {
+            JyObj.showRedSpotOnMenu("subscribe");
+          }else if(res.data.vt != 'm' && url.indexOf("__member__") == -1){
+            JyObj.showRedSpotOnMenu("subscribe");
+          }
+        }
+      });
+    }else if (type == "entnichepush" || type == "member" || type == "projectforecast" || type == "entchange" || type == "memberreport") {
+      JyObj.hideRedSpotOnMenu("my");
+    }
+    receivePushMessageHandle(type, url);
+  } catch (e) {
+    console.log(e)
+  }
+}
+
+//获取用户经纬度 每天记录一次
+function latlongitude(){
+  //首页
+  if(window.location.href.indexOf("jylab/mainSearch")==-1){
+    return false;
+  }
+  var llitude = "";
+  var lsllitude = localStorage.LLitude;
+  var nowDate = new Date().getDate();
+  var oldDate = new Date().getDate()-1;
+  if (lsllitude!=null&&lsllitude.split("_").length>2){
+    oldDate =  Number(lsllitude.split("_")[2]);
+  }
+  //每天记录一次
+  //alert(nowDate+"--"+oldDate+"--"+parseInt(distance))
+  if (nowDate==oldDate){
+    return false;
+  }
+  try{
+    llitude = JyObj.getLLitude();
+  }catch(e){}
+  if(llitude==""){
+    var ai = 0;
+    var llInterval = setInterval(function(){
+      ai=ai+1;
+      try{
+        llitude = JyObj.getLLitude();
+      }catch(e){}
+      //五次获取不到客户端经纬度 就不再获取,获取位置存localStorage 一天
+      //alert(llitude+"---:"+ai)
+      if((llitude!=""&&llitude!=undefined&&llitude.indexOf("null")<0)||ai>4){
+        clearInterval(llInterval);
+        llrequest(llitude)
+      }
+    },500)
+  }else{
+    //alert("经纬度:"+llitude)
+    llrequest(llitude)
+  }
+}
+//判断经纬度是否够收录条件
+function llrequest(ll){
+  //获取不到定位信息
+  if(ll==null||ll.indexOf("_")==-1){
+    return false
+  }
+  //localStorage.removeItem("LLitude");
+  var latitude = parseFloat(ll.split("_")[1]);//纬度
+  var longitude =  parseFloat(ll.split("_")[0]);//经度
+  var _lat = 0.0;
+  var _long = 0.0;
+  var llitude = localStorage.LLitude;
+  if (llitude!=null&&llitude.split("_").length>2){
+    _long =  parseFloat(llitude.split("_")[0]);//经度
+    _lat =  parseFloat(llitude.split("_")[1]);//纬度
+  }
+  //alert(latitude+":::"+longitude+"----"+_lat+":::"+_long)
+  var calculate = calculateLL(latitude,longitude,_lat,_long);
+  if (calculate>parseInt(distance)){
+    $.post("/publicapply/appLoc/action", {
+      "longitude": longitude,
+      "latitude": latitude,
+      "calculate": calculate
+    }, function (r) {
+      if (r.data) {
+        localStorage.LLitude = ll+"_"+new Date().getDate();
+      }
+    })
+  }
+}
+/*计算两经纬度点之间的距离(单位:米)*/
+function calculateLL(lat1, lng1, lat2, lng2) {
+  var radLat1 = lat1 * Math.PI / 180.0;
+  var radLat2 = lat2 * Math.PI / 180.0;
+  var a = radLat1 - radLat2;
+  var b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
+  var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
+  s = s * 6378.137;
+  s = Math.round(s * 10000) / 10;
+  //alert("距离上个位置:"+s+" 米")
+  return s
+}
+//
+function androidVersion(){
+  if(mySysIsIos()){
+    return "";
+  }
+  var m = navigator.userAgent.match(/Android \d+/);
+  if(m == null){
+    return "";
+  }
+  return m[0].split(" ")[1];
+}
+//app更新日志
+function newVersionUpdateLog(event,new_version){
+  $.post("/jyapp/free/newVersionUpdateLog",{
+    token: JyObj.getUserToken(),//用户token
+    event: event,//事件类型
+    current_version: JyObj.getVersion(),//当前版本号
+    new_version: new_version,//新版本号
+    channel: getChannel(),//渠道
+    phonetype: getPhoneType(),//手机型号
+    system: androidVersion()
+  })
+
+}
+
+/**
+ * 根据keys校验object必填项
+ * @param {Array} keys - 待校验字段keys
+ * @param {Object} target - 待校验object
+ * @returns {boolean} - 是否通过
+ */
+function checkRequiredKeys (keys, target) {
+  try {
+    // 职位/部门特殊处理, 满足时移除部门校验
+    if (keys.indexOf('branch') !== -1 && keys.indexOf('position') !== -1) {
+      if (target['position'] === '总裁' || target['position'] === '总经理') {
+        keys.splice(keys.indexOf('branch'), 1)
+      }
+    }
+    return !keys.some(function (k) {
+      var tempValue = target[k]
+      var result = false
+      if (typeof tempValue === 'number') {
+        tempValue = tempValue.toString()
+      }
+      if (typeof tempValue === 'string') {
+        result = tempValue.trim() !== ''
+      }
+      if (typeof tempValue === 'boolean') {
+        result = true
+      }
+      return !result
+    })
+  } catch (e) {
+    console.warn(e)
+    return false
+  }
+}
+
+/**
+ * 根据keys覆盖object必填项
+ * @param {Object}target - 指定需替换的object
+ * @param {Object}now - 数据来源object
+ * @param {Array}[keys] - 指定需替换的keys
+ * @returns {Object} - 替换后的object,需注意target已被替换
+ */
+function echoRequiredValues (target, now, keys) {
+  try {
+    Object.keys(now).forEach(function (k) {
+      if (keys && keys.indexOf(k) === -1) {
+        return
+      }
+      if (target.hasOwnProperty(k)) {
+        target[k] = JSON.parse(JSON.stringify(now[k]))
+      }
+    })
+    return target
+  } catch (e) {
+    console.warn(e)
+    return {}
+  }
+}
+
+function addPageCommonStorageEvent () {
+  var listenerKey = 'commonEvent'
+  var currentData = localStorage.getItem(listenerKey)
+
+  window._doTryCallCommonEvent = function (type, data) {
+    localStorage.setItem(listenerKey, JSON.stringify({
+      type: type,
+      data: data,
+      _key: Date.now(),
+      origin: location.href
+    }))
+  }
+
+  var inIframe = window.top !== window
+  if (inIframe) return
+
+  window.addEventListener('storage', function (event) {
+    if (event.key === listenerKey) {
+      var newData = event.newValue
+      if (newData === currentData) return
+      if (typeof window._doTryRespondCommonEvent === 'function') {
+        window._doTryRespondCommonEvent(newData, currentData)
+      } else {
+        try {
+          var nowData = JSON.parse(newData)
+          var canReloadEvent = nowData.type === 'reload' && nowData.origin !== location.href
+          if (canReloadEvent) {
+            location.reload()
+          }
+        } catch (e) {
+          console.warn(e)
+        }
+      }
+    }
+  })
+}
+
+addPageCommonStorageEvent()

+ 57 - 0
resource/staticres/mobile/js/index.js

@@ -0,0 +1,57 @@
+var page = {
+  init: function () {
+    areaNavModule.init()
+    bannerSwiper.init()
+    backToTop.init()
+    industryNav.init()
+    entBuyerInfoList.init()
+    textTagListShowMore.init()
+    loading.init()
+    this.initEvents()
+    this.changeTopNavTheme(!!templateData.areaTopTitle)
+    this.clearSessionStorages()
+  },
+  initEvents: function () {
+    this.initFooterPhoneCall()
+    // this.showAppFooterNavs()
+  },
+  showAppFooterNavs: function () {
+    var isInHomePage = location.pathname === '/jyapp/jylab/mainSearch'
+    if (utils.$envs.inApp) {
+      setTimeout(function () {
+        try {
+          if (isInHomePage) {
+            JyObj.hiddenBottom('1')
+          }
+        } catch (error) {
+          console.log(error)
+        }
+      }, 10)
+    }
+  },
+  clearSessionStorages: function () {
+    localStorage.removeItem('JY-MOBILE-home-top-search')
+  },
+  initFooterPhoneCall: function () {
+    if (utils.$envs.inApp) {
+      $('.tel-link,.phone-concat-customer').on('click', function (e) {
+        e.preventDefault()
+        var tel = $(this).attr('data-tel')
+        try {
+          JyObj.callPhone(tel)
+        } catch (error) {
+          console.log(error)
+        }
+      })
+    }
+  },
+  changeTopNavTheme: function (f) {
+    if (f) {
+      $('.tag-info-type-nav-list, .tag-area-nav-container').addClass('dark-mode')
+    }
+  }
+}
+
+$(function () {
+  page.init()
+})

+ 203 - 0
resource/staticres/mobile/js/tag-common.js

@@ -0,0 +1,203 @@
+var areaNavModule = {
+  $el: null,
+  init: function () {
+    this.getTargetDOM()
+    this.addListener()
+  },
+  getTargetDOM: function () {
+    this.$el = $('.tag-area-nav-container')
+  },
+  addListener: function () {
+    var _this = this
+    if (!this.$el) return
+    this.$el.find('.action-show-more').on('click', function () {
+      _this.$el.find('.tag-area-nav-list-group').toggle()
+    })
+  }
+}
+
+var loading = {
+  $el: $('.loading-wrapper'),
+  init: function () {
+    var _this = this
+    $('[v-loading]').on('click', function () {
+      _this.show()
+    })
+  },
+  show: function () {
+    this.$el.show()
+    $('body').addClass('loading')
+  },
+  hide: function () {
+    this.$el.hide()
+    $('body').removeClass('loading')
+  }
+}
+
+var bannerSwiper = {
+  $el: $('.swiper-container'),
+  className: '.swiper-container',
+  init: function () {
+    this.initSwiper()
+  },
+  initSwiper: function () {
+    var _this = this
+    var conf = {
+      slidesPerView: 1,
+      centeredSlides: true,
+      observer: true,
+      speed: 800,
+      pagination: {
+        el: '.swiper-pagination'
+      },
+      autoplay: _this.$el.find('.swiper-slide').length > 1 ? {
+        delay: 5000
+      } : false, // imageList.length > 1 ? true : false
+      loop: _this.$el.find('.swiper-slide').length > 1 ? true : false,
+    }
+    // console.log(conf)
+    this.$el = new Swiper(this.className, conf)
+  },
+}
+
+var backToTop = {
+  $scrollDOM: $(window),
+  $backToTop: $('.back-to-top'),
+  init: function () {
+    this.checkBackToTopButtonShow()
+    this.bindEvents()
+  },
+  bindEvents: function () {
+    var _this = this
+    this.$backToTop.on('click', function () {
+      $('html').animate({
+        scrollTop: 0
+      })
+    })
+    this.$scrollDOM.on('scroll', function (e) {
+      _this.checkBackToTopButtonShow()
+    })
+  },
+  checkBackToTopButtonShow: function () {
+    var scrollTop = this.$scrollDOM.scrollTop()
+    if (scrollTop < 5) {
+      this.$backToTop.hide()
+    } else {
+      this.$backToTop.show()
+    }
+  },
+}
+
+var industryNav = {
+  $el: $('.industry-nav-container'),
+  init: function () {
+    this.bindEvents()
+    this.$el.find('.tag-industry-item:eq(0)').trigger('click')
+  },
+  bindEvents: function () {
+    var _this = this
+    this.$el.find('.tag-industry-list').on('click', '.tag-industry-item', function () {
+      var $this = $(this)
+      var value = $this.attr('data-value')
+      $this.addClass('active').siblings().removeClass('active')
+      var target = _this.$el.find('[data-list-title='+value+']')
+      target.show().siblings().hide()
+    })
+  }
+}
+
+var textTagListShowMore = {
+  $el: $('.text-list-container'),
+  init: function () {
+    this.bindEvents()
+  },
+  // calcActionButtonPosition: function () {
+  //   this.$el.find('.tag-card-bd').each(function (_, cardBody) {
+  //     var cardBodyHeight = $(this).height()
+  //     var actionGroup = $(this).find('.action-group')
+  //     $(cardBody).find('.text-list-item').each(function (index, item) {
+  //       var offsetTop = item.offsetTop
+  //       if (offsetTop >= cardBodyHeight) {
+  //         // 将操作按钮组插入此元素前
+  //         actionGroup.find('.more').show().end().insertBefore($(item))
+  //         return false // return false 提前结束循环
+  //       }
+  //     })
+  //   })
+  // },
+  bindEvents: function () {
+    this.$el.find('.action-group').on('click', '.more,.shouqi', function () {
+      var $this = $(this)
+      var parentWrapper = $(this).parents('.tag-card-bd').find('.tag-card-i-content-list')
+      if ($(this).hasClass('more')) {
+        parentWrapper.removeClass('max-height')
+      }
+      if ($(this).hasClass('shouqi')) {
+        parentWrapper.addClass('max-height')
+      }
+      $this.hide().siblings().show()
+    })
+  }
+}
+
+var entBuyerInfoList = {
+  $elBuyer: $('.buyer-info-list-container'),
+  $elEnt: $('.ent-info-list-container'),
+  init: function () {
+    this.calcEntBuyerShortname()
+  },
+  calcEntBuyerShortname: function () {
+    var _this = this
+    // 计算采购采购单位shortName
+    this.$elBuyer.find('.buyer-info-item').each(function (index, buyer) {
+      var $buyer = $(buyer)
+      var entName = $buyer.find('.buyer-info-title a').text()
+      var shortname = _this.getShortName(entName)
+      $buyer.find('.hd-icon').text(shortname)
+    })
+    // 计算企业列表shortName,并添加colorful icon bgc
+    this.$elEnt.find('.ent-info-item').each(function (index, ent) {
+      var $ent = $(ent)
+      var buyerName = $ent.find('.ent-info-title a').text()
+      var shortname = _this.getShortName(buyerName)
+      var colorfulIconClassName = _this.randomBgc()
+      $ent.find('.hd-icon').text(shortname).addClass(colorfulIconClassName)
+    })
+  },
+  getShortName: function (comName) {
+    var areaMap = chinaMapJSON || []
+    var shortname = comName
+    // 1. 循环省份城市进行替换
+    areaMap.forEach(function (item) {
+        var p = item.name.replace(/[省市]/, '')
+        if (shortname.indexOf(p) !== -1) {
+            shortname = shortname.replace(item.name, '').replace(p, '')
+            // console.log(p + ' -> \'\'')
+        }
+        item.city.forEach(function (iitem) {
+            var c = iitem.name.replace(/[省市]/, '')
+            if (shortname.indexOf(c) !== -1) {
+                shortname = shortname.replace(iitem.name, '').replace(c, '')
+                // console.log(c + ' -> \'\'')
+            }
+            iitem.area.forEach(function (iiitem) {
+                if (shortname.indexOf(iiitem) !== -1) {
+                    shortname = shortname.replace(iiitem, '')
+                    // console.log(iiitem + ' -> \'\'')
+                }
+            })
+        })
+    })
+    var matchRes = shortname.match(/[\u4e00-\u9fa5]{4}/gm)
+    var shortname = matchRes ? matchRes[0] : shortname.slice(0, 4)
+    if (shortname.length < 4) {
+        shortname = shortname.slice(0, 4)
+    }
+    return shortname
+  },
+  randomBgc: function () {
+    var arr = ['default', 'blue', 'orange', 'green']
+    var randomIndex = utils.getRandomNumber(0, arr.length - 1)
+    return 'bgc-' + arr[randomIndex]
+  }
+}

+ 95 - 0
resource/template/mobile/area_index.html

@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html lang="zh-CN" style="font-size: 50px;">
+<head>
+    {{include "mobile/components/tag-meta.html" .}}
+    <title>{{.tdk.Title}}</title>
+    {{include "mobile/components/tag-header-common-assets.html" .}}
+</head>
+<body>
+<section class="page-container">
+    <header class="page-header">
+        {{include "mobile/components/tag-header.html"}}
+    </header>
+    <main class="page-main">
+        <div class="module-wrapper">
+            <!--        头部搜索-->
+            {{include "mobile/components/tag-register-login-group.html" .}}
+            {{include "mobile/components/tag-info-type-nav.html"}}
+            {{include "mobile/components/tag-area-nav.html"}}
+            <!--        广告位-->
+            {{include "mobile/components/tag-swiper-list.html"}}
+            <!--         各类招标信息 -->
+            <section class="card-list">
+                {{include "mobile/components/tag-card-bidding-title.html" (CardFormat (concat .areaNode.Name "招标预告")
+                (concat "/list/" .areaType "/" .areaNode.Code "_01/") (GetMiniTab .areaNode.Code "ZBYG" 8))}}
+                {{include "mobile/components/tag-card-bidding-title.html" (CardFormat (concat .areaNode.Name "招标公告")
+                (concat "/list/" .areaType "/" .areaNode.Code "_02/") (GetMiniTab .areaNode.Code "ZBGG" 8))}}
+                {{include "mobile/components/tag-card-bidding-title.html" (CardFormat (concat .areaNode.Name "招标结果")
+                (concat "/list/" .areaType "/" .areaNode.Code "_03/") (GetMiniTab .areaNode.Code "ZBJG" 8))}}
+                {{include "mobile/components/tag-card-bidding-title.html" (CardFormat (concat .areaNode.Name "招标信用信息")
+                (concat "/list/" .areaType "/" .areaNode.Code "_04/") (GetMiniTab .areaNode.Code "ZBXYXX" 8))}}
+
+                {{$biddingList:=.T.biddingList}}
+                {{range $v := $biddingList}}
+                {{include "mobile/components/tag-card-bidding-title.html" $v }}
+                {{end}}
+            </section>
+            <!--          招标导航-->
+            <section class="tag-card bg-white industry-nav-container mt12">
+                <header class="tag-card-hd">
+                    <h3 class="tag-card-title">招标导航</h3>
+                    <div class="tag-card-actions">
+                        <a href="/tags/industry/all.html">更多<i class="j-icon base-icon icon-arrow-up"></i></a>
+                    </div>
+                </header>
+                {{$industryArr := GetEachIndustryRandomKeyWords 12}}
+                <main class="tag-card-bd">
+                    <div class="tag-industry-hd-container">
+                        <ul class="tag-industry-list">
+                            {{range $industry:=$industryArr}}
+                            <li class="tag-industry-item active" data-value="{{$industry.Class}}">{{$industry.Class}}
+                            </li>
+                            {{end}}
+                        </ul>
+                    </div>
+                    <div class="tag-industry-bd-container">
+                        {{range $industry:=$industryArr}}
+                        <ul class="tag-card-i-content-list" style="display: none;"
+                            data-list-title="{{$industry.Class}}">
+                            {{range $info:=$industry.List}}
+                            <li class="tag-industry-content-item nav-button">
+                                <a href="{{$info.Url}}" v-loading>{{$info.KeyWord}}</a>
+                            </li>
+                            {{end}}
+                        </ul>
+                        {{end}}
+                    </div>
+                </main>
+            </section>
+            <section class="tag-breadcrumb-navigation ellipsis">
+                <span>当前位置:</span>
+                <a href="/">剑鱼标讯首页</a>
+                &gt; <a href="javascript:;">{{.areaNode.Name}}招标网</a>
+            </section>
+            {{include "mobile/components/tag-footer.html"}}
+        </div>
+    </main>
+</section>
+<div class="loading-wrapper" style="display: none;">
+    <div class="loading-icon"></div>
+</div>
+{{include "mobile/components/tag-footer-common-assets.html"}}
+<script>
+    var templateData = {
+        homeLink: "/tags/home/home.html",
+        areaTopTitle: "{{if .areaNode}}{{.areaNode.Name}}招标网{{end}}"
+    }
+</script>
+<script src='{{Cdn2}}/common-module/public/js/china-map-data.js?v={{Msg "version"}}'></script>
+<script src='/jyseo/mobile/js/common.js'></script>
+<script src='/jyseo/mobile/js/tag-common.js'></script>
+<script src='/jyseo/mobile/js/index.js'></script>
+
+</body>
+</html>
+

+ 65 - 0
resource/template/mobile/area_list.html

@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html lang="zh-CN" style="font-size: 50px;">
+<head>
+    {{include "mobile/components/tag-meta.html" .}}
+    <title>{{.tdk.Title}}</title>
+    {{include "mobile/components/tag-header-common-assets.html" .}}
+</head>
+<body>
+<section class="page-container">
+    <header class="page-header">
+        {{include "mobile/components/tag-header.html"}}
+    </header>
+    <main class="page-main">
+        <div class="module-wrapper">
+            {{$areaNode := .areaNode}}
+            {{$sTypeNode := .sTypeNode}}
+            {{$sTypeArr := GetSTypeParentNodes}}
+            <!-- 头部搜索-->
+            {{include "mobile/components/tag-register-login-group.html" .}}
+            {{include "mobile/components/tag-info-type-nav.html"}}
+            {{include "mobile/components/tag-area-nav.html"}}
+            <!-- 广告位-->
+            {{include "mobile/components/tag-swiper-list.html"}}
+            <!-- 数据列表-->
+            <section class="tag-card bg-white bidding-info-list-container mt12">
+                <header class="tag-card-hd">
+                    <h2 class="tag-card-title"> {{$areaNode.Name}}{{$sTypeNode.Name}} </h2>
+                    <div class="tag-card-actions"></div>
+                </header>
+                {{include "mobile/components/tag-card-bidding-info-list.html" .}}
+                <footer class="tag-card-ft">
+                    {{include "mobile/components/tag-pagination.html" .}}
+                </footer>
+            </section>
+            <section class="tag-breadcrumb-navigation ellipsis">
+                <span>当前位置:</span>
+                <a href="/">剑鱼标讯首页</a>
+                {{if $areaNode.PNode}}
+                &gt; <a href="/list/area/{{$areaNode.PNode.Code}}.html">{{$areaNode.PNode.Name}}招标网</a>
+                {{end}}
+                &gt; <a href="/list/area/{{$areaNode.Code}}.html">{{$areaNode.Name}}招标网</a>
+                &gt; <span class="current-tag">{{$areaNode.Name}}{{$sTypeNode.Name}}</span>
+            </section>
+            {{include "mobile/components/tag-footer.html"}}
+        </div>
+    </main>
+</section>
+<div class="loading-wrapper" style="display: none;">
+    <div class="loading-icon"></div>
+</div>
+{{include "mobile/components/tag-footer-common-assets.html"}}
+<script>
+    var templateData = {
+        homeLink: "/tags/home/home.html",
+        areaTopTitle: "{{if .areaNode}}{{.areaNode.Name}}招标网{{end}}"
+    }
+</script>
+<script src='{{Cdn2}}/common-module/public/js/china-map-data.js?v={{Msg "version"}}'></script>
+<script src='/jyseo/mobile/js/common.js'></script>
+<script src='/jyseo/mobile/js/tag-common.js'></script>
+<script src='/jyseo/mobile/js/index.js'></script>
+
+</body>
+</html>
+

+ 109 - 0
resource/template/mobile/components/baiducc.html

@@ -0,0 +1,109 @@
+<script>
+  var _hmt = _hmt || [];
+  var advUrl = window.location.href;
+  // 将版本号存至本地缓存,供vue单页面程序获取
+  localStorage.setItem('jyVersion-to-vue', {{Msg "version"}})
+
+  function adv_statistics(e){
+    var advName = $(e).attr("adv_name");
+    _hmt.push(['_trackEvent', '广告', 'click', advName]);
+    grafana_statistics(advName);
+    if ($(e).find("a").attr("datalink")!=undefined){
+      window.location.href= $(e).find("a").attr("datalink");
+    }
+    if ($(e).find("a").attr("ad_link")!=undefined){//app三级页调用打开方法
+      var ad_title = $(e).find("a").attr("ad_title");
+      if (utils.$envs.inApp) {
+        JyObj.openExternalLink($(e).find("a").attr("ad_link"), ad_title);
+      }
+      window.location.href= $(e).find("a").attr("ad_link");
+    }
+    if ($(e).find("a").attr("openurl")!=undefined){//app三级页调用打开方法
+      $.post('/salesLeads/retainedCapital'+ '?source=article_original').done(function (r) {
+        // 判断当前信息否在其他页面留资  如果全部留资 直接弹窗提交成功
+        var checkKeys = ['name', 'phone', 'company', 'branch', 'position', 'companyType']
+        var result = checkRequiredKeys(checkKeys, r.info)
+        if (result || !window.isFree) {
+          if (utils.$envs.inApp) {
+            JyObj.openExternalLink($(e).find("a").attr("openurl"), "查看原文");
+          }
+          window.location.href= $(e).find("a").attr("openurl");
+          return true
+        }
+
+        if (r && r.error_msg === '' && r.data) {
+          if (r.data.retainedCapital || !result) {
+            vKeepComponent.$dialog.confirm({
+              message: '为给您匹配精准的推荐信息,请完善个人信息,免费查看原文',
+              className: 'ent-search-dialog max-54 add-close-after',
+              overlayClass: 'z-2030',
+              showCancelButton: false,
+              confirmButtonText: '立即前往',
+            }).then(function () {
+              sessionStorage.setItem('salesBackData', JSON.stringify({
+                type: 'article_original',
+                url: $(e).find("a").attr("openurl")
+              }))
+              location.href = '/jyapp/frontPage/bigmember/free/perfect_info?origin=article_original'
+            }).catch(function () {});
+            $("body").on('click', '.add-close-after .van-dialog__content', function (e) {
+              vKeepComponent.$dialog.close()
+            })
+          } else {
+            if (utils.$envs.inApp) {
+              JyObj.openExternalLink($(e).find("a").attr("openurl"),"查看原文");
+            }
+            window.location.href= $(e).find("a").attr("openurl");
+          }
+        } else {
+          if (utils.$envs.inApp) {
+            JyObj.openExternalLink($(e).find("a").attr("openurl"),"查看原文");
+          }
+          window.location.href= $(e).find("a").attr("openurl");
+        }
+      }).fail(function () {
+        if (utils.$envs.inApp) {
+          JyObj.openExternalLink($(e).find("a").attr("openurl"),"查看原文");
+        }
+        window.location.href= $(e).find("a").attr("openurl");
+      })
+    }
+  }
+
+  function grafana_statistics(advName){
+    var obj = {
+      "pccontent_bottom":  "PC快照页-底部",
+      "pccontent_right":   "PC快照页-右部",
+      "pcsearch_bottom":   "PC搜索列表页-底部",
+      "wxcontent_bottom":  "微信快照页-底部",
+      "wxpush_middle":     "微信推送历史页-中部",
+      "wxsearch_middle":   "微信搜索列表页-中部",
+      "appcontent_bottom": "APP快照页-底部",
+      "apppush_middle":    "APP推送历史页-中部",
+      "appsearch_middle":  "APP搜索列表页-中部",
+      "wxswiper_one":      "微信搜索页轮播图1",
+      "wxswiper_two":      "微信搜索页轮播图2",
+      "wxswiper_three":    "微信搜索页轮播图3",
+      "wxswiper_four":     "微信搜索页轮播图4",
+      "appswiper_one":     "APP搜索页轮播图1",
+      "appswiper_two":     "APP搜索页轮播图2",
+      "appswiper_three":   "APP搜索页轮播图3"
+    }
+    if(advName !== ""){
+      for(var i in obj){
+        if(advName === obj[i]){
+          $.ajax({
+            type: "get",
+            url: "/jyapp/front/grafanaStatistics?advName=" + i
+          })
+        }
+      }
+    }
+  }
+  try {
+    /* 临时修改 头部 */
+    $("head").append("<style>\n.jy-app-header.app-layout-header span.app-back.jyapp-icon.jyapp-icon-zuojiantou::after,.j-header.jy-app-header span.icon-fanhui::after {\n    content: \"\";\n    display: inline-block;\n    width: 4em;\n    height: 100%;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n</style>");
+  } catch (e) {
+    console.warn(e)
+  }
+</script>

+ 40 - 0
resource/template/mobile/components/tag-area-nav.html

@@ -0,0 +1,40 @@
+<section class="tag-area-nav-container">
+  <div class="tag-area-nav-list-container simple-area">
+    <p class="tag-area-nav-list-title">分站</p>
+    <ul class="tag-area-nav-list">
+      <li class="tag-area-nav-item">
+        <a href="/list/area/BJ.html" title="北京招标网">北京</a>
+      </li>
+      <li class="tag-area-nav-item">
+        <a href="/list/area/SD.html" title="山东招标网">山东</a>
+      </li>
+      <li class="tag-area-nav-item">
+        <a href="/list/area/SXC.html" title="陕西招标网">陕西</a>
+      </li>
+      <li class="tag-area-nav-item">
+        <a href="/list/area/JS.html" title="江苏招标网">江苏</a>
+      </li>
+      <li class="tag-area-nav-item">
+        <a href="/list/area/GD.html" title="广东招标网">广东</a>
+      </li>
+      <li class="tag-area-nav-item highlight-text action-show-more">更多 &gt;</li>
+    </ul>
+  </div>
+  <ul class="tag-area-nav-list-group" style="display: none;">
+    {{range $k,$v := GetConfigArr "areaModule"}}
+    <li class="tag-area-nav-list-container more-area">
+      <p class="tag-area-nav-list-title">{{$v.name}}</p>
+      <ul class="tag-area-nav-list">
+        {{range $n,$m := $v.values}}
+          {{$node:=(GetAreaNodeByCode $m)}}
+          {{if $node}}
+            <li class="tag-area-nav-item">
+              <a href="/list/area/{{$node.Code}}.html" title="{{$node.Name}}招标网"> {{$node.Name}}</a>
+            </li>
+          {{end}}
+        {{end}}
+      </ul>
+    </li>
+    {{end}}
+  </ul>
+</section>

+ 24 - 0
resource/template/mobile/components/tag-card-bidding-info-list.html

@@ -0,0 +1,24 @@
+<main class="tag-card-bd">
+    <ul class="bidding-info-list">
+      {{if ne (len .list) 0 }}
+        {{range $k,$v :=.list}}
+          <li class="bidding-info-item">
+            <div class="bidding-info-hd">
+              <a class="bidding-info-title ellipsis-2" href="{{$v.Url}}"> {{$v.Title}} </a>
+            </div>
+            <div class="bidding-info-bd">
+              <div class="tag-group clearfix">
+                {{if $v.Area}}<p class="tag-item grey fl">{{$v.Area}}</p>{{end}}
+                {{if $v.Industry}}<p class="tag-item grey fl">{{$v.Industry}}</p>{{end}}
+                {{if $v.Subtype}}<p class="tag-item grey fl">{{$v.Subtype}}</p>{{end}}
+                {{if $v.Price}}<p class="tag-item grey fl">{{$v.Price}}</p>{{end}}
+                {{if $v.PublishTime }}<p class="tag-item tag-item--time fr">{{$v.PublishTime | date "Y-m-d"}}</p>{{end}}
+              </div>
+            </div>
+            <!-- <div class="bidding-info-ft"></div> -->
+          </li>
+        {{end}}
+      {{end}}
+    </ul>
+  </main>
+

+ 20 - 0
resource/template/mobile/components/tag-card-bidding-title.html

@@ -0,0 +1,20 @@
+<section class="tag-card bg-white bidding-list">
+  <header class="tag-card-hd">
+    <h3 class="tag-card-title">{{.title}}</h3>
+    <div class="tag-card-actions">
+      <a href="{{.link}}">更多<i class="j-icon base-icon icon-arrow-up"></i></a>
+    </div>
+  </header>
+  {{ if ne (len .data) 0 }}
+  <main class="tag-card-bd">
+    <ul class="tag-card-list">
+      {{range $k,$v:= .data}}
+      <li class="tag-card-item ellipsis">
+        <a href="{{$v.Url}}">{{$v.Title}}</a>
+      </li>
+      {{end}}
+    </ul>
+  </main>
+  {{end}}
+</section>
+

+ 25 - 0
resource/template/mobile/components/tag-card-text-list.html

@@ -0,0 +1,25 @@
+<section>
+  {{range $industry:=.industryList}}
+  <section class="tag-card bg-white text-list-container mt12">
+    <header class="tag-card-hd">
+      <h3 class="tag-card-title">{{$industry.Class}}</h3>
+      <div class="tag-card-actions"></div>
+    </header>
+    <main class="tag-card-bd">
+      <div class="tag-card-bd-content">
+        <ul class="tag-card-i-content-list max-height clearfix">
+          {{range $v:=$industry.List}}
+          <li class="text-list-item text-button fl">
+            <a href="{{$v.Url}}">{{$v.KeyWord}}</a>
+          </li>
+          {{end}}
+        </ul>
+        <div class="text-button action-group highlight-text">
+          <span class="more">更多&gt;</span>
+          <span class="shouqi" style="display: none;">收起&lt;</span>
+        </div>
+      </div>
+    </main>
+  </section>
+  {{end}}
+</section>

+ 15 - 0
resource/template/mobile/components/tag-footer-common-assets.html

@@ -0,0 +1,15 @@
+<script src='{{Cdn2}}/common-module/public/js/utils.js?v={{Msg "version"}}'></script>
+<script>
+    utils.iosBackRefresh()
+    // 头部事件js
+    // goBack写外面方便随时解绑
+    function goBack() {
+        history.back()
+        window.afterClickBack && window.afterClickBack()
+    }
+</script>
+<!-- seo相关页面未使用到客户端方法,暂时不引用commonjs -->
+<!-- <script src='{{Cdn2}}/jyapp/js/common.js?v={{Msg "version"}}'></script> -->
+<script src='https://cdn-common.jianyu360.com/cdn/lib/jquery/3.6.0/jquery.min.js'></script>
+<script src="https://cdn-common.jianyu360.com/cdn/lib/swiper/5.4.2/swiper.min.js"></script>
+{{include "mobile/components/baiducc.html"}}

+ 30 - 0
resource/template/mobile/components/tag-footer.html

@@ -0,0 +1,30 @@
+<section class="tag-footer-container">
+  <div class="footer-card">
+    <div class="footer-card-line tel-container">
+      <p>咨询热线</p>
+      <a class="tel-link" data-tel="400-108-6670" href="tel:400-108-6670">400-108-6670</a>
+    </div>
+    <div class="footer-card-line bottom-navs">
+      <a class="bottom-nav-link" href="/">首页</a>
+      <a class="bottom-nav-link" href="/jyapp/free/swordfish/about">关于剑鱼标讯</a>
+    </div>
+    <div class="footer-divider"></div>
+    <p class="footer-card-line copyright">版权所有-剑鱼标讯</p>
+  </div>
+</section>
+<section class="tag-footer-container fixed">
+  <div class="footer-button-group">
+    <a class="seo-button theme-main radius phone-concat-customer" data-tel="400-108-6670" href="tel:400-108-6670">
+      <span class="j-icon base-icon icon-phone-white-solid"></span>
+      <p>电话咨询</p>
+    </a>
+    <a class="seo-button theme-main radius" href="/jyapp/free/login?url=/jyapp/jylab/mainSearch">
+      <span class="j-icon base-icon icon-person-white-solid"></span>
+      <p>登录/注册</p>
+    </a>
+  </div>
+</section>
+<section class="back-to-top">
+  <i class="j-icon base-icon icon-arrow-up2"></i>
+</section>
+

+ 10 - 0
resource/template/mobile/components/tag-header-common-assets.html

@@ -0,0 +1,10 @@
+<script src='{{Cdn2}}/common-module/history-push/local/rem.js'></script>
+<script src='https://cdn-common.jianyu360.com/cdn/lib/jquery/3.6.0/jquery.min.js'></script>
+<script src='{{Cdn2}}/common-module/public/head.js?v={{Msg "version"}}'></script>
+<!-- <script src='{{Cdn2}}/common-module/track/j-track.min.js?v={{Msg "version"}}'></script> -->
+
+<link rel="stylesheet" href=//cdn-common.jianyu360.com/cdn/lib/reset-css/5.0.1/reset.min.css />
+<link rel="stylesheet" href='{{Cdn2}}/jyapp/big-member/css/public.css?v={{Msg "version"}}' />
+<link rel="stylesheet" href='{{Cdn2}}/jyapp/big-member/css/j-icons.css?v={{Msg "version"}}' />
+<link rel="stylesheet" href="https://cdn-common.jianyu360.com/cdn/lib/swiper/5.4.2/swiper.min.css"/>
+<link rel="stylesheet" href='{{Cdn}}/jyseo/mobile/css/tags-module-common.css?v={{Msg "version"}}' />

+ 6 - 0
resource/template/mobile/components/tag-header.html

@@ -0,0 +1,6 @@
+<div class="tag-header-container j-header jy-app-header">
+    <a class="search-container bg-white" href="/jy_mobile/search/middle/bidding">
+        <i class="search-icon j-icon base-icon icon-search"></i>
+        <div class="search-input">请输入您要搜索的内容</div>
+    </a>
+</div>

+ 7 - 0
resource/template/mobile/components/tag-info-type-nav.html

@@ -0,0 +1,7 @@
+<ul class="tag-info-type-nav-list">
+  {{range $k,$v:= GetSTypeParentNodes}}
+  <li class="tag-info-type-nav-item">
+    <a href="/list/stype/{{$v.Code}}.html">{{$v.Name}}</a>
+  </li>
+  {{end}}
+</ul>

+ 17 - 0
resource/template/mobile/components/tag-meta.html

@@ -0,0 +1,17 @@
+
+<!--S-meta-->
+<meta charset="utf-8">
+<meta name="Keywords" content='{{.tdk.KeyWords}}'/>
+<meta name="Description" content='{{.tdk.Description}}'/>
+<meta name="author" content="剑鱼标讯">
+<meta name="applicable-device" content="mobile" />
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
+<meta name="browsermode" content="application">
+<meta name="x5-orientation" content="portrait">
+<meta name="screen-orientation" content="portrait">
+<meta name="x5-page-mode" content="app">
+<meta name="apple-mobile-web-app-capable" content="yes">
+<meta name="apple-mobile-web-app-status-bar-style" content="black">
+<meta name="format-detection" content="telephone=no">
+<link rel="icon" href="/favicon.ico">

+ 29 - 0
resource/template/mobile/components/tag-pagination.html

@@ -0,0 +1,29 @@
+<ul class="tag-pagination bg-white">
+    {{if .pagination.PrevHref }}
+    <li class="tag-pagination-button tag-pagination-prev clickable">
+        <a href="{{.pagination.PrevHref}}">
+            <i class="j-icon base-icon icon-arrow-up"></i>
+            <p>上一页</p>
+        </a>
+    </li>
+    {{else}}
+    <li class="tag-pagination-button tag-pagination-placeholder"></li>
+    {{end}}
+    <li class="tag-pagination-button tag-pagination-page-num">
+        <span class="highlight-text">    {{.pagination.PageNum}}</span>
+        <span>&nbsp;/&nbsp;</span>
+        <span>    {{.pagination.PageCount}}</span>
+    </li>
+
+    {{if .pagination.NextHref }}
+    <li class="tag-pagination-button tag-pagination-next clickable">
+        <a href="{{.pagination.NextHref}}">
+            <p>下一页</p>
+            <i class="j-icon base-icon icon-arrow-up"></i>
+        </a>
+    </li>
+    {{else}}
+    <li class="tag-pagination-button tag-pagination-placeholder"></li>
+    {{end}}
+</ul>
+

+ 9 - 0
resource/template/mobile/components/tag-register-login-group.html

@@ -0,0 +1,9 @@
+<section class="register-login-container bg-white">
+  <a class="logo-img-wrapper" href="/jyapp/jylab/mainSearch">
+    <img class="logo-img" src="{{Cdn2}}/common-module/public/image/jianyu-logo-for-free.png" alt="">
+  </a>
+  {{if .areaNode}}
+    <h1 class="header-title">{{.areaNode.Name}}招标网</h1>
+  {{end}}
+  <a class="seo-button theme-main" href="/jyapp/free/login?url=/jyapp/jylab/mainSearch">登录/注册</a>
+</section>

+ 16 - 0
resource/template/mobile/components/tag-swiper-list.html

@@ -0,0 +1,16 @@
+<section class="tag-swiper-list-container swiper-container bg-white">
+  <ul class="tag-swiper-list swiper-wrapper">
+    {{range $ad:=Ad "mobile_seo_ad" 1}}
+    <li class="tag-swiper-item swiper-slide">
+      {{if $ad.S_link}}
+      <a href="{{$ad.S_link}}">
+      {{else}}
+      <a href="javascript:;">
+      {{end}}
+        <img class="banner-img" src="{{$ad.S_pic}}" alt="{{$ad.S_picalt}}">
+      </a>
+    </li>
+    {{end}}
+  </ul>
+  <div class="swiper-pagination swiper-custom-dot"></div>
+</section>

+ 86 - 0
resource/template/mobile/index.html

@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html lang="zh-CN" style="font-size: 50px;">
+<head>
+    {{include "mobile/components/tag-meta.html" .}}
+    <title>{{.tdk.Title}}</title>
+    {{include "mobile/components/tag-header-common-assets.html" .}}
+</head>
+<body>
+<section class="page-container">
+    <header class="page-header">
+        {{include "mobile/components/tag-header.html"}}
+    </header>
+    <main class="page-main">
+        <div class="module-wrapper">
+            <!--        头部搜索-->
+            {{include "mobile/components/tag-register-login-group.html" .}}
+            {{include "mobile/components/tag-info-type-nav.html"}}
+            {{include "mobile/components/tag-area-nav.html"}}
+            <!--        广告位-->
+            {{include "mobile/components/tag-swiper-list.html"}}
+            <!--         各类招标信息 -->
+            <section class="card-list">
+                {{include "mobile/components/tag-card-bidding-title.html" (CardFormat "招标预告"  "/list/stype/ZBYG.html"  (GetMiniTab "" "ZBYG" 8))}}
+                {{include "mobile/components/tag-card-bidding-title.html" (CardFormat "招标公告"  "/list/stype/ZBGG.html"  (GetMiniTab "" "ZBGG" 8))}}
+                {{include "mobile/components/tag-card-bidding-title.html" (CardFormat "招标结果"  "/list/stype/ZBJG.html"  (GetMiniTab "" "ZBJG" 8))}}
+                {{include "mobile/components/tag-card-bidding-title.html" (CardFormat "招标信用信息" "/list/stype/ZBXYXX.html" (GetMiniTab "" "ZBXYXX" 8))}}
+
+                {{$biddingList:=.T.biddingList}}
+                {{range $v := $biddingList}}
+                {{include "mobile/components/tag-card-bidding-title.html" $v }}
+                {{end}}
+            </section>
+            <!--          招标导航-->
+            <section class="tag-card bg-white industry-nav-container mt12">
+                <header class="tag-card-hd">
+                    <h3 class="tag-card-title">招标导航</h3>
+                    <div class="tag-card-actions">
+                        <a href="/tags/industry/all.html">更多<i class="j-icon base-icon icon-arrow-up"></i></a>
+                    </div>
+                </header>
+                {{$industryArr := GetEachIndustryRandomKeyWords 12}}
+                <main class="tag-card-bd">
+                    <div class="tag-industry-hd-container">
+                        <ul class="tag-industry-list">
+                            {{range $industry:=$industryArr}}
+                            <li class="tag-industry-item active" data-value="{{$industry.Class}}">{{$industry.Class}}
+                            </li>
+                            {{end}}
+                        </ul>
+                    </div>
+                    <div class="tag-industry-bd-container">
+                        {{range $industry:=$industryArr}}
+                        <ul class="tag-card-i-content-list" style="display: none;"
+                            data-list-title="{{$industry.Class}}">
+                            {{range $info:=$industry.List}}
+                            <li class="tag-industry-content-item nav-button">
+                                <a href="{{$info.Url}}" v-loading>{{$info.KeyWord}}</a>
+                            </li>
+                            {{end}}
+                        </ul>
+                        {{end}}
+                    </div>
+                </main>
+            </section>
+            {{include "mobile/components/tag-footer.html"}}
+        </div>
+    </main>
+</section>
+<div class="loading-wrapper" style="display: none;">
+    <div class="loading-icon"></div>
+</div>
+{{include "mobile/components/tag-footer-common-assets.html"}}
+<script>
+    var templateData = {
+        homeLink: "/tags/home/home.html",
+        areaTopTitle: "{{if .areaNode}}{{.areaNode.Name}}招标网{{end}}"
+    }
+</script>
+<script src='{{Cdn2}}/common-module/public/js/china-map-data.js?v={{Msg "version"}}'></script>
+<script src='/jyseo/mobile/js/common.js'></script>
+<script src='/jyseo/mobile/js/tag-common.js'></script>
+<script src='/jyseo/mobile/js/index.js'></script>
+
+</body>
+</html>
+

+ 44 - 0
resource/template/mobile/industry_index.html

@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html lang="zh-CN" style="font-size: 50px;">
+<head>
+    {{include "mobile/components/tag-meta.html" .}}
+    <title>{{.tdk.Title}}</title>
+    {{include "mobile/components/tag-header-common-assets.html" .}}
+</head>
+<body>
+<section class="page-container">
+    <header class="page-header">
+        {{include "mobile/components/tag-header.html"}}
+    </header>
+    <main class="page-main">
+        <div class="module-wrapper">
+            <!-- 头部搜索-->
+            {{include "mobile/components/tag-register-login-group.html" .}}
+            {{include "mobile/components/tag-info-type-nav.html"}}
+            {{include "mobile/components/tag-area-nav.html"}}
+
+            <!-- 数据列表-->
+            {{include "mobile/components/tag-card-text-list.html" .}}
+
+            {{include "mobile/components/tag-footer.html"}}
+        </div>
+    </main>
+</section>
+<div class="loading-wrapper" style="display: none;">
+    <div class="loading-icon"></div>
+</div>
+{{include "mobile/components/tag-footer-common-assets.html"}}
+<script>
+    var templateData = {
+        homeLink: "/tags/home/home.html",
+        areaTopTitle: "{{if .areaNode}}{{.areaNode.Name}}招标网{{end}}"
+    }
+</script>
+<script src='{{Cdn2}}/common-module/public/js/china-map-data.js?v={{Msg "version"}}'></script>
+<script src='/jyseo/mobile/js/common.js'></script>
+<script src='/jyseo/mobile/js/tag-common.js'></script>
+<script src='/jyseo/mobile/js/index.js'></script>
+
+</body>
+</html>
+

+ 58 - 0
resource/template/mobile/industry_list.html

@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html lang="zh-CN" style="font-size: 50px;">
+<head>
+    {{include "mobile/components/tag-meta.html" .}}
+    <title>{{.tdk.Title}}</title>
+    {{include "mobile/components/tag-header-common-assets.html" .}}
+</head>
+<body>
+<section class="page-container">
+    <header class="page-header">
+        {{include "mobile/components/tag-header.html"}}
+    </header>
+    <main class="page-main">
+        <div class="module-wrapper">
+            <!-- 头部搜索-->
+            {{include "mobile/components/tag-register-login-group.html" .}}
+            {{include "mobile/components/tag-info-type-nav.html"}}
+            {{include "mobile/components/tag-area-nav.html"}}
+            <!-- 广告位-->
+            {{include "mobile/components/tag-swiper-list.html"}}
+            <!-- 数据列表-->
+            <section class="tag-card bg-white bidding-info-list-container mt12">
+                <header class="tag-card-hd">
+                    <h2 class="tag-card-title"> {{.keywordsNode.KeyWord}}招标采购信息列表 </h2>
+                    <div class="tag-card-actions"></div>
+                </header>
+                {{include "mobile/components/tag-card-bidding-info-list.html" .}}
+                <footer class="tag-card-ft">
+                    {{include "mobile/components/tag-pagination.html" .}}
+                </footer>
+            </section>
+            <section class="tag-breadcrumb-navigation ellipsis">
+                <span>当前位置:</span>
+                <a href="/">剑鱼标讯首页</a>
+                &gt; <span class="current-tag">{{.keywordsNode.KeyWord}}招标采购</span>
+            </section>
+            {{include "mobile/components/tag-footer.html"}}
+        </div>
+    </main>
+</section>
+<div class="loading-wrapper" style="display: none;">
+    <div class="loading-icon"></div>
+</div>
+{{include "mobile/components/tag-footer-common-assets.html"}}
+<script>
+    var templateData = {
+        homeLink: "/tags/home/home.html",
+        areaTopTitle: "{{if .areaNode}}{{.areaNode.Name}}招标网{{end}}"
+    }
+</script>
+<script src='{{Cdn2}}/common-module/public/js/china-map-data.js?v={{Msg "version"}}'></script>
+<script src='/jyseo/mobile/js/common.js'></script>
+<script src='/jyseo/mobile/js/tag-common.js'></script>
+<script src='/jyseo/mobile/js/index.js'></script>
+
+</body>
+</html>
+

+ 59 - 0
resource/template/mobile/sType_list.html

@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html lang="zh-CN" style="font-size: 50px;">
+<head>
+    {{include "mobile/components/tag-meta.html" .}}
+    <title>{{.tdk.Title}}</title>
+    {{include "mobile/components/tag-header-common-assets.html" .}}
+</head>
+<body>
+<section class="page-container">
+    <header class="page-header">
+        {{include "mobile/components/tag-header.html"}}
+    </header>
+    <main class="page-main">
+        <div class="module-wrapper">
+            <!-- 头部搜索-->
+            {{include "mobile/components/tag-register-login-group.html" .}}
+            {{include "mobile/components/tag-info-type-nav.html"}}
+            {{include "mobile/components/tag-area-nav.html"}}
+            <!-- 广告位-->
+            {{include "mobile/components/tag-swiper-list.html"}}
+            <!-- 数据列表-->
+            <section class="tag-card bg-white bidding-info-list-container mt12">
+                <header class="tag-card-hd">
+                    <h2 class="tag-card-title"> {{.sTypeNode.Name}} </h2>
+                    <div class="tag-card-actions"></div>
+                </header>
+                    {{include "mobile/components/tag-card-bidding-info-list.html" .}}
+                <footer class="tag-card-ft">
+                    {{include "mobile/components/tag-pagination.html" .}}
+                </footer>
+            </section>
+
+            <section class="tag-breadcrumb-navigation ellipsis">
+                <span>当前位置:</span>
+                <a href="/">剑鱼标讯首页</a>
+                &gt; <a href="javascript:;">{{.sTypeNode.Name}}</a>
+            </section>
+            {{include "mobile/components/tag-footer.html"}}
+        </div>
+    </main>
+</section>
+<div class="loading-wrapper" style="display: none;">
+    <div class="loading-icon"></div>
+</div>
+{{include "mobile/components/tag-footer-common-assets.html"}}
+<script>
+    var templateData = {
+        homeLink: "/tags/home/home.html",
+        areaTopTitle: "{{if .areaNode}}{{.areaNode.Name}}招标网{{end}}"
+    }
+</script>
+<script src='{{Cdn2}}/common-module/public/js/china-map-data.js?v={{Msg "version"}}'></script>
+<script src='/jyseo/mobile/js/common.js'></script>
+<script src='/jyseo/mobile/js/tag-common.js'></script>
+<script src='/jyseo/mobile/js/index.js'></script>
+
+</body>
+</html>
+

+ 2 - 2
resource/template/pc/components/seo-pagination.html

@@ -74,8 +74,8 @@
 
 </style>
 
-{{if .pagination}}
-<div class="seo-pagination">{{ParseHtml .pagination}}</div>
+{{if .pagination.PagingHtml}}
+<div class="seo-pagination">{{ParseHtml .pagination.PagingHtml}}</div>
 {{end}}
 
 <script src='{{Cdn}}/jyseo/js/seo-pagination.js?v={{Msg "version"}}'></script>

+ 12 - 0
utility/util.go

@@ -1,12 +1,15 @@
 package utility
 
 import (
+	"fmt"
 	"github.com/gogf/gf/v2/util/gconv"
 	"reflect"
+	"regexp"
 	"strconv"
 	"strings"
 )
 
+// ConversionMoney 金额格式化
 func ConversionMoney(i_money interface{}) string {
 	if i_money == nil {
 		return ""
@@ -41,3 +44,12 @@ func ConversionMoney(i_money interface{}) string {
 	}
 	return m
 }
+
+var mobileReg = regexp.MustCompile("(?i)(Android|Mobile|Phone)")
+
+func GetCommonRenderPatch(path, value string) string {
+	if mobileReg.MatchString(path) {
+		return fmt.Sprintf("mobile/%s", value)
+	}
+	return fmt.Sprintf("pc/%s", value)
+}