Explorar o código

Merge branch 'dev4.6.2.15' into dev4.6.3.2

luwenna %!s(int64=3) %!d(string=hai) anos
pai
achega
a5afef604b
Modificáronse 89 ficheiros con 7921 adicións e 303 borrados
  1. 2 3
      README.md
  2. 7 1
      config_formal/big_member_1_172.17.145.180/config.json
  3. 1 1
      config_formal/big_member_1_172.17.145.180/time.txt
  4. 7 1
      config_formal/bigmember_172.17.145.180/config.json
  5. 5 0
      config_formal/publicapply_172.17.148.50/bigmembermenu.json
  6. 8 0
      config_formal/publicapply_172.17.148.50/commonfunctions.json
  7. 1 1
      config_formal/publicapply_172.17.148.50/time.txt
  8. 1 1
      src/jfw/front/dataExport.go
  9. 17 9
      src/jfw/front/frontRouter.go
  10. 1 1
      src/jfw/front/ws_dataExport.go
  11. 1 1
      src/jfw/modules/app/src/app/front/ws_dataExport.go
  12. 0 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/css/j-big-icons.css
  13. 581 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/css/report_analysis.css
  14. BIN=BIN
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/buyer-open.png
  15. BIN=BIN
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/gold/dingzhi.png
  16. BIN=BIN
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/winner-open.png
  17. 185 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/lineChartScatter.js
  18. 104 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/marketAreaScatter.js
  19. 237 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/marketSegment.js
  20. 237 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/marketTimeScatter.js
  21. 105 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/marketTop3Table.js
  22. 161 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/marketUserScatter.js
  23. 198 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/projectScatter.js
  24. 80 34
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/ent_portrait.js
  25. 11 1
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/main_root_data.js
  26. 1795 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/report_analysis.js
  27. 222 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/report_analysis_history.js
  28. 26 3
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/unit_portrayal.js
  29. 32 10
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/utils.js
  30. 3 1
      src/jfw/modules/app/src/web/staticres/jyapp/js/historypush.js
  31. 22 5
      src/jfw/modules/app/src/web/staticres/jyapp/me/js/mine.js
  32. 0 0
      src/jfw/modules/app/src/web/templates/big-member/page_contrast.html
  33. 8 2
      src/jfw/modules/app/src/web/templates/big-member/page_ent_portrait.html
  34. 442 0
      src/jfw/modules/app/src/web/templates/big-member/page_report_analysis.html
  35. 49 0
      src/jfw/modules/app/src/web/templates/big-member/page_report_analysis_history.html
  36. 1 20
      src/jfw/modules/app/src/web/templates/big-member/page_set_area.html
  37. 18 12
      src/jfw/modules/app/src/web/templates/big-member/page_unit_portrayal.html
  38. 4 2
      src/jfw/modules/app/src/web/templates/weixin/historypush.html
  39. 51 5
      src/jfw/modules/app/src/web/templates/weixin/wxinfocontent.html
  40. 6 1
      src/jfw/modules/bigmember/src/config.json
  41. 7 0
      src/jfw/modules/bigmember/src/config/config.go
  42. 125 0
      src/jfw/modules/bigmember/src/entity/marketAnalysis/commonSearch.go
  43. 915 0
      src/jfw/modules/bigmember/src/entity/marketAnalysis/customizad_distribution.go
  44. 577 0
      src/jfw/modules/bigmember/src/entity/marketAnalysis/customized_analysis.go
  45. 322 0
      src/jfw/modules/bigmember/src/entity/marketAnalysis/marketAnalysisEntity.go
  46. 258 0
      src/jfw/modules/bigmember/src/entity/marketAnalysis/scaleRefineQuery.go
  47. 55 12
      src/jfw/modules/bigmember/src/entity/portrailUtil.go
  48. 1 1
      src/jfw/modules/bigmember/src/entity/portraitBuyerSearch.go
  49. 1 1
      src/jfw/modules/bigmember/src/entity/portraitWinnerSearch.go
  50. 1 1
      src/jfw/modules/bigmember/src/entity/portrait_screen.go
  51. 1 1
      src/jfw/modules/bigmember/src/service/analysis/decision.go
  52. 1 1
      src/jfw/modules/bigmember/src/service/init.go
  53. 127 0
      src/jfw/modules/bigmember/src/service/report/marketAnalysis.go
  54. 10 3
      src/jfw/modules/bigmember/src/service/use/use.go
  55. 2 2
      src/jfw/modules/bigmember/src/util/aggsSearchUtil.go
  56. 1 1
      src/jfw/modules/bigmember/src/util/util.go
  57. 40 9
      src/jfw/modules/common/src/qfw/util/dataexport/dataexport.go
  58. 1 1
      src/jfw/modules/common/src/qfw/util/dataexport/entdataexport.go
  59. 5 0
      src/jfw/modules/publicapply/src/userbase/bigmembermenu.json
  60. 8 0
      src/jfw/modules/publicapply/src/userbase/commonfunctions.json
  61. 1 1
      src/jfw/modules/publicapply/src/userbase/entity/entity.go
  62. 2 2
      src/jfw/modules/subscribepay/src/service/dataExportPay.go
  63. 6 3
      src/jfw/modules/subscribepay/src/service/dataexportPack.go
  64. BIN=BIN
      src/web/staticres/big-member/image/buyer-open.png
  65. BIN=BIN
      src/web/staticres/big-member/image/winner-open.png
  66. 25 0
      src/web/staticres/big-member/js/meauContact.js
  67. 26 2
      src/web/staticres/big-member/js/unit_portrayal.js
  68. 18 2
      src/web/staticres/common-module/collection/css/index.css
  69. 35 23
      src/web/staticres/common-module/collection/js/area-city-mobile.js
  70. 0 1
      src/web/staticres/common-module/collection/js/cate-mobile.js
  71. 74 37
      src/web/staticres/common-module/collection/js/date-mobile.js
  72. 77 31
      src/web/staticres/common-module/collection/js/ent_portrait.js
  73. 35 0
      src/web/staticres/common-module/collection/js/industry-mobile.js
  74. 85 17
      src/web/staticres/common-module/collection/js/keyword-mobile.js
  75. 1 1
      src/web/staticres/common-module/collection/js/vip-dialog.js
  76. 87 0
      src/web/staticres/common-module/diy-report/css/report-list.css
  77. 219 0
      src/web/staticres/common-module/diy-report/js/report-list.js
  78. BIN=BIN
      src/web/staticres/commonFunctions/analysis_report.png
  79. 12 0
      src/web/staticres/css/dev2/newBidSearch.css
  80. 2 2
      src/web/staticres/js/ent-search-index-pc.js
  81. 10 4
      src/web/staticres/js/login.js
  82. 20 2
      src/web/staticres/me/js/mine.js
  83. 3 1
      src/web/staticres/vipsubscribe/js/historypush.js
  84. 0 0
      src/web/templates/big-member/wx/page_index.html
  85. 12 6
      src/web/templates/big-member/wx/page_unit_portrayal.html
  86. 9 3
      src/web/templates/frontRouter/wx/collection/sess/ent_portrait.html
  87. 15 4
      src/web/templates/pc/biddetail_rec.html
  88. 3 3
      src/web/templates/pc/subscribe_new.html
  89. 57 10
      src/web/templates/weixin/wxinfocontent_rec.html

+ 2 - 3
README.md

@@ -4,6 +4,5 @@ v4.6.3.2
 微信和pc端功能
 weixin sdk https://github.com/wizjin/weixin
 web用xweb框架
-v4.6.2.17
-附件下载包
-
+v4.6.2.15
+定制化市场分析报告

+ 7 - 1
config_formal/big_member_1_172.17.145.180/config.json

@@ -64,5 +64,11 @@
     "mainWebDomain": "https://www.jianyu360.cn",
     "createPdfServer": "http://10.170.187.34:8081/api/to-pdf/%s?delay=300&dir=%s&url=https://www.jianyu360.cn/swordfish/frontPage/report/free/report?pid=%s",
     "pdfDataApiWhiteList": ["123.56.103.12","1.192.61.183","1.192.61.146"],
-    "pdfServerPoor" : 5
+    "pdfServerPoor" : 5,
+    "marketAnalysisPool": {
+	  "limit": 3,
+	  "timeOut": 20,
+	  "projectNumLimit": 600000
+	}
+
 }

+ 1 - 1
config_formal/big_member_1_172.17.145.180/time.txt

@@ -1,2 +1,2 @@
 #上次修改时间,比当前修改时间小就行
-2021-12-30 16:15:12
+2022-1-14 9:00:00

+ 7 - 1
config_formal/bigmember_172.17.145.180/config.json

@@ -64,5 +64,11 @@
     "mainWebDomain": "https://www.jianyu360.cn",
     "createPdfServer": "http://172.17.145.176:8079/api/to-pdf/%s?delay=300&dir=%s&url=https://www.jianyu360.cn/swordfish/frontPage/report/free/report?pid=%s",
     "pdfDataApiWhiteList": ["123.56.103.12","1.192.61.183","1.192.61.146","39.107.83.53"],
-    "pdfServerPoor" : 5
+    "pdfServerPoor" : 5,
+    "marketAnalysisPool": {
+	  "limit": 3,
+	  "timeOut": 20,
+          "projectNumLimit": 600000
+	}
+
 }

+ 5 - 0
config_formal/publicapply_172.17.148.50/bigmembermenu.json

@@ -91,6 +91,11 @@
 				"name":"月报",
 				"url":"/swordfish/page_big_pc/bigvip_subreport_month",
 				"isusable":false
+			},
+			{
+				   "name":"定制化分析报告",
+				   "url":"/swordfish/page_big_pc/desktop/report_analysis",
+				   "isusable":false
 			}
 		]
 	},

+ 8 - 0
config_formal/publicapply_172.17.148.50/commonfunctions.json

@@ -135,6 +135,14 @@
 				"img":"/commonFunctions/pc_subreport_week.png"
 			}
 		},
+		{
+			   "name":"定制化分析报告",
+			   "charge":true,
+			   "pc":{
+			      "url":"/swordfish/page_big_pc/desktop/report_analysis",
+			      "img":"/commonFunctions/analysis_report.png"
+			   }
+		},
 		{
 			"name":"月报",
 			"charge":true,

+ 1 - 1
config_formal/publicapply_172.17.148.50/time.txt

@@ -1,2 +1,2 @@
 #上次修改时间,比当前修改时间小就行
-2021-12-30 16:15:12
+2022-1-14 9:00:00

+ 1 - 1
src/jfw/front/dataExport.go

@@ -391,7 +391,7 @@ func (d *DataExport) ToCreateOrderPage(_id string) error {
 	} else {
 		d.DelSession("Structed")
 	}
-	msgCount := dataexport.GetDataExportSearchCountByScdId(public.MQFW, public.DbConf.Elasticsearch.Main.Address, id)
+	msgCount := dataexport.GetDataExportSearchCountByScdId(public.MQFW, public.Mgo_Bidding, public.DbConf.Mongodb.Bidding.DbName, public.DbConf.Elasticsearch.Main.Address, id)
 	if msgCount > public.ExConf.MsgMaxCount || msgCount == -1 {
 		msgCount = public.ExConf.MsgMaxCount
 	}

+ 17 - 9
src/jfw/front/frontRouter.go

@@ -5,7 +5,6 @@ import (
 	"jfw/config"
 	"jfw/public"
 	"jfw/wx"
-	"log"
 	"qfw/util/jy"
 	"regexp"
 	"strings"
@@ -156,15 +155,17 @@ func (this *CommonRouter) doEntpcPage() error {
 
 //大会员
 func (this *CommonRouter) BigpcIndex() error {
-	return this.doPcBigPage("")
+	return this.doPcBigPage("", "")
 }
 func (this *CommonRouter) BigpcPage(htmlPage string) error {
-	return this.doPcBigPage(htmlPage)
+	types := this.GetString("type")
+	return this.doPcBigPage(htmlPage, types)
 }
 
 var bigVipFreePageReg = regexp.MustCompile(`set_.*|free|unit_portrayal|analysis_(search|result)|pro_follow_detail`)
 
-func (this *CommonRouter) doPcBigPage(pageSign string) error {
+func (this *CommonRouter) doPcBigPage(pageSign, types string) error {
+	page := pageSign
 	userid, _ := this.GetSession("userId").(string)
 	//没有登录跳转登录页面
 	if userid == "" {
@@ -172,12 +173,15 @@ func (this *CommonRouter) doPcBigPage(pageSign string) error {
 	}
 	//没有购买大会员跳转大会员介绍页
 	if !strings.HasPrefix(pageSign, "svip/ent_ser_portrait") {
-		if array := strings.Split(pageSign, "/"); len(array) > 0 {
-			pageSign = array[0]
+		for _, v := range strings.Split(pageSign, "/") {
+			if v == "" || v == "desktop" {
+				continue
+			}
+			pageSign = v
+			break
 		}
-		log.Println(bigVipFreePageReg.MatchString(pageSign), pageSign)
-		if !bigVipFreePageReg.MatchString(pageSign) {
-			bigBaseMsg := jy.GetBigVipUserBaseMsg(userid, public.Mysql, public.MQFW)
+		bigBaseMsg := jy.GetBigVipUserBaseMsg(userid, public.Mysql, public.MQFW)
+		if !bigVipFreePageReg.MatchString(pageSign) && pageSign != "index" {
 			if bigBaseMsg.Status <= 0 && bigBaseMsg.Vip_BuySet.Upgrade != 1 {
 				return this.Redirect("/big/page/index")
 			}
@@ -186,6 +190,10 @@ func (this *CommonRouter) doPcBigPage(pageSign string) error {
 				return this.Redirect("/big/page/index")
 			}
 		}
+		//限制超级订阅用户不能进入购买页
+		if page == "free/svip/buy" && bigBaseMsg.VipStatus > 0 && types != "upgrade" {
+			return this.Redirect("/front/subscribe.html")
+		}
 	}
 	return this.Render(fmt.Sprintf("/frontRouter/pc/page_big_pc/sess/index.html"))
 }

+ 1 - 1
src/jfw/front/ws_dataExport.go

@@ -291,7 +291,7 @@ func (w *WsDataExport) SubmitOrder() error {
 			return errors.New("未登录")
 		}
 	}
-	msgCount := dataexport.GetDataExportSearchCountByScdId(public.MQFW, public.DbConf.Elasticsearch.Main.Address, id)
+	msgCount := dataexport.GetDataExportSearchCountByScdId(public.MQFW, public.Mgo_Bidding, public.DbConf.Mongodb.Bidding.DbName, public.DbConf.Elasticsearch.Main.Address, id)
 	if msgCount > public.ExConf.MsgMaxCount || msgCount == -1 {
 		msgCount = public.ExConf.MsgMaxCount
 	}

+ 1 - 1
src/jfw/modules/app/src/app/front/ws_dataExport.go

@@ -258,7 +258,7 @@ func (w *WsDataExport) ToCreateOrderPage() error {
 		return errors.New("未登录")
 	}
 	log.Println(id)
-	msgCount := dataexport.GetDataExportSearchCountByScdId(public.MQFW, public.DbConf.Elasticsearch.Main.Address, id)
+	msgCount := dataexport.GetDataExportSearchCountByScdId(public.MQFW, public.Mgo_Bidding, public.DbConf.Mongodb.Bidding.DbName, public.DbConf.Elasticsearch.Main.Address, id)
 	if msgCount > public.ExConf.MsgMaxCount || msgCount == -1 {
 		msgCount = public.ExConf.MsgMaxCount
 	}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/css/j-big-icons.css


+ 581 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/css/report_analysis.css

@@ -0,0 +1,581 @@
+.order-list-container .van-tabs__wrap {
+  height: .96rem;
+}
+.order-list-container .van-tabs__line {
+  bottom: .36rem;
+}
+.order-list-container .van-tab__pane {
+  height: 100%;
+}
+.order-list-container .van-tabs__content {
+  flex: 1;
+  overflow-y: scroll;
+  overflow-x: hidden;
+}
+.order-list-container .van-tabs {
+  width: 100%;
+}
+.order-list-container .van-tab {
+  font-size: .32rem;
+  line-height: .4rem;
+}
+
+/* vant-reset */
+.van-dialog {
+  width: 6rem;
+  border-radius: .16rem;
+}
+.van-dialog__header {
+  font-weight: 700;
+  font-size: 18px;
+  line-height: 26px;
+  color: #171826;
+}
+.van-dialog__content {
+  padding: .16rem .6rem;
+}
+.van-dialog__message {
+  padding-left: 0;
+  padding-right: 0;
+  font-size: .3rem;
+  line-height: .44rem;
+  color: #5F5E64;
+}
+.van-dialog .van-button {
+  font-size: 18px;
+  line-height: 26px;
+}
+
+.van-dialog  .van-button--default {
+  color: #171826;
+}
+
+.van-toast {
+  max-width: 4.2rem;
+  line-height: 1.6;
+}
+
+/* vant-custom */
+.j-confirm-dialog {
+  border-radius: 8px;
+}
+.j-confirm-dialog .van-dialog__message {
+  font-size: .32rem;
+  color: #171826;
+  line-height: .48rem;
+  text-align: left;
+}
+.j-confirm-dialog.text-center .van-dialog__message {
+  text-align: center;
+}
+.j-confirm-dialog .van-button {
+  font-size: .36rem;
+  color: #171826;
+  line-height: .52rem;
+}
+
+/* j-tag */
+.j-tag {
+  white-space: nowrap;
+}
+.j-tag.tag-orange {
+  color: #FF9F3F;
+  background-color: rgba(255, 159, 63, 0.1);
+  border-color: rgba(255, 159, 63, 0.1);
+}
+.j-tag.tag-blue {
+  color: #05A6F3;
+  background-color: rgba(5, 166, 243, 0.1);
+  border-color: rgba(5, 166, 243, 0.1);
+}
+.j-tag.tag-plain {
+  color: #5E5E64;
+  background-color: #F7F9F9;
+  border-color: rgba(0, 0, 0, 0.05);
+}
+
+/* empty */
+.empty-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  flex: 1;
+  height: 80%;
+  padding: .32rem;
+  box-sizing: border-box;
+  background-color: rgba(245, 244, 249, 1);
+}
+.empty-container {
+  min-height: 7rem;
+}
+.empty-main,
+.empty-content-position {
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.empty-content-position {
+  margin-top: -1rem;
+}
+
+.empty-container .tip-text {
+  margin-top: .2rem;
+  color: #5F5E64;
+  font-size: .28rem;
+  line-height: .4rem;
+  text-align: center;
+}
+
+.empty-container .tip-sub-text {
+  color: #9B9CA3;
+  font-size: .26rem;
+  line-height: .4rem;
+  margin-top: .12rem;
+  text-align: center;
+}
+
+.empty-container .image {
+  width: 4rem;
+  height: 4rem;
+}
+.empty-container .image > img {
+  width: 100%;
+  height: 100%;
+}
+
+/* common-css */
+.j-container .van-tabs__wrap {
+  height: 0.96rem;
+}
+.van-tab {
+  font-size: .32rem;
+  line-height: .4rem;
+}
+
+/* analysis-page */
+.pd-16 {
+  padding: .32rem;
+}
+.pd-lr16 {
+  padding: 0 .32rem;
+}
+.height8 {
+  height: .16rem;
+  width: 100%;
+  color: transparent;
+  background-color: transparent;
+}
+
+.filters-title {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: .24rem .32rem;
+  color: #161826;
+  line-height: .6rem;
+  font-size: .4rem;
+  font-weight: 700;
+}
+.filters-list {
+  margin-bottom: .16rem;
+  border-top: 1px solid transparent;
+}
+.filters-list .van-cell {
+  height: 1.08rem;
+}
+.date-cell .cell-title,
+.filters-list .van-cell__title {
+  color: #161826;
+  line-height: .48rem;
+  font-size: .28rem;
+}
+.keys-popup .popup-header {
+  padding-top: .24rem;
+  padding-bottom: .24rem;
+  height: auto;
+  flex-direction: column;
+  align-items: flex-start;
+}
+.keys-popup .header-top {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.keys-popup .header-title {
+  margin-right: .2rem;
+}
+.keys-popup .header-action {
+  padding: 0 .32rem;
+  font-size: .26rem;
+  line-height: .42rem;
+  color: #2ABDD1;
+  background: rgba(42, 189, 209, 0.1);
+  border-radius: .24rem;
+  border: 1px solid #2ABDD1;
+}
+
+.keys-popup .header-bottom {
+  margin-top: .1rem;
+  color: #2ABDD1;
+  font-size: .22rem;
+  line-height: .26rem;
+}
+
+.date-cell {
+  padding: 10px 0;
+}
+.date-cell .cell-title {
+  padding: 0 16px;
+}
+
+.filters-list .collection .dateTags .customTime {
+  display: none;
+}
+.filters-list .collection .dateTags .timeTag {
+  flex-wrap: wrap;
+}
+.collection .dateTags {
+  height: unset;
+}
+.collection .timePicker.clickactive {
+  background-color: #fff;
+}
+.collection .timePicker.clickactive::after {
+  content: unset;
+}
+.collection .timePicker.clickactive .van-cell.van-field {
+  border-color: #2abed1;
+}
+.collection .timeTag .area-card-item {
+  width: unset;
+  height: unset;
+  padding: 0 .16rem;
+}
+.date-cell > .j-container > .j-footer {
+  display: none;
+}
+
+.search-result {
+  position: relative;
+}
+.search-result .filters-list .van-cell__title {
+  color: #161826;
+  font-size: .4rem;
+}
+.search-result .section:not(:first-of-type) {
+  position: relative;
+  margin-top: .16rem;
+}
+.search-result .section-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.search-result .section .section-title {
+  color: #161826;
+  line-height: .52rem;
+  font-size: .36rem;
+}
+.search-result .section:not(:first-of-type) .section-content {
+  margin: .16rem 0;
+  padding: .12rem 0;
+}
+
+.fixed-bottom-right {
+  position: absolute;
+  bottom: 15%;
+  right: .32rem;
+}
+.scroll-to-top {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: .8rem;
+  height: .8rem;
+  font-size: .4rem;
+  border-radius: 50%;
+  background-color: #fff;
+  box-shadow: rgb(54,147,79,20%) 0 0 30px 5px;
+}
+
+.section-sticky {
+  width: 100%;
+}
+.van-sticky {
+  padding: 0 .32rem;
+  width: 100%;
+  background-color: #fff;
+}
+
+.section .section-tip-text {
+  font-size: .22rem;
+  line-height: .3rem;
+  color: #9B9BA3;
+  text-align: center;
+}
+
+.search-result .dimension {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  min-height: 2.5rem;
+}
+
+.search-result .dimension .section-content {
+  padding: .28rem 0;
+}
+.van-sticky--fixed {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  min-height: 1.32rem;
+  background-color: #fff;
+}
+.van-sticky--fixed .dimension-list {
+  padding: 0!important;
+}
+.search-result .dimension > div {
+  width: 100%;
+}
+.search-result .dimension .section-title {
+  font-size: .28rem;
+  line-height: .28rem;
+  padding: .32rem;
+  padding-bottom: 0;
+  text-align: center;
+}
+.search-result .dimension .section-tip-text {
+  padding-bottom: .32rem;
+}
+
+
+.search-result .dimension-list {
+  display: flex;
+  align-items: center;
+  width: 100%;
+}
+.search-result .dimension-item {
+  display: flex;
+  flex: 1;
+  font-size: .28rem;
+  line-height: .4rem;
+}
+.search-result .dimension-item:not(:last-of-type) {
+  margin-right: .32rem;
+}
+.search-result .dimension-item::after {
+  content: unset;
+}
+
+.market-overview-list {
+  display: flex;
+  margin: 0!important;
+  padding-left: .08rem!important;
+  padding-right: .08rem!important;
+}
+.market-overview-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: space-between;
+  flex: 1;
+  padding: 0 .08rem;
+}
+.market-overview-item:not(:last-of-type) {
+  border-right: 1px solid #F2F2F2;
+}
+
+.m-overview-name {
+  margin-bottom: .08rem;
+  white-space: nowrap;
+}
+.m-overview-name,
+.m-overview-unit,
+.m-overview-type {
+  font-size: .22rem;
+  line-height: .28rem;
+  color: #5E5E64;
+  text-align: center;
+}
+.m-overview-count {
+  margin: .12rem 0;
+}
+.m-overview-ratio {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-top: .08rem;
+  height: .32rem;
+  padding: 0 .08rem;
+  border-radius: .2rem;
+}
+.m-overview-ratio.red {
+  color: #FA483C;
+  background-color: #FFEDEC;
+}
+.m-overview-ratio.green {
+  color: #04B15E;
+  background-color: #EAF8E5;
+}
+.m-overview-ratio .icon-reverse {
+  transform: rotate(180deg);
+}
+
+/* 表格首页索引 */
+.table-index-rect {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin: 0 auto;
+  width: .4rem;
+  height: .4rem;
+  color: #fff;
+  font-size: .28rem;
+  border-radius: 3px;
+  background-color: #C0C4CC;
+}
+.table-index-rect.red {
+  background-color: #FF3A20;
+}
+.table-index-rect.orange {
+  background-color: #FF9F3F;
+}
+.table-index-rect.soft-orange {
+  background-color: #EED08C;
+}
+
+/* TOP10 */
+.project-top-item {
+  padding: .32rem 0;
+}
+.project-top-item:first-of-type {
+  padding-top: .16rem;
+}
+.project-top-item:last-of-type {
+  padding-bottom: .16rem;
+}
+.project-top-item:not(:last-of-type) {
+  border-bottom: 1px solid rgba(0, 0, 0, 0.03);
+}
+.project-top-item .p-t-i-hd {
+  display: flex;
+  justify-content: space-between;
+}
+.project-top-item .p-t-i-hd .p-t-i-hd-r {
+  display: flex;
+  flex-direction: column;
+  flex: 1;
+  margin-left: .16rem;
+}
+.project-top-item .p-t-i-hd .p-t-i-hd-r-top {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+}
+.project-top-item .p-t-i-hd-r .project-actions {
+  display: flex;
+  align-items: center;
+  color: #2ABDD1;
+  line-height: .36rem;
+  font-size: .24rem;
+  white-space: nowrap;
+}
+.project-top-item .p-t-i-hd-r .project-actions .van-icon {
+  margin-left: .12rem;
+}
+.project-top-item .p-t-i-hd-r .project-actions.icon-reverse .van-icon {
+  transform: rotate(180deg);
+}
+.project-top-item .p-t-i-hd-r .project-info {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.market-top3-table .project-name {
+  max-width: 4rem;
+}
+.project-top-item .p-t-i-hd-r .project-name {
+  font-size: .28rem;
+  color: #1D1D1D;
+  line-height: .48rem;
+  flex: 1;
+}
+.project-top-item .p-t-i-hd-r .project-tags {
+  display: flex;
+  align-items: center;
+}
+.project-top-item .p-t-i-hd-r .project-right {
+  color: #5E5E64;
+}
+.project-top-item .j-tag {
+  margin-right: .08rem;
+}
+.project-top-item .p-t-i-ft {
+  margin-top: .24rem;
+  padding: .16rem;
+  background: linear-gradient(180deg, rgba(108, 217, 236, 0.3) 0%, rgba(255, 255, 255, 0) 100%);
+  border-radius: 6px;
+}
+.project-top-item .p-t-i-ft .p-t-i-ft-top {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.project-top-item .p-t-i-ft .p-t-i-ft-bottom {
+  display: flex;
+  align-items: center;
+  font-size: .24rem;
+  color: #5E5E64;
+  line-height: .36rem;
+}
+.project-top-item .p-t-i-ft .p-t-i-ft-sub {
+  margin-right: .24rem;
+}
+.project-top-item .p-t-i-ft .p-t-i-ft-title {
+  font-size: .26rem;
+  color: #161826;
+  line-height: .36rem;
+}
+.project-top-item .p-t-i-ft .p-t-i-ft-winner {
+  font-size: .24rem;
+  color: #5E5E64;
+  line-height: .36rem;
+}
+.project-top-item .p-t-i-ft.disabled,
+.project-top-item .p-t-i-hd-r .project-name.disabled,
+.project-top-item .p-t-i-ft .p-t-i-ft-winner.disabled {
+  color: #a2a2a2;
+  cursor: not-allowed;
+}
+
+/* time scatter */
+.time-scatter .section-actions {
+  display: flex;
+  align-items: center;
+}
+.time-scatter .action-button {
+  position: relative;
+  margin-left: .36rem;
+  font-size: .26rem;
+  color: #5E5E64;
+  line-height: .28rem;
+}
+.time-scatter .action-button.active {
+  color: #2ABDD1;
+}
+.time-scatter .action-button.active::after {
+  content: '';
+  position: absolute;
+  bottom: -8px;
+  left: 50%;
+  width: 80%;
+  height: .04rem;
+  transform: translateX(-50%);
+  background-color: #2ABDD1;
+}

BIN=BIN
src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/buyer-open.png


BIN=BIN
src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/gold/dingzhi.png


BIN=BIN
src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/winner-open.png


+ 185 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/lineChartScatter.js

@@ -0,0 +1,185 @@
+var lineChartScatterTemplate = `
+<ve-line :data="chartData" :height="options.height" :after-config="options.config" :extend="defaultOption"></ve-line>
+`
+
+var lineChartScatter = {
+  name: 'line-chart-scatter',
+  template: lineChartScatterTemplate,
+  props: {
+    chartData: {
+      type: Object,
+      default () {
+        return {
+          columns: ['金额区间', '采购总金额占比', '采购单位数量占比'],
+          rows: [
+            // {
+            //   金额区间: '>=1亿',
+            //   采购总金额占比: 2,
+            //   采购单位数量占比: 222
+            // },
+            // {
+            //   金额区间: '1000万-1亿',
+            //   采购总金额占比: 322,
+            //   采购单位数量占比: 2222
+            // },
+            // {
+            //   金额区间: '500万-1000万',
+            //   采购总金额占比: 1,
+            //   采购单位数量占比: 111
+            // }
+          ]
+        }
+      }
+    },
+  },
+  data:function () {
+    return {
+      options: {
+        height: '326px',
+        config: this.configOptions
+      },
+      defaultOption: {
+        color: ['#05A6F3', '#FF9F40'],
+        xAxis: {
+          axisLabel: {
+            textStyle: {
+              color: '#626262',
+              fontSize: 10
+            },
+            formatter: this.xAxisFormatter,
+            interval: 0
+          }
+        },
+        grid: {
+          top: 10,
+          left: 12,
+          right: 12
+        },
+        yAxis: {
+          splitLine: {
+            lineStyle: {
+              type: 'dashed',
+              width: 0.5
+            }
+          },
+          nameGap: 15,
+          nameTextStyle: {
+            fontSize: 12,
+            align: 'left',
+            color: '#9B9CA3',
+            padding: [0, 0, 0, -30]
+          },
+          axisLabel: {
+            margin: 2,
+            fontSize: 12,
+            color: '#5F5E64',
+            interval: 'auto',
+            formatter: p => p + '%'
+          }
+        },
+        legend: {
+          orient: 'horizontal',
+          icon: 'circle',
+          bottom: 10,
+          itemWidth: 8,
+          itemHeight: 8,
+          itemGap: 40,
+          textStyle: {
+            color: '#5F5E64',
+            fontSize: 12
+          }
+        },
+        series: {
+          type: 'line',
+          showSymbol: false,
+          smooth: false,
+          symbol: 'circle',
+          symbolSize: 3,
+          itemStyle: {
+            borderColor: '#fff',
+            borderWidth: 1
+          }
+        },
+        tooltip: {
+          backgroundColor: '#fff',
+          confine: true,
+          axisPointer: {
+            type: 'line',
+            lineStyle: {
+              width: 2,
+              color: '#FA483C'
+            },
+            z: 3
+          },
+          textStyle: {
+            color: '#171826',
+            fontSize: 12
+          },
+          padding: [7, 12],
+          extraCssText: 'box-shadow: 0px 4px 16px rgba(8, 31, 38, 0.08)',
+          borderWidth: 2,
+          borderColor: '#F5F6F7'
+        },
+        lineStyle: {
+          width: 0.5
+        }
+      }
+    }
+  },
+  computed: {},
+  created () {},
+  methods: {
+    xAxisFormatter (params) {
+      var arr = params.split('-')
+      if (arr.length === 2) {
+        return arr.join('\n-')
+      } else {
+        return params
+      }
+    },
+    configOptions (options) {
+      // 面积颜色-渐变
+      Object.assign(options.series[0], {
+        areaStyle: {
+          normal: {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+              {
+                offset: 0,
+                color: 'rgba(42, 190, 209, 0.5)'
+              },
+              {
+                offset: 1,
+                color: 'rgba(42, 190, 209, 0)'
+              }
+            ], false)
+          }
+        }
+      })
+      Object.assign(options.series[1], {
+        areaStyle: {
+          normal: {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+              {
+                offset: 0,
+                color: 'rgba(255, 159, 63, 0.5)'
+              },
+              {
+                offset: 1,
+                color: 'rgba(255, 159, 63, 0)'
+              }
+            ], false)
+          }
+        }
+      })
+      options.tooltip.formatter = params => {
+        let tip = `<div style="padding-top:2px;color:#9B9CA3;">${params[0].name}</div>`
+        for (let i = 0; i < params.length; i++) {
+          params[i].marker = '<span style="display:inline-block;margin-right:5px;border-radius:8px;width:8px;height:8px;background-color:' + params[i].color + ';"></span>'
+          tip += params[i].marker + params[i].seriesName + ':' + params[i].value[1].toString().replace(/,/, '') + '%' + '<br/>'
+        }
+        return tip
+      }
+      return options
+    }
+  }
+}

+ 104 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/marketAreaScatter.js

@@ -0,0 +1,104 @@
+var marketAreaScatterTemplate = `
+  <div class="market-area-scatter-chart">
+    <ve-map
+      :height="options.height"
+      :init-options="initRendererSvg"
+      :after-config="options.config"
+      :data="chartData"
+      :settings="defaultSettings"
+      :extend="defaultOptions">
+    </ve-map>
+  </div>
+`
+var marketAreaScatter = {
+  name: 'market-area-scatter',
+  template: marketAreaScatterTemplate,
+  props: {
+    chartData: {
+      type: Object,
+      default () {
+        return {
+          columns: ['项目所在地', '项目数量', '中标金额'],
+          rows: [
+            // {
+            //   项目所在地: '河南',
+            //   项目数量: 2,
+            //   中标金额: 2222
+            // },
+            // {
+            //   项目所在地: '北京',
+            //   项目数量: 22,
+            //   中标金额: 565666
+            // },
+            // {
+            //   项目所在地: '浙江',
+            //   项目数量: 22,
+            //   中标金额: 765666
+            // }
+          ]
+        }
+      }
+    },
+  },
+  data:function () {
+    return {
+      options: {
+        height: '300px',
+        colors: ['#05a6f3'],
+        config: this.configArea
+      },
+      initRendererSvg: {
+        renderer: 'svg'
+      },
+      // 引用/jyapp/big-member/js/echarts_option.js中配置文件
+      defaultSettings: mapSettings.chartSettings,
+      defaultOptions: mapSettings.chartExtend
+    }
+  },
+  computed: {},
+  created () {},
+  methods: {
+    extend (chart) {
+      chart.setOption({
+        series: [{
+          type: 'bar',
+          barWidth: 20
+        }, {
+          type: 'line',
+          smooth: false,
+          symbol: 'none'
+        }]
+      })
+    },
+    configArea (options) {
+      const arr = this.chartData.rows || []
+      const maxNum = Math.max.apply(Math, arr.map((o) => { return o['项目数量'] }))
+      options.visualMap.min = 1
+      options.visualMap.max = maxNum < 100 ? 100 : maxNum
+      options.graphic[0].children[0].style.text = '项目数量(个)'
+      options.graphic[options.graphic.length - 1].children[0].style.text = maxNum > 100 ? maxNum : 100
+      options.graphic[options.graphic.length - 1].children[1].style.text = 1
+      options.tooltip.formatter = params => {
+        const obj = {}
+        let tip = ''
+        arr.forEach((v) => {
+          if (v['项目所在地'] === params.name) {
+            for (const key in v) {
+              obj[key] = v[key]
+            }
+          }
+        })
+        if (Object.keys(obj).length > 0) {
+          const regArea = '<span style="color: #999">' + obj['项目所在地'] + '</span></br>'
+          const count = '<span>项目数量:' + obj['项目数量'] + '个</span></br>'
+          const scale = '<span>项目金额:' + obj['项目金额'] + '万元</span></br>'
+          tip = regArea + count + scale
+        } else {
+          tip = ''
+        }
+        return tip
+      }
+      return options
+    }
+  }
+}

+ 237 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/marketSegment.js

@@ -0,0 +1,237 @@
+var marketSegmentTemplate = `
+<ve-histogram
+  :id="id"
+  :height="options.height"
+  :width="options.width ? options.width : null"
+  :colors="options.colors"
+  :data="chartData"
+  :settings="options.settings"
+  :after-config="options.config"
+  :after-set-option="extend"
+  :extend="defaultOptions"
+></ve-histogram>
+`
+
+var marketSegment = {
+  name: 'market-segment',
+  template: marketSegmentTemplate,
+  props: {
+    id: String,
+    type: {
+      type: String,
+      default: 'count' // count/amount
+    },
+    chartData: {
+      type: Object,
+      default () {
+        return {
+          columns: ['行业', '项目金额'],
+          rows: [
+            // {
+            //   行业: '6月2',
+            //   项目金额: 2
+            // },
+            // {
+            //   行业: '6月3',
+            //   项目金额: 3
+            // },
+            // {
+            //   行业: '6月4',
+            //   项目金额: 4
+            // },
+            // {
+            //   行业: '6月4',
+            //   项目金额: 0
+            // },
+            // {
+            //   行业: '6月5',
+            //   项目金额: 5
+            // }
+          ]
+        }
+      }
+    },
+  },
+  data: function () {
+    const color = this.type === 'count' ? '#05A6F3' : '#FF9F3F'
+    return {
+      options: {
+        height: '320px',
+        colors: [color],
+        config: this.config(this.type)
+      },
+      defaultOptions: {
+        grid: {
+          top: 20
+        },
+        xAxis: {
+          axisLabel: {
+            margin: 10,
+            interval: 0, // 强制显示x轴所有刻度
+            fontSize: 10
+          },
+          nameLocation: 'start',
+          nameTextStyle: {
+            fontSize: 12,
+            align: 'left',
+            padding: [70, 0, 0, 50],
+            color: '#9B9CA3'
+          }
+        },
+        yAxis (item) {
+          item[0].splitLine = {
+            lineStyle: {
+              type: 'dashed',
+              width: 0.5
+            }
+          }
+          item[0].axisLabel = {
+            margin: 2,
+            fontSize: 12
+          }
+          item[1].splitLine = {
+            show: false
+          }
+          item[1].axisLabel = {
+            show: false,
+            fontSize: 12
+          }
+          item[0].axisLabel.formatter = (value, index) => {
+            return value.toString().replace(/,/, '')
+          }
+          item[1].axisLabel.formatter = (value, index) => {
+            return value.toString().replace(/,/, '')
+          }
+          return item
+        },
+        tooltip: {
+          trigger: 'axis',
+          confine: true,
+          backgroundColor: '#fff',
+          axisPointer: {
+            type: 'shadow',
+            shadowStyle: {
+              color: 'rgba(42, 190, 209,0.1)'
+            },
+            z: 3
+          },
+          textStyle: {
+            color: '#171826',
+            fontSize: 12
+          },
+          padding: [7, 12],
+          extraCssText: 'box-shadow: 0px 4px 16px rgba(8, 31, 38, 0.08);transform: translate3d(0,0,0)'
+        },
+        legend: {
+          orient: 'horizontal',
+          icon: 'circle',
+          bottom: 0,
+          align: 'left',
+          itemWidth: 8,
+          itemHeight: 8,
+          itemGap: 20,
+          textStyle: {
+            fontSize: 12,
+            rich: {
+              a: {
+                fontSize: 16,
+                verticalAlign: 'top',
+                align: 'center',
+                padding: [0, 15, 28, 0]
+              },
+              b: {
+                fontSize: 14,
+                align: 'center',
+                padding: [0, 15, 0, 0],
+                lineHeight: 25
+              }
+            }
+          },
+          formatter: (name) => {
+            if (name === '企业数量') {
+              name = name + '(个)'
+            }
+            return name
+          }
+        }
+      }
+    }
+  },
+  computed: {},
+  created () {
+    // console.log(this.chartData)
+  },
+  methods: {
+    extend (chart) {
+      chart.setOption({
+        series: [{
+          type: 'bar',
+          barMaxWidth: 40
+        }, {
+          type: 'line',
+          smooth: false,
+          symbol: 'none'
+        }]
+      })
+    },
+    config (type) {
+      return options => {
+        const suffix = type === 'count' ? '个' : '万元'
+        options.xAxis[0].axisLabel.rotate = 60
+        options.xAxis[0].axisLabel.formatter = name => {
+          if (name && name.length > 4) {
+            return `${name.slice(0, 4)}...`
+          } else {
+            return name
+          }
+        }
+
+        if (this.chartData.rows.length > 8) {
+          // 设置时间轴
+          Object.assign(options, {
+            // grid解决dataZoom文字被隐藏的问题
+            // https://github.com/apache/echarts/issues/11601
+            grid: {
+              left: '5%',
+              right: '13%'
+            },
+            dataZoom: {
+              show: true, // 显示滚动条
+              realtime: true, // 拖动时,是否实时更新系列的视图
+              type: 'slider',
+              height: 20,
+              bottom: 0,
+              textStyle: {
+                fontSize: 10
+              }
+            }
+          })
+        }
+
+        options.legend.bottom = 30
+        options.legend.formatter = name => {
+          return `${name}(${suffix})`
+        }
+
+        options.legend.data = [
+          { icon: 'rect', name: this.chartData.columns[1] }
+        ]
+
+        options.tooltip.axisPointer.shadowStyle.color = 'rgba(5,166,243,0.1)'
+        options.tooltip.formatter = params => {
+          let tip = `<div style="padding-top:2px;color:#9B9CA3;">${params[0].name}</div>`
+          for (let i = 0; i < params.length; i++) {
+            if (params[i].value === undefined) {
+              params[i].value = 0
+            }
+            if (i === 0) {
+              tip = tip + params[i].marker + params[i].seriesName + ':' + params[i].value + suffix + '<br/>'
+            }
+          }
+          return tip
+        }
+        return options
+      }
+    }
+  }
+}

+ 237 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/marketTimeScatter.js

@@ -0,0 +1,237 @@
+var marketTimeScatterTemplate = `
+  <div class="market-time-scatter">
+    <ve-histogram
+      id="bar-line-histogram-chart"
+      :init-options="initRendererSvg"
+      :height="options.height"
+      :width="options.width ? options.width : null"
+      :colors="options.colors"
+      :data="chartData"
+      :settings="options.settings"
+      :after-config="options.config"
+      :after-set-option="extend"
+      :extend="defaultOptions"
+      >
+    </ve-histogram>
+  </div>
+`
+
+
+var marketTimeScatter = {
+  name: 'market-time-scatter',
+  template: marketTimeScatterTemplate,
+  props: {
+    chartData: {
+      type: Object,
+      default () {
+        return {
+          columns: ['日期', '项目规模', '环比增长率(%)'],
+          rows: [
+            // {
+            //   日期: '6月',
+            //   项目规模: 0,
+            //   '环比增长率(%)': -33
+            // },
+            // {
+            //   日期: '7月',
+            //   项目规模: 736325,
+            //   '环比增长率(%)': 0
+            // },
+            // {
+            //   日期: '8月',
+            //   项目规模: 73145,
+            //   '环比增长率(%)': 20
+            // }
+          ]
+        }
+      }
+    },
+    width: String,
+    // 柱状图颜色
+    barChartColor: {
+      type: String,
+      default: '#05A6F3'
+    }
+  },
+  data:function () {
+    return {
+      initRendererSvg: {
+        renderer: 'svg'
+      },
+      options: {
+        height: '320px',
+        width: this.width,
+        colors: [this.barChartColor, '#FF3A20'],
+        settings: {
+          showLine: [this.chartData.columns[2]],
+          axisSite: { right: [this.chartData.columns[2]] }
+        },
+        config: this.newTimeConfig
+      },
+      defaultOptions: {
+        grid: {
+          top: 20
+        },
+        xAxis: {
+          axisLabel: {
+            margin: 10,
+            interval: 0, // 强制显示x轴所有刻度
+            fontSize: 10
+          },
+          nameLocation: 'start',
+          nameTextStyle: {
+            fontSize: 12,
+            align: 'left',
+            padding: [70, 0, 0, 50],
+            color: '#9B9CA3'
+          }
+        },
+        yAxis (item) {
+          item[0].splitLine = {
+            lineStyle: {
+              type: 'dashed',
+              width: 0.5
+            }
+          }
+          item[0].axisLabel = {
+            margin: 2,
+            fontSize: 12
+          }
+          item[1].splitLine = {
+            show: false
+          }
+          item[1].axisLabel = {
+            show: false,
+            fontSize: 12
+          }
+          item[0].axisLabel.formatter = (value, index) => {
+            return value.toString().replace(/,/, '')
+          }
+          item[1].axisLabel.formatter = (value, index) => {
+            return value.toString().replace(/,/, '')
+          }
+          return item
+        },
+        tooltip: {
+          trigger: 'axis',
+          confine: true,
+          backgroundColor: '#fff',
+          axisPointer: {
+            type: 'shadow',
+            shadowStyle: {
+              color: 'rgba(42, 190, 209,0.1)'
+            },
+            z: 3
+          },
+          textStyle: {
+            color: '#171826',
+            fontSize: 12
+          },
+          padding: [7, 12],
+          extraCssText: 'box-shadow: 0px 4px 16px rgba(8, 31, 38, 0.08);transform: translate3d(0,0,0)'
+        },
+        legend: {
+          orient: 'horizontal',
+          icon: 'circle',
+          bottom: 0,
+          align: 'left',
+          itemWidth: 8,
+          itemHeight: 8,
+          itemGap: 20,
+          textStyle: {
+            fontSize: 12,
+            rich: {
+              a: {
+                fontSize: 16,
+                verticalAlign: 'top',
+                align: 'center',
+                padding: [0, 15, 28, 0]
+              },
+              b: {
+                fontSize: 14,
+                align: 'center',
+                padding: [0, 15, 0, 0],
+                lineHeight: 25
+              }
+            }
+          },
+          formatter: (name) => {
+            if (name === '企业数量') {
+              name = name + '(个)'
+            }
+            return name
+          }
+        }
+      }
+    }
+  },
+  computed: {},
+  created () {},
+  methods: {
+    extend (chart) {
+      chart.setOption({
+        series: [{
+          type: 'bar',
+          barMaxWidth: 40
+        }, {
+          type: 'line',
+          smooth: false,
+          symbol: 'none'
+        }]
+      })
+    },
+    newTimeConfig (options) {
+      options.xAxis[0].axisLabel.rotate = 60
+      options.xAxis[0].axisLabel.interval = 'auto'
+
+      options.yAxis[1].axisLabel.show = true
+
+      if (this.chartData.rows.length > 8) {
+        // 设置时间轴
+        Object.assign(options, {
+          // grid解决dataZoom文字被隐藏的问题
+          // https://github.com/apache/echarts/issues/11601
+          grid: {
+            left: '5%',
+            right: '13%'
+          },
+          dataZoom: {
+            show: true, // 显示滚动条
+            realtime: true, // 拖动时,是否实时更新系列的视图
+            type: 'slider',
+            height: 20,
+            bottom: 0,
+            textStyle: {
+              fontSize: 10
+            }
+          }
+        })
+      }
+
+      options.legend.bottom = 30
+      options.legend.data = [
+        { icon: 'rect', name: this.chartData.columns[1] },
+        { icon: 'line', name: this.chartData.columns[2] }
+      ]
+
+      options.tooltip.axisPointer.shadowStyle.color = 'rgba(5,166,243,0.1)'
+      options.tooltip.formatter = params => {
+        let tip = '' 
+        for (let i = 0; i < params.length; i++) {
+          if (params[i].value === undefined || params[i].value === '') {
+            params[i].value = 0
+          }
+          if (i === 0) {
+            const unit = params[i].seriesName.match(/((.*))$/g).join('').replace(/[()]/g, '')
+            tip = tip + params[i].marker + params[i].seriesName + ':' + params[i].value + unit + '<br/>'
+          } else if (i === 1) {
+            tip = tip + params[i].marker + params[i].seriesName + ':' + params[i].value + '%' + '<br/>'
+          }
+        }
+        tip += `<div style="padding-top:2px;color:#9B9CA3;text-align:center">- ${params[0].name} -</div>`
+        return tip
+      }
+      return options
+    }
+  }
+}

+ 105 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/marketTop3Table.js

@@ -0,0 +1,105 @@
+var marketTop3TableTemplate = `
+  <div class="market-top3-table">
+    <div
+      class="project-top-item"
+      v-for="(item, index) in tableData"
+      :key="index">
+      <div class="p-t-i-hd">
+        <div
+          class="p-t-i-hd-l table-index-rect"
+          v-text="index + 1"
+          :class="{
+              red: index === 0,
+              orange: index === 1,
+              'soft-orange': index === 2
+          }"></div>
+        <div class="p-t-i-hd-r">
+          <div class="p-t-i-hd-r-top">
+            <div class="project-name ellipsis" v-text="item.name" :class="{ disabled: !item.id }" @click="toPortrait(item.id, item.type)"></div>
+            <div class="project-actions" v-show="item.children.length" :class="{ 'icon-reverse': item.childrenShow }" @click="changeChildrenShow(item)">
+              <div v-text="item.actionText"></div>
+              <van-icon name="arrow-down"></van-icon>
+            </div>
+          </div>
+          <div class="project-info">
+            <div class="project-tags">
+              <div class="j-tag" :class="{ 'tag-blue': type === 'count', 'tag-orange': type === 'amount' }" v-text="item.subInfo1" v-if="item.subInfo1"></div>
+              <div class="j-tag tag-plain" v-text="item.subInfo2" v-if="item.subInfo2"></div>
+            </div>
+            <div class="project-right"></div>
+          </div>
+        </div>
+      </div>
+      <div
+        class="p-t-i-ft"
+        :class="{ disabled: !child.id }"
+        v-for="(child, i) in item.children"
+        :key="i"
+        @click="toPortrait(child.id, child.type)"
+        v-show="item.childrenShow">
+        <div class="p-t-i-ft-title" v-text="child.name"></div>
+        <div class="p-t-i-ft-bottom">
+          <div class="p-t-i-ft-sub" v-text="child.subInfo1" v-if="child.subInfo1"></div>
+          <div class="p-t-i-ft-sub" v-text="child.subInfo2" v-if="child.subInfo2"></div>
+        </div>
+      </div>
+    </div>
+  </div>
+`
+
+var marketTop3Table = {
+  name: 'market-top3-table',
+  template: marketTop3TableTemplate,
+  props: {
+    type: {
+      type: String,
+      default: 'count' // count/amount
+    },
+    tableData: {
+      type: Array,
+      default () {
+        return [
+          // {
+          //   name: 'xxxx',
+          //   subInfo1: 'xx',
+          //   subInfo2: 'xxx',
+          //   actionText: 'actionText',
+          //   childrenShow: true,
+          //   children: [
+          //     {
+          //       name: 'w1',
+          //       subInfo1: 'xx',
+          //       subInfo2: 'xx',
+          //     },
+          //     {
+          //       name: 'w2',
+          //       subInfo1: 'xx',
+          //       subInfo2: 'xx',
+          //     }
+          //   ]
+          // }
+        ]
+      }
+    },
+  },
+  data:function () {
+    return {}
+  },
+  computed: {},
+  created () {},
+  methods: {
+    toPortrait (id, type) {
+      console.log(...arguments)
+      if (!type || !id) return
+      this.$emit('save')
+      if (type === 'winner') {
+        location.href = `./ent_portrait?eId=${id}`
+      } else if (type === 'buyer') {
+        location.href = `./unit_portrayal?entName=${id}`
+      }
+    },
+    changeChildrenShow (item) {
+      item.childrenShow = !item.childrenShow
+    }
+  }
+}

+ 161 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/marketUserScatter.js

@@ -0,0 +1,161 @@
+var marketUserScatterTemplate = `<div class="rect-tree-map-chart" style="width: 100%;min-height: 400px"></div>`
+
+var marketUserScatter = {
+  name: 'market-user-scatter',
+  template: marketUserScatterTemplate,
+  props: {
+    chartData: {
+      type: Array,
+      default () {
+        return [
+          // {
+          //   name: 'a',
+          //   value: 222,
+          //   amount: '22'
+          // },
+          // {
+          //   name: 'b',
+          //   value: 122,
+          //   amount: '22'
+          // },
+          // {
+          //   name: 'b',
+          //   value: 22,
+          //   amount: '22'
+          // },
+          // {
+          //   name: 'd',
+          //   value: 2,
+          //   amount: '22'
+          // },
+        ]
+      }
+    },
+  },
+  data:function () {
+    return {
+      myChart: null,
+      height: '500px',
+      options: {
+        title: {
+          subtext: '单位:个、万元',
+          left: '0',
+          textStyle: {
+            color: '#000',
+            fontWeight: 'normal'
+          }
+        },
+        tooltip: {
+          formatter: this.tooltipFormatter
+        }
+      },
+      defaultOptions: {
+        legend: {
+          show: true,
+          selectedMode: 'single',
+          data: [],
+          bottom: 0,
+          itemGap: 5
+        },
+        tooltip: {
+          backgroundColor: '#fff',
+          confine: true,
+          textStyle: {
+            color: '#171826',
+            fontSize: 12
+          },
+          padding: [7, 12],
+          extraCssText: 'box-shadow: 0px 4px 16px rgba(8, 31, 38, 0.08)',
+          borderWidth: 2,
+          borderColor: '#F5F6F7'
+        },
+        series: [
+          {
+            type: 'treemap',
+            width: '100%',
+            // height: '85%',
+            // top: '15%',
+            roam: false, // 是否开启拖拽漫游(移动和缩放)
+            nodeClick: false, // 点击节点后的行为,false无反应
+            breadcrumb: {
+              show: false
+            },
+            label: { // 描述了每个矩形中,文本标签的样式。
+              normal: {
+                show: true,
+                position: ['10%', '40%']
+              }
+            },
+            itemStyle: {
+              normal: {
+                show: true,
+                textStyle: {
+                  color: '#fff',
+                  fontSize: 16
+                },
+                borderWidth: 1,
+                borderColor: '#fff'
+              },
+              emphasis: {
+                label: {
+                  show: true
+                }
+              }
+            },
+            data: [
+              // {
+              //   name: 'xxx',
+              //   value: 122
+              // },
+              // {
+              //   name: 'yyy',
+              //   value: 122
+              // }
+            ]
+          }
+        ]
+      }
+    }
+  },
+  computed: {},
+  mounted () {
+    this.updateChartView()
+  },
+  methods: {
+    updateChartView () {
+      this.myChart = echarts.init(this.$el, 'light', { renderer: 'canvas' })
+      if (!this.myChart) return
+      this.mergeOptions()
+      this.myChart.setOption(this.defaultOptions)
+      window.addEventListener('resize', () => {
+        // this.myChart.resize()
+      })
+    },
+    mergeOptions () {
+      // 设置数据
+      this.defaultOptions.series[0].data = this.chartData
+      // 设置图例?
+      this.defaultOptions.legend.data = this.chartData.map(item => {
+        return item.name
+      })
+
+      _.merge(this.defaultOptions, this.options)
+    },
+    tooltipFormatter (params) {
+      const item = params.data
+      let tip = `<span style="display:inline-block;margin-right:5px;border-radius:8px;width:8px;height:8px;background-color:${params.color};"></span>${params.name}<br />`
+      if (item && item.value) {
+        tip += `<div>项目数量:${item.value}个<div>`
+      }
+      if (item && item.amount) {
+        tip += `<div>项目金额:${item.amount}万元<div>`
+      }
+      return tip
+    }
+  },
+  beforeDestroy () {
+    if (this.myChart) {
+      this.myChart.dispose()
+    }
+  }
+}

+ 198 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/components/projectScatter.js

@@ -0,0 +1,198 @@
+var projectScatterTemplate = `
+  <div class="project-scatter-chart" v-if="chartData.rows.length">
+    <ve-histogram
+      id="simple-histogram-chart"
+      :init-options="initRendererSvg"
+      :colors="options.colors"
+      :width="options.width"
+      :height="options.height"
+      :data="chartData"
+      :settings="options.settings"
+      :after-config="options.config"
+      :after-set-option="extend"
+      :extend="defaultOptions"
+      >
+    </ve-histogram>
+  </div>
+`
+
+
+var projectScatter = {
+  name: 'project-scatter',
+  template: projectScatterTemplate,
+  props: {
+    chartData: {
+      type: Object,
+      default () {
+        return {
+          columns: ['项目规模', '项目总金额占比', '项目总数占比'],
+          rows: [
+            // {
+            //   项目规模: '≥1亿',
+            //   项目总金额占比: 20,
+            //   项目总数占比: 10
+            // },
+            // {
+            //   项目规模: '1000万-1亿',
+            //   项目总金额占比: 50,
+            //   项目总数占比: 40
+            // },
+            // {
+            //   项目规模: '500万-1000万',
+            //   项目总金额占比: 20,
+            //   项目总数占比: 30
+            // },
+            // {
+            //   项目规模: '100万-500万',
+            //   项目总金额占比: 20,
+            //   项目总数占比: 30
+            // }
+          ]
+        }
+      }
+    },
+  },
+  data:function () {
+    return {
+      initRendererSvg: {
+        renderer: 'svg'
+      },
+      options: {
+        colors: ['#FF9F3F', '#05A5F2'],
+        width: '100%',
+        height: '300px',
+        settings: {}
+      },
+      defaultOptions: {
+        grid: {
+          top: 20
+        },
+        xAxis: {
+          axisLabel: {
+            margin: 10,
+            interval: 0, // 强制显示x轴所有刻度
+            fontSize: 10,
+            formatter: this.xAxisFormatter
+          },
+          nameLocation: 'start',
+          nameTextStyle: {
+            fontSize: 12,
+            align: 'left',
+            padding: [70, 0, 0, 50],
+            color: '#9B9CA3'
+          }
+        },
+        yAxis (item) {
+          Object.assign(item[0], {
+            splitLine: {
+              lineStyle: {
+                type: 'dashed',
+                width: 0.5
+              }
+            },
+            axisLabel: {
+              margin: 2,
+              fontSize: 12,
+              formatter: (value, index) => value.toString().replace(/,/, '') + '%'
+            }
+          })
+
+          Object.assign(item[1], {
+            splitLine: {
+              show: false
+            },
+            axisLabel: {
+              show: false,
+              fontSize: 12,
+              formatter: (value, index) => value.toString().replace(/,/, '')
+            }
+          })
+          return item
+        },
+        tooltip: {
+          trigger: 'axis',
+          confine: true,
+          backgroundColor: '#fff',
+          axisPointer: {
+            type: 'shadow',
+            shadowStyle: {
+              color: 'rgba(42, 190, 209,0.1)'
+            },
+            z: 3
+          },
+          textStyle: {
+            color: '#171826',
+            fontSize: 12
+          },
+          padding: [7, 12],
+          extraCssText: 'box-shadow: 0px 4px 16px rgba(8, 31, 38, 0.08);transform: translate3d(0,0,0)',
+          formatter: this.tooltipFormatter
+        },
+        legend: {
+          orient: 'horizontal',
+          icon: 'rect',
+          bottom: 20,
+          align: 'left',
+          itemGap: 20,
+          textStyle: {
+            fontSize: 12,
+            rich: {
+              a: {
+                fontSize: 16,
+                verticalAlign: 'top',
+                align: 'center',
+                padding: [0, 15, 28, 0]
+              },
+              b: {
+                fontSize: 14,
+                align: 'center',
+                padding: [0, 15, 0, 0],
+                lineHeight: 25
+              }
+            }
+          },
+          formatter: name => name
+        }
+      }
+    }
+  },
+  computed: {},
+  created () {},
+  methods: {
+    extend (chart) {
+      chart.setOption({
+        series: [
+          {
+            type: 'bar'
+          },
+          {
+            type: 'bar'
+          }
+        ]
+      })
+    },
+    tooltipFormatter (params) {
+      let tip = ''
+      for (let i = 0; i < params.length; i++) {
+        if (params[i].value === undefined || params[i].value === '') {
+          params[i].value = 0
+        }
+        if (i === 0) {
+          tip = tip + params[i].marker + params[i].seriesName + ':' + params[i].value + '%<br/>'
+        } else if (i === 1) {
+          tip = tip + params[i].marker + params[i].seriesName + ':' + params[i].value + '%<br/>'
+        }
+      }
+      tip +=`<div style="padding-top:2px;color:#9B9CA3;text-align:center">- ${params[0].name} -</div>`
+      return tip
+    },
+    xAxisFormatter (params) {
+      var arr = params.split('-')
+      if (arr.length === 2) {
+        return arr.join('\n-')
+      } else {
+        return params
+      }
+    }
+  }
+}

+ 80 - 34
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/ent_portrait.js

@@ -134,7 +134,8 @@ var vNode = {
         dt: true
       },
       canFreeExp: false,
-      canFreeTrial: false
+      canFreeTrial: false,
+      freeWinnerOpen: false
     }
   },
   created: function () {
@@ -231,7 +232,7 @@ var vNode = {
       return (!this.conf._4 && !this.isVip) || (this.entvisit.total <= this.entvisit.usage && this.powerInfo.memberStatus <= 0 && !this.entvisit.visited) || (this.entvisit.total <= this.entvisit.usage && !this.showContacts && !this.entvisit.visited)
     },
     isMember () {
-      return this.powerInfo.memberStatus <= 0 || !this.conf._4
+      return !this.conf._4 || this.powerInfo.memberStatus <= 0
     },
     isShowUpTip () {
       // 出现升级提醒 是新超级订阅买的不是全国、次数已用完 、不是大会员
@@ -264,11 +265,45 @@ var vNode = {
     }
   },
   methods: {
+    // 监听画像页面滚动
+    onEntScroll: utils.debounce(function(){
+      if (!this.freeWinnerOpen) return // 没有开通超级订阅广告位banner return
+      var scrollTop = this.$refs.container.scrollTop // 画像页面父dom滚动距离
+      var offSetTop = this.$refs.setRef.offsetTop // 中标分析-高级分析设置距顶部距离
+      var bannerHeight = this.$refs.bannerRef.offsetHeight // 广告位banner高度
+      if (scrollTop >= offSetTop - bannerHeight) {
+        $('.banner-sticky').css({
+          "position": "fixed",
+          'top': '33.67vw',
+          "z-index": '9999'
+        })
+      } else {
+        $('.banner-sticky').css({
+          "position": "static"
+        })
+        $('.win-analyse').css({
+          "margin-top": '.24rem'
+        })
+      }
+    }, 50),
     scrollHeight: function () {
       var storageClick = JSON.parse(sessionStorage.getItem('is-click-set'))
       if ($('.win-analyse').length && $('.win-analyse').length > 0 && storageClick) {
         this.$nextTick(function(){
-          document.querySelector('.win-analyse').scrollIntoView()
+          // 有开通超级订阅banner时
+          if (this.freeWinnerOpen) {
+            document.querySelector('.banner-sticky').scrollIntoView()
+            $('.banner-sticky').css({
+              "position": "fixed",
+              'top': '33.67vw',
+              "z-index": '9999'
+            })
+            $('.win-analyse').css({
+              "margin-top": '2rem'
+            })
+          } else {
+            document.querySelector('.win-analyse').scrollIntoView()
+          }
           sessionStorage.removeItem('is-click-set')
         })
       }
@@ -356,20 +391,22 @@ var vNode = {
       }
       let urls = ''
       // 如果专家版、智慧版 调大会员接口,如果是专家版、自定义版,同时是超级订阅 根据可查看次数判断 调大会员还是超级订阅接口
-      if (_this.powerInfo.memberStatus > 0 && _this.powerInfo.memberStatus <= 2) {
+      if (_this.powerInfo.memberStatus > 0 && _this.powerInfo.power.indexOf(4) > -1) {
         urls = '/bigmember/portrait/winner/getData'
-      } else if (_this.powerInfo.memberStatus > 2) {
-        if ( _this.isVip) { // 超级订阅
-          if(_this.entvisit.total <= _this.entvisit.usage && !_this.entvisit.visited) {
-            urls = '/bigmember/portrait/winner/getData'
-          } else {
-            urls = '/bigmember/portrait/subVipPortrait/winner'
-          }
-        } else {
-          urls = '/bigmember/portrait/winner/getData'
-           // 商机版、自定义版
-        }
-      } else {
+      }
+      //  else if (_this.powerInfo.memberStatus > 2) {
+      //   if ( _this.isVip) { // 超级订阅
+      //     if(_this.entvisit.total <= _this.entvisit.usage && !_this.entvisit.visited) {
+      //       urls = '/bigmember/portrait/winner/getData'
+      //     } else {
+      //       urls = '/bigmember/portrait/subVipPortrait/winner'
+      //     }
+      //   } else {
+      //     urls = '/bigmember/portrait/winner/getData'
+      //      // 商机版、自定义版
+      //   }
+      // } 
+      else {
         urls = '/bigmember/portrait/subVipPortrait/winner'
       }
       _this.getEntPortraitInfoTimes++
@@ -460,19 +497,21 @@ var vNode = {
       var _this = this
       var urls = ''
       // 判断专家版、智慧版; 商机版和自定义版时判断是不是超级订阅
-      if (_this.powerInfo.memberStatus > 0 && _this.powerInfo.memberStatus <= 2) {
+      if (_this.powerInfo.memberStatus > 0 && _this.powerInfo.power.indexOf(13) > -1) {
         urls = '/bigmember/portrait/winner/getNewMsg'
-      } else if (_this.powerInfo.memberStatus > 2) {
-        if (_this.isVip) {
-          if (_this.entvisit.total <= _this.entvisit.usage && !_this.entvisit.visited) {
-            urls = '/bigmember/portrait/winner/getNewMsg'
-          } else {
-            urls = '/bigmember/portrait/subVipPortrait/winnerNewMsg'
-          }
-        } else {
-          urls = '/bigmember/portrait/winner/getNewMsg'
-        }
-      } else {
+      } 
+      // else if (_this.powerInfo.memberStatus > 2) {
+      //   if (_this.isVip) {
+      //     if (_this.entvisit.total <= _this.entvisit.usage && !_this.entvisit.visited) {
+      //       urls = '/bigmember/portrait/winner/getNewMsg'
+      //     } else {
+      //       urls = '/bigmember/portrait/subVipPortrait/winnerNewMsg'
+      //     }
+      //   } else {
+      //     urls = '/bigmember/portrait/winner/getNewMsg'
+      //   }
+      // } 
+      else {
         urls = '/bigmember/portrait/subVipPortrait/winnerNewMsg'
       }
       return urls
@@ -553,9 +592,9 @@ var vNode = {
         },
         error: function (error) {
           console.log(error)
-          setTimeout(function() {
-            _this.getEntBaseInfo()
-          }, 3000)
+          // setTimeout(function() {
+          //   _this.getEntBaseInfo()
+          // }, 3000)
         }
       })
     },
@@ -668,7 +707,7 @@ var vNode = {
             _this.conf.arr = res.data.power
             _this.conf.vipStatus = res.data.vipStatus
             // 新版超级订阅用户获取访问量
-            if (res.data.viper && _this.conf.isMember <= 0) {
+            if (res.data.viper && (_this.conf.isMember <= 0 || res.data.power.indexOf(4) == -1)) {
               _this.getEntVisits()
             }
             _this.getDataFn()
@@ -676,8 +715,12 @@ var vNode = {
             _this.$toast(res.error_msg)
           }
           //免费用户体验权限
-          if(res.data.isFree&&res.data.freeEntPort==0){
-            _this.canFreeExp=true
+          if(res.data.isFree){
+            if (res.data.freeEntPort==0) {
+              _this.canFreeExp=true
+            } else {
+              _this.freeWinnerOpen = true
+            }
           }
           // 免费用户看过当前企业画像数据
           if (res.data.isFree) {
@@ -1240,6 +1283,9 @@ var vNode = {
     //免费赠送企业全景分析体验 去解锁
     goGiveAnalysis: function(){
       location.href = '/jyapp/frontPage/bigmember/free/perfect_info?source=ent_portrait_freeuser';
+    },
+    goOpenVip: function() {
+      location.href = "/jyapp/vipsubscribe/vipsubscribe_new"
     }
   }
 }

+ 11 - 1
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/main_root_data.js

@@ -7,7 +7,7 @@
     7.挖掘潜在客户
     8.挖掘潜在伙伴/竞争对手 
     9.挖掘潜在项目
-    10.周报月报
+    10.周报月报+定制化报告
     11.招标文件解读
     12.企业情报监控
     13.企业中标动态
@@ -187,6 +187,16 @@ var staticData = [
                 b_high:'月报',
                 b_content:'根据为您推送的招标项目信息,提供每月的市场(含细分市场)、采购单位、中标单位等多维度分析报告,助您掌握市场发展趋势。'
             },
+            {
+                id:10,
+                b_class:'isgray',
+                url:'/jyapp/big/page/report_analysis',
+                dis_url:'javascript:;',
+                b_gray_icon:'icon-gray-dingzhi',
+                b_gold_icon:'icon-gold-dingzhi',
+                b_high:'定制化市场分析报告',
+                b_content:'您可自定义时间范围,自动生成多维度市场分析报告。'
+            },
             {
                 id:17,
                 b_class:'isgray',

+ 1795 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/report_analysis.js

@@ -0,0 +1,1795 @@
+function dateFormatter (date, pattern) {
+  return new Date(date).pattern(pattern)
+}
+var vm = new Vue({
+  delimiters: ['${', '}'],
+  el: '#analysis',
+  components: {
+    keywordComponent: keywordComponent,
+    areaCityMobile: areaCityMobileComponent,
+    industryComponent: industryComponent,
+    cateComponent: cateComponent,
+    dateComponent: dateComponent,
+    // 图表
+    projectScatter: projectScatter,
+    marketTimeScatter: marketTimeScatter,
+    marketAreaScatter: marketAreaScatter,
+    marketTop3Table: marketTop3Table,
+    marketUserScatter: marketUserScatter,
+    marketSegment: marketSegment,
+    lineChartScatter: lineChartScatter,
+  },
+  data: {
+    sessStorageKey: '$data-report_analysis',
+    tabActiveName: 'analysis', // analysis/history
+    tabList: [
+      {
+        label: '定制化市场分析',
+        name: 'analysis'
+      },
+      {
+        label: '历史报告',
+        name: 'history'
+      }
+    ],
+    tabConf: {
+      titleActiveColor: '#2ABED1',
+      titleInactiveColor: '#5F5E64',
+      lineWidth: '24',
+      color: '#2ABED1'
+    },
+    timeOptions: [
+      {
+        name: '近3个月',
+        value: 'lately90',
+        selected: false
+      },
+      {
+        name: '近半年',
+        value: 'lately180',
+        selected: false
+      },
+      {
+        name: '今年全年',
+        value: 'thisYear',
+        selected: false
+      },
+      {
+        name: '去年至今',
+        value: 'sinceLastYear',
+        selected: false
+      },
+      {
+        name: '前年至今',
+        value: 'sinceYearBeforeLast',
+        selected: false
+      }
+    ],
+    scrollTop: 0,
+    filtersPageShow: true,
+    filters: {
+      selectKeysArr: [], // 关键词简单数组,用于恢复选择状态
+      keys: [], // 关键词详细数组,用于提交数据
+      area: {},
+      industry: [],
+      industryDetail: {},
+      buyerclass: [],
+      rangeTime: {
+        start: '',
+        end: '',
+        exact: 'sinceYearBeforeLast',
+      },
+    },
+    filterDialogShow: {
+      keys: false,
+      area: false,
+      industry: false,
+      buyerclass: false,
+      rangeTime: false
+    },
+    // 分析结果页面数据
+    activeDimension: 'market',
+    dimensionList: [
+      {
+        id: 'market',
+        name: '市场规模',
+        top: 0,
+        anchor: 'market-overview'
+      },
+      {
+        id: 'buyer',
+        name: '采购单位',
+        top: 0,
+        anchor: 'buyerclass-scatter'
+      },
+      {
+        id: 'bidder',
+        name: '中标单位',
+        top: 0,
+        anchor: 'winner-scatter'
+      },
+    ],
+    analysis: { // 开始分析请求的loaed和loading
+      loaded: false,
+      loading: false
+    },
+    rid: '', // reportId
+    reportFilters: {
+      keys: [],
+      selectTime: '',
+      selectTimeExtra: '',
+      area: {},
+      industry: {},
+      buyerclass: []
+    },
+    sections: {
+      market: {
+        overview: [],
+        refine: {
+          dataAlready: false,
+          projectCountData: null,
+          projectAmountData: null,
+          // 项目数量Top3
+          projectCountTop3: null,
+          // 项目金额Top3
+          projectAmountTop3: null
+        }
+      },
+      projectScatter: {
+        dataAlready: false,
+        chartData: null,
+        tableData: [
+          // {
+          //   projectname: 'xxxx',
+          //   area: 'xx',
+          //   city: 'xxx',
+          //   sortprice: 'zzz',
+          //   jgtime: 'zzzz',
+          //   winner_s: [
+          //     {
+          //       name: 'w1',
+          //       id: '33'
+          //     },
+          //     {
+          //       name: 'w2',
+          //       id: '33'
+          //     }
+          //   ]
+          // },
+          // {
+          //   projectname: 'xxxx',
+          //   area: 'xx',
+          //   city: 'xxx',
+          //   sortprice: 'zzz',
+          //   jgtime: 'zzzz',
+          //   winner_s: [
+          //     {
+          //       name: 'w1',
+          //       id: '33'
+          //     },
+          //     {
+          //       name: 'w2',
+          //       id: '33'
+          //     }
+          //   ]
+          // }
+        ]
+      },
+      timeScatter: {
+        dataAlready: false, // 数据准备好之后才能开始渲染
+        activeAction: 'month',
+        actionList: [
+          {
+            label: '月度数据',
+            value: 'month'
+          },
+          {
+            label: '年度数据',
+            value: 'year'
+          }
+        ],
+        month: {
+          count: {},
+          amount: {}
+        },
+        year: {
+          count: {},
+          amount: {}
+        }
+      },
+      areaScatter: {
+        dataAlready: false,
+        chartData: null,
+        // 项目数量Top3
+        projectCountTop3: null,
+        // 项目金额Top3
+        projectAmountTop3: null
+      },
+      userScatter: {
+        list: [],
+        // 项目数量Top3
+        projectCountTop3: null,
+        // 项目金额Top3
+        projectAmountTop3: null
+      },
+      buyerclass: {
+        dataAlready: false,
+        chartData: null,
+        // 项目数量Top3
+        projectCountTop3: null,
+        // 项目金额Top3
+        projectAmountTop3: null
+      },
+      winner: {
+        dataAlready: false,
+        chartData: null,
+        // 项目数量Top3
+        projectCountTop3: null,
+        // 项目金额Top3
+        projectAmountTop3: null
+      }
+    },
+    empty: {
+      defaultMsg: '对不起,没有匹配到相关信息<br />请修改您的分析条件',
+      msg: ''
+    },
+    stickyOffset: 0,
+    notSetKey: false, // 未设置关键词
+    isSubCount: false // 是否子账号
+  },
+  computed: {
+    anchorTopList: function () {
+      var arr = []
+      this.dimensionList.forEach(function (item) {
+        arr.push(item.top)
+      })
+      return arr
+    },
+    // 报告详情筛选条件只有一个省份
+    // 此时不显示地区分布chart
+    oneAreaFilter () {
+      var area = this.reportFilters.area
+      var showArea = area && (Object.keys(area).length > 1 || Object.keys(area).length === 0)
+      return showArea
+    },
+    emptyShow () {
+      return !this.rid && this.analysis.loaded
+    },
+    tabActive: function () {
+      var _this = this
+      var active = {}
+      this.tabList.some(function (item) {
+        var findThis = item.name === _this.tabActiveName
+        if (findThis)  {
+          active = item
+          return findThis
+        }
+      })
+      return active
+    },
+    buyerclassSectionShow () {
+      const winnerState = this.sections.buyerclass
+      return winnerState.dataAlready && winnerState.projectCountTop3 && winnerState.projectAmountTop3
+    },
+    winnerSectionShow () {
+      const winnerState = this.sections.winner
+      return winnerState.dataAlready && winnerState.projectCountTop3 && winnerState.projectAmountTop3
+    },
+    overviewRateTotal: function () {
+      var total = 0
+      this.sections.market.overview.forEach(function (item) {
+        if (item.ringRatio !== undefined && item.ringRatio !== null) {
+          total += item.ringRatio
+        }
+      })
+      return total
+    }
+  },
+  watch: {
+    filtersPageShow (newVal) {
+      if (!newVal) {
+        this.calcStickyOffset()
+      }
+    }
+  },
+  created () {
+    this.calcLastTimeText()
+    this.getPower()
+    var id = utils.getParam('id')
+    if (id) {
+      this.rid = decodeURIComponent(id)
+      this.filtersPageShow = false
+    }
+  },
+  mounted: function () {
+    setTimeout(() => {
+      var restored = this.reStoreState()
+      if (!restored) {
+        if (this.rid) {
+          this.getReportResult()
+        }
+      } else {
+        this.$nextTick(this.calcOffsetTop)
+      }
+    }, 0)
+    this.addEventListeners()
+    utils.iosBackRefresh()
+  },
+  methods: {
+    showLoading: function () {
+      return this.$toast.loading({
+        duration: 0,
+        forbidClick: true,
+        message: 'loading...',
+      })
+    },
+    showToast: function (message) {
+      return this.$toast({
+        duration: 1500,
+        forbidClick: true,
+        message: message,
+      })
+    },
+    showDialog: function (conf) {
+      var defaultConf = {
+        title: '提示',
+        message: 'message',
+        className: 'j-confirm-dialog',
+        showConfirmButton: true,
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        confirmButtonColor: '#2abed1'
+      }
+      if (conf) {
+        Object.assign(defaultConf, conf)
+      }
+      return this.$dialog.confirm(defaultConf)
+    },
+    calcOffsetTop: function () {
+      var sticky = $('.van-sticky')
+      var stickyHeight = 0
+      if (sticky.length) {
+        stickyHeight = sticky[0].clientHeight
+      }
+      this.dimensionList.forEach(function (item) {
+        var anchor = $('.' + item.anchor)
+        var offsetTop = 0
+        if (anchor.length) {
+          offsetTop = parseInt(anchor[0].offsetTop - stickyHeight)
+        }
+        item.top = offsetTop
+      })
+    },
+    addEventListeners: function () {
+      this.scrollToTop()
+    },
+    scrollToTop: function () {
+      var $scrollDOM = $('.j-container.search-result > .j-main')
+      // 1. 检查当前高度是否满足显示快速滚动到顶部
+      this.checkScrollTopButtonShow()
+      // 2. 具体逻辑
+      $scrollDOM.on('scroll', this.checkScrollTopButtonShow)
+      setTimeout(function () {
+        // 2s后绑定(尽可能保证top能够被计算完)
+        $scrollDOM.on('scroll', this.checkAnchorItemActive)
+      }.bind(this), 2000)
+
+      $('.scroll-to-top').on('click', function () {
+        $scrollDOM.animate({ scrollTop: 0 })
+      })
+    },
+    checkAnchorItemActive: function () {
+      var $scrollDOM = $('.j-container.search-result > .j-main')
+      var anchorTopList = this.anchorTopList
+      var scrollTop = parseInt($scrollDOM.scrollTop()) + 3 // (误差校正)
+      var i = 0
+      if (scrollTop >= anchorTopList[1] && scrollTop < anchorTopList[2]) {
+        i = 1
+      } else if (scrollTop > anchorTopList[2]) {
+        i = 2
+      } else if (scrollTop < anchorTopList[1]) {
+        i = 0
+      }
+      this.activeDimension = this.dimensionList[i].id
+    },
+    checkScrollTopButtonShow: function () {
+      var showButtonHeight = 300
+      var $scrollDOM = $('.j-container.search-result > .j-main')
+      var button = $('.scroll-to-top')
+      var scrollTop = $scrollDOM.scrollTop()
+      if (scrollTop > showButtonHeight) {
+        button.show()
+      } else {
+        button.hide()
+      }
+    },
+    calcStickyOffset: function () {
+      setTimeout(function () {
+        var headerHeight = $('.jy-app-header')[0].clientHeight
+        var tabHeight = $('.analysis-tab')[0].clientHeight
+        this.stickyOffset = headerHeight + tabHeight - 5
+      }.bind(this), 1000)
+    },
+    setScrollTop: function (scrollTop) {
+      this.$nextTick(function () {
+        var wrapper = document.querySelector('.j-container.search-result > .j-main')
+        wrapper.scrollTop = scrollTop
+      })
+    },
+    saveScrollTop: function () {
+      var wrapper = document.querySelector('.j-container.search-result > .j-main')
+      if (wrapper.scrollTop) {
+        this.scrollTop = parseInt(wrapper.scrollTop)
+      }
+    },
+    beforeTabChange: function (name) {
+      if (name !== this.tabActiveName) {
+        this.goToAnalysisHistory()
+      }
+      return false
+    },
+    goToAnalysisHistory: function () {
+      location.href = './report_analysis_history'
+    },
+    formatSelectTime (value) {
+      if (!value) return '-'
+      const timeArr = value.split('-')
+      return `${dateFormatter(timeArr[0] * 1000, 'yyyy/MM/dd')}-${dateFormatter(timeArr[1] * 1000, 'yyyy/MM/dd')}`
+    },
+    getPower:function () {
+      var _this = this
+      $.ajax({
+        type:'POST',
+        url:'/bigmember/use/isAdd',
+        success:function(res) {
+          if (res.data && res.data.isSubCount){
+            _this.isSubCount = true
+          }
+        }
+      })
+    },
+    init: function () {
+      // 初始化页面数据
+      this.initDateTimeSelector('sinceYearBeforeLast')
+    },
+    // 时间选择器选中状态
+    initDateTimeSelector: function (exact) {
+      if (exact === 'exact') {
+        this.$refs.dateSelector.setState(this.filters.rangeTime)
+      } else {
+        this.$refs.dateSelector.setTimeSelectListState(exact)
+        this.$refs.dateSelector.dateStyle = false
+      }
+    },
+    resolveSelected: function (type) {
+      var filters = this.filters
+      var prefix = '已选:'
+      var text = ''
+      if (type === 'keys') {
+        if (this.notSetKey) return '请设置'
+        text = this.resolveSelectKeysText(filters.keys)
+      } else if (type === 'area') {
+        text = this.resolveSelectAreaText(filters.area)
+      } else if (type === 'industry') {
+        text = this.resolveSelectIndustryText(filters.industryDetail)
+      } else if (type === 'buyerclass') {
+        text = this.resolveSelectBuyerclassText(filters.buyerclass)
+      }
+      return prefix + text
+    },
+    resolveSelectKeysText: function (keys) {
+      if (Array.isArray(keys)) {
+        if (keys.length === 0) {
+          return '全部'
+        } else {
+          var count = 0
+          var arr = []
+          keys.forEach(function (classify) {
+            if (Array.isArray(classify.a_key) && classify.a_key.length) {
+              count += classify.a_key.length
+              classify.a_key.forEach(function (item) {
+                arr.push(item.key.join(' '))
+              })
+            }
+          })
+          if (count <= 0) {
+            return '全部'
+          } else {
+            return arr.join(',')
+          }
+        }
+      } else {
+        return '全部'
+      }
+    },
+    resolveSelectAreaText: function (area) {
+      if (!area || Object.keys(area).length === 0) return '全国'
+      var areaArr = []
+      var cityArr = []
+      for (var key in area) {
+        if (area[key].length === 0) {
+          areaArr.push(key)
+        } else {
+          cityArr = cityArr.concat(area[key])
+        }
+      }
+      return areaArr.concat(cityArr).join(',')
+    },
+    resolveSelectIndustryText: function (industry) {
+      if (!industry || Object.keys(industry).length === 0) return '全部'
+      var keyArr = []
+      var valueArr = []
+      for (var key in industry) {
+        if (industry[key].length === 0) {
+          keyArr.push(key)
+        } else {
+          valueArr = valueArr.concat(industry[key])
+        }
+      }
+      return keyArr.concat(valueArr).join(',')
+    },
+    resolveSelectBuyerclassText: function (buyerclass) {
+      if (!Array.isArray(buyerclass)) return '全部'
+      if (buyerclass.length === 0) return '全部'
+      return buyerclass.join(',')
+    },
+    calcLastTimeText: function () {
+      const renameList = [
+        'thisYear', // 今年全年
+        'sinceLastYear', // 去年至今
+        'sinceYearBeforeLast' // 前年至今
+      ]
+      const thisYear = new Date().getFullYear()
+      this.timeOptions.forEach(item => {
+        if (renameList.indexOf(item.value) !== -1) {
+          if (item.value === renameList[0]) {
+            item.name = `${thisYear}年全年`
+          } else if (item.value === renameList[1]) {
+            item.name = `${thisYear - 1}年至今`
+          } else if (item.value === renameList[2]) {
+            item.name = `${thisYear - 2}年至今`
+          }
+        }
+      })
+    },
+    // 重置
+    resetFilter: function (type) {
+      var filters = this.filters
+      if (type === 'keys') {
+        filters.keys = []
+        filters.selectKeysArr = []
+        try {
+          this.$refs.keywordSelector.resetAllNoSelect()
+        } catch (error) {}
+      } else if (type === 'area') {
+        filters.area = {}
+      } else if (type === 'industry') {
+        filters.industry = []
+        filters.industryDetail = {}
+      } else if (type === 'buyerclass') {
+        filters.buyerclass = []
+      } else if (type === 'date') {
+        this.filters.rangeTime.start = ''
+        this.filters.rangeTime.edd = ''
+        this.filters.rangeTime.exact = 'sinceYearBeforeLast'
+        this.initDateTimeSelector(this.filters.rangeTime.exact)
+      } else {
+        this.resetFilter('keys')
+        this.resetFilter('area')
+        this.resetFilter('industry')
+        this.resetFilter('buyerclass')
+        this.resetFilter('date')
+      }
+    },
+    clickCell: function (key) {
+      var _this = this
+      var dialog = this.filterDialogShow
+      if (key === 'keys') {
+        if (this.notSetKey) {
+          return this.setKeyTip()
+        }
+      } else if (key === 'area') {
+        setTimeout(function () {
+          _this.$refs.areaCitySelector.setState(_this.filters.area)
+        }, 0)
+      } else if (key === 'buyerclass') {
+        setTimeout(function () {
+          _this.$refs.buyerclassSelector.setState()
+        }, 0)
+      }  else if (key === 'industry') {
+        setTimeout(function () {
+          _this.$refs.industrySelector.setState()
+        }, 0)
+      }
+      dialog[key] = true
+    },
+    cancel: function (e, key) {
+      var dialog = this.filterDialogShow
+      this.resetFilter(key)
+      dialog[key] = false
+    },
+    confirm: function (e, key) {
+      var dialog = this.filterDialogShow
+      var filters = this.filters
+      if (key === 'keys') {
+        filters.keys = e.detail
+        filters.selectKeysArr = e.data
+      } else if (key === 'area') {
+        filters.area = e.data
+      } else if (key === 'industry') {
+        filters.industry = e.data
+        filters.industryDetail = e.detail
+      } else if (key === 'buyerclass') {
+        filters.buyerclass = e.data
+        console.log(e.data)
+      } 
+      dialog[key] = false
+    },
+    dateTimeSelectorConfirm () {
+      var result = this.$refs.dateSelector.getState()
+      this.filters.rangeTime.start = result.start
+      this.filters.rangeTime.end = result.end
+      this.filters.rangeTime.exact = result.exact
+    },
+    resetAllFilters: function () {
+      this.analysis.loaded = false
+      this.resetFilter('all')
+    },
+    getReportResult () {
+      this.sendRequest()
+    },
+    getSelectedKeys () {
+      const keys = this.filters.keys
+      if (Array.isArray(keys) && keys.length) {
+        return JSON.stringify(keys)
+      } else {
+        var allKeys = this.$refs.keywordSelector.keywordGroupList
+        return JSON.stringify(allKeys)
+      }
+    },
+    startAnalysis: function () {
+      this.dateTimeSelectorConfirm()
+
+      const query = {
+        keysItems: this.getSelectedKeys(),
+        rangeTime: `${parseInt(this.filters.rangeTime.start / 1000)}-${parseInt(this.filters.rangeTime.end / 1000)}`,
+        rangeTimeExtra: this.filters.rangeTime.exact,
+        area: JSON.stringify(this.filters.area),
+        industry: JSON.stringify(this.filters.industryDetail),
+        buyerclass: this.filters.buyerclass.join(',')
+      }
+
+      this.analysis.loaded = false
+      this.analysis.loading = true
+      this.showLoading()
+
+      $.ajax({
+        type: 'POST',
+        url: '/bigmember/marketAnalysis/doAnalysis',
+        data: query,
+        success: function (res) {
+          if (res && res.error_code === 0 && res.data) {
+            this.rid = res.data
+            this.analysis.loaded = true
+            // location.replace('./report_analysis?id=' + res.data)
+            this.rid = res.data
+            this.getReportResult()
+          } else {
+            this.$toast(res.error_msg)
+          }
+        }.bind(this),
+        complete: function () {
+          this.analysis.loading = false
+        }.bind(this)
+      })
+    },
+    // 保存页面状态
+    saveState: function () {
+      this.saveScrollTop()
+      this.dateTimeSelectorConfirm()
+      var $data = {
+        analysis: this.analysis,
+        filters: this.filters,
+        scrollTop: this.scrollTop,
+        filtersPageShow: this.filtersPageShow,
+        reportFilters: this.reportFilters,
+        sections: this.sections,
+        isSubCount: this.isSubCount
+      }
+      sessionStorage.setItem(this.sessStorageKey, JSON.stringify($data))
+    },
+    reStoreState: function () {
+      var $data = sessionStorage.getItem(this.sessStorageKey)
+      if ($data) {
+        $data = JSON.parse($data)
+
+        this.isSubCount = $data.isSubCount
+        this.scrollTop = $data.scrollTop
+        this.filtersPageShow = $data.filtersPageShow
+        Object.assign(this.analysis, $data.analysis)
+        this.$set(this, 'filters', $data.filters)
+        this.$set(this, 'reportFilters', $data.reportFilters)
+        this.$set(this, 'sections', $data.sections)
+
+        setTimeout(function () {
+          // 恢复滚动高度
+          this.setScrollTop(this.scrollTop)
+          this.initDateTimeSelector(this.filters.rangeTime.exact)
+        }.bind(this), 0)
+
+        sessionStorage.removeItem(this.sessStorageKey)
+      } else {
+        this.init()
+      }
+
+      return $data
+    },
+    onEmpty (info) {
+      if (this.loading) {
+        this.loading.clear()
+      }
+      this.filtersPageShow = true
+      this.analysis.loaded = true
+      this.rid = ''
+      if (info && info.msg) {
+        this.empty.msg = info.msg
+      } else {
+        this.empty.msg = this.empty.defaultMsg
+      }
+    },
+    sendRequest () {
+      // 先请求概况(1),判断报告是否为空
+      const query = {
+        rid: this.rid,
+        flag: 1
+      }
+      if (!query.rid) {
+        return
+      }
+      this.loading = this.showLoading()
+      var res = $.ajax({
+        type: 'POST',
+        async: false,
+        url: '/bigmember/marketAnalysis/getAnalysisResult',
+        data: query
+      }).responseJSON
+
+      if (res && res.error_code === 0 && res.data) {
+        var empty = this.formatterData(query.flag, res.data)
+        if (empty) {
+          return this.onEmpty()
+        }
+      } else {
+        if (res.error_msg.indexOf('项目数量超出上限') === -1) {
+          return this.onEmpty()
+        } else {
+          return this.onEmpty({ msg: '当前分析条件涉及项目数量已超过最大限制,请修改分析条件进行精确分析' })
+        }
+      }
+
+      this.filtersPageShow = false
+
+      const flagArr = [
+        0, // 筛选条件
+        // 1, // 市场概括与时间分布
+        2, // 项目规模Top10
+        3, // 项目规模分布/地区规模分布/客户分布/地区分布及客户分布&Top3(table+chart)
+        4, // 细分市场
+        5 // 采购单位/中标单位&Top3(table+chart)
+      ]
+
+      flagArr.forEach(this.getReport)
+
+      if (this.loading) {
+        this.loading.clear()
+      }
+    },
+    getReport (flag) {
+      const query = {
+        rid: this.rid,
+        flag
+      }
+      if (!query.rid) {
+        return
+      }
+      
+      $.ajax({
+        type: 'POST',
+        url: '/bigmember/marketAnalysis/getAnalysisResult',
+        data: query,
+        success: function (res) {
+          if (res && res.error_code === 0 && res.data) {
+            this.formatterData(flag, res.data)
+          } else {
+            this.$toast('请求失败')
+          }
+        }.bind(this)
+      })
+    },
+    formatterData (flag, data) {
+      if (flag === 0) {
+        this.sortReportFilters(data)
+      } else if (flag === 1) {
+        // 市场概况
+        const totalCount = this.sortMarketOverview(data.market_profile)
+        if (!totalCount) {
+          return true
+        }
+        // 时间分布
+        this.sortTimeScatter(data)
+      } else if (flag === 2) {
+        // 项目规模Top10
+        this.sortProjectTop10(data.ProjectTop10)
+      } else if (flag === 3) {
+        // 项目规模分布/地区规模分布/客户分布/地区分布及客户分布&Top3(table+chart)
+        // 项目规模分布
+        this.sortProjectScatter(data.projectScale)
+        // 地区规模分布
+        this.sortAreaScatter(data.area_infos)
+        // 客户分布
+        this.sortUserScatter(data.customer_scale)
+        // 地区分布及客户分布Top3
+        this.sortAreaUserTop3(data)
+      } else if (flag === 4) {
+        // 细分市场
+        this.sortMarketRefineData(data)
+      } else if (flag === 5) {
+        // 采购单位/中标单位&Top3(table+chart)
+        this.sortBuyerclassData(data)
+        // 中标单位分析
+        this.sortWinnerData(data)
+      }
+
+      this.$nextTick(this.calcOffsetTop)
+    },
+    formatSelectTime (value) {
+      if (!value) return '-'
+      const timeArr = value.split('-')
+      return `${dateFormatter(timeArr[0] * 1000, 'yyyy/MM/dd')}-${dateFormatter(timeArr[1] * 1000, 'yyyy/MM/dd')}`
+    },
+    // 整理数据,并赋值给filters
+    sortReportFilters (data) {
+      if (data.keysItems && data.keysItems !== '[]') {
+        this.reportFilters.keys = JSON.parse(data.keysItems)
+        this.filters.keys = this.reportFilters.keys
+        var keyArr = []
+        this.filters.keys.forEach(function (classify) {
+          if(Array.isArray(classify.a_key)) {
+            classify.a_key.forEach(function (item) {
+              keyArr.push(item.key.join(' '))
+            })
+          }
+        })
+        this.filters.selectKeysArr = keyArr
+      }
+      if (data.rangeTime) {
+        this.reportFilters.selectTime = data.rangeTime
+        var arr = data.rangeTime.split('-')
+        this.filters.rangeTime.start = arr[0] * 1000
+        this.filters.rangeTime.end = arr[1] * 1000
+      }
+      if (data.s_rangeTimeExtra) {
+        this.reportFilters.selectTimeExtra = data.s_rangeTimeExtra
+        this.filters.rangeTime.exact = this.reportFilters.selectTimeExtra
+      } else {
+        this.filters.rangeTime.exact = 'exact'
+      }
+      this.$refs.dateSelector.setState(this.filters.rangeTime)
+      if (data.area && data.area !== '{}') {
+        this.reportFilters.area = JSON.parse(data.area)
+        this.filters.area = this.reportFilters.area
+      }
+      if (data.industry && data.industry !== '{}') {
+        this.reportFilters.industry = JSON.parse(data.industry)
+        this.$set(this.filters, 'industryDetail', this.reportFilters.industry)
+        var industry = []
+        for (var key in this.reportFilters.industry) {
+          this.reportFilters.industry[key].forEach(function (item) {
+            industry.push(key + '_' + item)
+          })
+        }
+        this.filters.industry = industry
+      }
+      if (data.buyerclass) {
+        this.reportFilters.buyerclass = data.buyerclass.split(',')
+        this.filters.buyerclass = this.reportFilters.buyerclass
+      }
+    },
+    // 市场概况
+    sortMarketOverview (profile) {
+      if (!profile) return
+      const list = [
+        {
+          label: '项目总数',
+          unit: '个',
+          count: 0,
+          ringRatio: 0
+        },
+        {
+          label: '项目总金额',
+          unit: '万元',
+          count: 0,
+          ringRatio: 0
+        },
+        {
+          label: '项目平均金额',
+          unit: '万元',
+          count: 10.04,
+          ringRatio: 0
+        },
+        {
+          label: '中标单位数',
+          unit: '家',
+          count: 10628,
+          ringRatio: 0
+        },
+        {
+          label: '采购单位数',
+          unit: '家',
+          count: 16215,
+          ringRatio: 0
+        }
+      ]
+
+      // 项目总数
+      list[0].count = profile.project_count ? profile.project_count : 0
+      list[0].ringRatio = profile.project_count_ratio ? (profile.project_count_ratio * 100).toFixed(2) : 0
+      // 项目总金额
+      const projectTotalMoney = this.moneyUnit(profile.projctamout ? profile.projctamout : 0)
+      list[1].count = projectTotalMoney.count
+      list[1].unit = projectTotalMoney.unit
+
+      list[1].ringRatio = profile.projctamount_ratio ? (profile.projctamount_ratio * 100).toFixed(2) : 0
+      // 项目平均金额
+      const projectAvgMoney = this.moneyUnit(profile.projectavgmoney ? profile.projectavgmoney : 0)
+      list[2].count = projectAvgMoney.count
+      list[2].unit = projectAvgMoney.unit
+      list[2].ringRatio = profile.projectavgmoney_ratio ? (profile.projectavgmoney_ratio * 100).toFixed(2) : 0
+      // 中标单位数
+      list[3].count = profile.winnercount ? profile.winnercount : 0
+      list[3].ringRatio = profile.winnercount_ratio ? (profile.winnercount_ratio * 100).toFixed(2) : 0
+      // 采购单位数
+      list[4].count = profile.buyercount ? profile.buyercount : 0
+      list[4].ringRatio = profile.winnercount_ratio ? (profile.winnercount_ratio * 100).toFixed(2) : 0
+      
+      var totalCount = list.reduce((total, item) => item.count + total, 0)
+
+      if (totalCount) {
+        this.sections.market.overview = list
+      }
+
+      return totalCount
+    },
+    // 时间分布
+    sortTimeScatter (data) {
+      const hasDataM = this.sortTimeScatterData('month', data.month_distribution)
+      const hasDataY = this.sortTimeScatterData('year', data.year_distribution)
+
+      const hasData = hasDataM && hasDataY
+      this.sections.timeScatter.dataAlready = hasData
+    },
+    sortTimeScatterData (type, data) {
+      // columns: ['日期', '项目规模', '环比增长率(%)'],
+      // rows: [
+      //   {
+      //     日期: '6月',
+      //     项目规模: 0,
+      //     '环比增长率(%)': -99
+      //   },
+      //   {
+      //     日期: '7月',
+      //     项目规模: 736325,
+      //     '环比增长率(%)': 0
+      //   },
+      // ]
+
+      if (!data) return
+
+      // 项目数量
+      const mDCount = {
+        columns: ['日期', '项目数量(个)', '项目数量环比'],
+        rows: []
+      }
+      let mDCountTotal = 0
+      if (Array.isArray(data.project_count)) {
+        const field = {
+          [mDCount.columns[0]]: 'minth',
+          [mDCount.columns[1]]: 'value',
+          [mDCount.columns[2]]: 'ratio'
+        }
+        data.project_count.forEach(item => {
+          const row = {}
+          mDCount.columns.forEach(column => {
+            var value = item[field[column]]
+            if (value) {
+              if (field[column] === 'ratio') {
+                row[column] = utils.formatMoney(value * 100, undefined, true) - 0
+              } else {
+                row[column] = value
+              }
+            } else {
+              row[column] = null
+            }
+
+            if (typeof value === 'number') {
+              mDCountTotal += value
+            }
+          })
+          mDCount.rows.push(row)
+        })
+      }
+
+      if (mDCountTotal || isNaN(mDCountTotal)) {
+        this.$set(this.sections.timeScatter[type], 'count', mDCount)
+      }
+
+      // 项目规模
+      const mDAmount = {
+        columns: ['日期', '项目金额', '项目金额环比'],
+        rows: []
+      }
+      let mDAmuntTotal = 0
+      if (Array.isArray(data.project_amount)) {
+        // 求金额平均值,计算单位
+        const avg = data.project_amount.reduce((prev, current) => current.value + prev, 0) / data.project_amount.length
+        mDAmount.columns[1] += `(${this.moneyUnit(avg).unit})` // 得到单位
+        const field = {
+          [mDAmount.columns[0]]: 'minth',
+          [mDAmount.columns[1]]: 'value',
+          [mDAmount.columns[2]]: 'ratio'
+        }
+        data.project_amount.forEach(item => {
+          const row = {}
+          mDAmount.columns.forEach(column => {
+            const value = item[field[column]]
+            if (value) {
+              if (field[column] === 'value') {
+                // 把所有值的单位都转换为坐标上显示的单位
+                const mUint = this.moneyUnit(value).unit
+                row[column] = this.moneyUnit(value, 'transfer', mUint).count
+              } else if (field[column] === 'ratio') {
+                row[column] = utils.formatMoney(value * 100, undefined, true)
+              } else {
+                row[column] = value
+              }
+            } else {
+              row[column] = null
+            }
+
+            if (typeof value === 'number') {
+              mDAmuntTotal += value
+            }
+          })
+          mDAmount.rows.push(row)
+        })
+      }
+
+      if (mDAmuntTotal || !isNaN(mDAmuntTotal)) {
+        this.$set(this.sections.timeScatter[type], 'amount', mDAmount)
+      }
+
+      const r = !!(mDCountTotal + mDAmuntTotal)
+      const hasOneNaN = isNaN(mDCountTotal) || isNaN(mDAmuntTotal)
+      return hasOneNaN || r
+    },
+    // 项目规模分布
+    sortProjectScatter (data) {
+      // const chartData = {
+      //   columns: ['项目规模', '项目总金额占比', '项目总数占比'],
+      //   rows: [
+      //     {
+      //       项目规模: '≥1亿',
+      //       项目总金额占比: 20,
+      //       项目总数占比: 10
+      //     },
+      //     {
+      //       项目规模: '1000万-1亿',
+      //       项目总金额占比: 50,
+      //       项目总数占比: 40
+      //     },
+      //     {
+      //       项目规模: '500万-1000万',
+      //       项目总金额占比: 20,
+      //       项目总数占比: 30
+      //     },
+      //     {
+      //       项目规模: '100万-500万',
+      //       项目总金额占比: 20,
+      //       项目总数占比: 30
+      //     }
+      //   ]
+      // }
+
+      const scaleList = data
+      const scaleData = {
+        columns: ['项目规模', '项目总金额占比', '项目总数占比'],
+        rows: []
+      }
+      let total = 0
+
+      if (scaleList && Array.isArray(scaleList)) {
+        const field = {
+          [scaleData.columns[0]]: 'Name',
+          [scaleData.columns[1]]: 'Persent_c',
+          [scaleData.columns[2]]: 'Persent_a'
+        }
+        scaleList.forEach(item => {
+          const row = {}
+          scaleData.columns.forEach(column => {
+            if (field[column] === 'Persent_c' || field[column] === 'Persent_a') {
+              row[column] = (item[field[column]] * 100).toFixed(2)
+              total += (item[field[column]] - 0)
+            } else {
+              row[column] = item[field[column]]
+            }
+          })
+          scaleData.rows.push(row)
+        })
+      }
+
+      if (total) {
+        this.$set(this.sections.projectScatter, 'chartData', scaleData)
+        if (this.sections.projectScatter.tableData.length) {
+          this.sections.projectScatter.dataAlready = true
+        }
+      }
+    },
+    // 项目规模Top10
+    sortProjectTop10 (top10List) {
+      if (!Array.isArray(top10List)) return
+
+      this.sections.projectScatter.tableData = top10List.map(top => {
+        let winners = top.winner_s ? top.winner_s.join(',') : ''
+        if (!winners) {
+          winners = []
+        } else {
+          winners = top.winner_s
+        }
+
+        winners = winners.map((item, index) => {
+          return {
+            name: item,
+            id: Array.isArray(top.eidlist) ? top.eidlist[index] : null
+          }
+        })
+
+        top.area = top.area ? top.area : ''
+        top.city = top.city ? top.city : ''
+        top.sortprice = top.sortprice ? utils.formatMoney(top.sortprice / 10000, undefined, true) : ''
+        top.jgtime = top.jgtime ? dateFormatter(top.jgtime * 1000, 'yyyy-MM-dd') : ''
+        top.winner_s = winners
+
+        return top
+      })
+
+      if (this.sections.projectScatter.chartData) {
+        this.sections.projectScatter.dataAlready = true
+      }
+    },
+    // 地区规模分布
+    sortAreaScatter (areaList) {
+      // const chartData = {
+      //   columns: ['项目所在地', '项目数量', '项目金额'],
+      //   rows: [
+      //     {
+      //       项目所在地: '河南',
+      //       项目数量: 2,
+      //       项目金额: 2222
+      //     },
+      //     {
+      //       项目所在地: '北京',
+      //       项目数量: 22,
+      //       项目金额: 565666
+      //     },
+      //     {
+      //       项目所在地: '浙江',
+      //       项目数量: 22,
+      //       项目金额: 765666
+      //     }
+      //   ]
+      // }
+
+      const areaChartData = {
+        columns: ['项目所在地', '项目数量'],
+        sColumns: ['项目金额'],
+        rows: []
+      }
+      let total = 0
+
+      if (areaList && Array.isArray(areaList)) {
+        const field = {
+          [areaChartData.columns[0]]: 'area',
+          [areaChartData.columns[1]]: 'total',
+          [areaChartData.sColumns[0]]: 'amount'
+        }
+        areaList.forEach(item => {
+          const row = {}
+          areaChartData.columns.concat(areaChartData.sColumns).forEach(column => {
+            if (field[column] === 'amount') {
+              row[column] = utils.formatMoney(item[field[column]] / 10000, undefined, true) - 0
+            } else {
+              row[column] = item[field[column]]
+            }
+
+            if (field[column] === 'amount' || field[column] === 'total') {
+              total += (item[field[column]] - 0)
+            }
+          })
+          areaChartData.rows.push(row)
+        })
+      }
+
+      if (total) {
+        this.$set(this.sections.areaScatter, 'chartData', areaChartData)
+        this.sections.areaScatter.dataAlready = true
+      }
+    },
+    // 客户分布
+    sortUserScatter (userList) {
+      if (Array.isArray(userList)) {
+        this.sections.userScatter.list = userList.map(item => {
+          item.name = item.buyclass
+          item.value = item.total
+          item.amount = utils.formatMoney(item.amount / 10000, undefined, true)
+          return item
+        })
+      }
+    },
+    // 地区分布及客户分布Top3
+    sortAreaUserTop3 (data) {
+      if (data.scaleAreaCountTop || data.scaleAreaAmountTop) {
+        this.sorAreaTop3(data)
+      }
+      if (data.scaleBuyclassCountTop || data.scaleBuyclassAmountTop) {
+        this.sorUserTop3(data)
+      }
+    },
+    sorAreaTop3 (data) {
+      const tableDataCount = {
+        columns: ['序号', '地区:项目数量(个),占比', '前3中标单位:中标数量(个)'], // ,该地区占比
+        rows: []
+      }
+      const tableDataAmount = {
+        columns: ['序号', '地区:项目金额(万元),占比', '前3中标单位:中标金额(万元)'], // ,该地区占比
+        rows: []
+      }
+
+      const scaleAreaCountTop3 = data.scaleAreaCountTop
+      if (Array.isArray(scaleAreaCountTop3)) {
+        scaleAreaCountTop3.forEach((item, index) => {
+          item.name = item.name
+          item.subInfo1 = item.area_count ? `项目数量:${item.area_count}个` : ''
+          item.subInfo2 = item.area_scale ? `全国占比:${utils.formatMoney(item.area_scale * 100, undefined, true)}%` : ''
+          item.actionText = `中标单位 TOP3`
+          item.childrenShow = true
+          item.children = []
+          if (Array.isArray(item.winner)) {
+            item.winner.forEach((w, i) => {
+              const row = {
+                name: w.winner,
+                id: w.id,
+                type: 'winner',
+                subInfo1: w.winner_total ? `中标个数:${w.winner_total}个` : '',
+                // subInfo2: w.total_scale ? `地区占比:${utils.formatMoney(w.total_scale * 100, undefined, true)}%` : 0
+              }
+              item.children.push(row)
+            })
+          }
+        })
+        tableDataCount.rows = scaleAreaCountTop3
+      }
+
+      const scaleAreaAmountTop3 = data.scaleAreaAmountTop
+      if (Array.isArray(scaleAreaAmountTop3)) {
+        scaleAreaAmountTop3.forEach((item, index) => {
+          item.name = item.name
+          item.subInfo1 = item.area_amount ? `中标金额:${utils.formatMoney(item.area_amount / 10000, undefined, true)}万元` : ''
+          item.subInfo2 = item.area_scale ? `全国占比:${utils.formatMoney(item.area_scale * 100, undefined, true)}%` : ''
+          item.actionText = `中标单位 TOP3`
+          item.childrenShow = true
+          item.children = []
+          if (Array.isArray(item.winner)) {
+            item.winner.forEach((w, i) => {
+              const row = {
+                name: w.winner,
+                id: w.id,
+                type: 'winner',
+                subInfo1: w.winner_amount ? `中标金额:${utils.formatMoney(w.winner_amount / 10000, undefined, true)}万元` : '',
+                // subInfo2: w.amount_scale ? `地区占比:${utils.formatMoney(w.amount_scale * 100, undefined, true)}%` : ''
+              }
+              item.children.push(row)
+            })
+          }
+        })
+        tableDataAmount.rows = scaleAreaAmountTop3
+      }
+
+      if (tableDataCount.rows.length) {
+        this.$set(this.sections.areaScatter, 'projectCountTop3', tableDataCount.rows)
+      }
+      if (tableDataAmount.rows.length) {
+        this.$set(this.sections.areaScatter, 'projectAmountTop3', tableDataAmount.rows)
+      }
+    },
+    sorUserTop3 (data) {
+      const tableDataCount = {
+        columns: ['序号', '客户类型:项目数量(个),占比', '前3中标单位:中标数量(个)'], // ,该客户类型占比
+        rows: []
+      }
+      const tableDataAmount = {
+        columns: ['序号', '客户类型:项目金额(万元),占比', '前3中标单位:中标金额(万元)'], // ,该客户类型占比
+        rows: []
+      }
+
+      const countTop3 = data.scaleBuyclassCountTop
+      if (Array.isArray(countTop3)) {
+        countTop3.forEach((item, index) => {
+          item.name = item.name
+          item.subInfo1 = item.buyclass_count ? `项目数量:${item.buyclass_count}个` : ''
+          item.subInfo2 = item.buyclass_scale ? `全部占比:${utils.formatMoney(item.buyclass_scale * 100, undefined, true)}%` : ''
+          item.actionText = `中标单位 TOP3`
+          item.childrenShow = true
+          item.children = []
+
+          if (Array.isArray(item.winner)) {
+            item.winner.forEach((w, i) => {
+              const row = {
+                name: w.winner,
+                id: w.id,
+                type: 'winner',
+                subInfo1: w.winner_total ? `中标个数:${w.winner_total}个` : '',
+                // subInfo2: w.total_scale ? `该行业占比:${utils.formatMoney(w.total_scale * 100, undefined, true)}%` : ''
+              }
+              item.children.push(row)
+            })
+          }
+        })
+        tableDataCount.rows = countTop3
+      }
+
+      const amountTop3 = data.scaleBuyclassAmountTop
+      if (Array.isArray(amountTop3)) {
+        amountTop3.forEach((item, index) => {
+          item.name = item.name
+          item.subInfo1 = item.buyclass_amount ? `项目金额:${utils.formatMoney(item.buyclass_amount / 10000, undefined, true)}万元` : ''
+          item.subInfo2 = item.buyclass_scale ? `全部占比:${utils.formatMoney(item.buyclass_scale * 100, undefined, true)}%` : 0
+          item.actionText = `中标单位 TOP3`
+          item.childrenShow = true
+          item.children = []
+          if (Array.isArray(item.winner)) {
+            item.winner.forEach((w, i) => {
+              const row = {
+                name: w.winner,
+                id: w.id,
+                type: 'winner',
+                subInfo1: w.winner_amount ? `中标金额:${utils.formatMoney(w.winner_amount / 10000, undefined, true)}万元` : '',
+                // subInfo2: w.amount_scale ? `该行业占比:${utils.formatMoney(w.amount_scale * 100, undefined, true)}%` : ''
+              }
+              item.children.push(row)
+            })
+          }
+        })
+        tableDataAmount.rows = amountTop3
+      }
+
+      if (tableDataCount.rows.length) {
+        this.$set(this.sections.userScatter, 'projectCountTop3', tableDataCount.rows)
+      }
+      if (tableDataAmount.rows.length) {
+        this.$set(this.sections.userScatter, 'projectAmountTop3', tableDataAmount.rows)
+      }
+    },
+    // 细分市场
+    sortMarketRefineData (data) {
+      const refineCount = {
+        columns: ['行业', '项目数量'],
+        rows: []
+      }
+      const refineAmount = {
+        columns: ['行业', '项目金额'],
+        rows: []
+      }
+      let total = 0
+      const refineAll = data.scaleRefineAll
+      if (Array.isArray(refineAll)) {
+        const field = {
+          行业: 'name',
+          项目数量: 'total',
+          项目金额: 'amount'
+        }
+        refineAll.forEach(item => {
+          const row = {}
+          for (const key in field) {
+            if (field[key] === 'amount') {
+              row[key] = utils.formatMoney(item[field[key]] / 10000, undefined, true)
+            } else {
+              row[key] = item[field[key]]
+            }
+
+            if (field[key] === 'total' || field[key] === 'amount') {
+              total += (item[field[key]] - 0)
+            }
+          }
+          refineCount.rows.push(row)
+          refineAmount.rows.push(row)
+        })
+      }
+
+      if (total) {
+        this.$set(this.sections.market.refine, 'projectCountData', refineCount)
+        this.$set(this.sections.market.refine, 'projectAmountData', refineAmount)
+
+        this.sections.market.refine.dataAlready = true
+      }
+      
+      this.sortRefineTop3(data)
+    },
+    sortRefineTop3 (data) {
+      const tableDataCount = {
+        columns: ['序号', '细分市场:项目数量(个)', '前3中标单位:中标数量(个)'], // ,占比,该细分市场占比
+        rows: []
+      }
+      const tableDataAmount = {
+        columns: ['序号', '细分市场:项目金额(万元)', '前3中标单位:中标金额(万元)'], // ,占比,该细分市场占比
+        rows: []
+      }
+
+      const countTop3 = data.scaleRefineTotalTop
+      if (Array.isArray(countTop3)) {
+        countTop3.forEach((item, index) => {
+          item.name = item.name
+          item.subInfo1 = item.value ? `项目数量:${item.value}个` : ''
+          // item.subInfo2 = item.prop ? `全部占比:${utils.formatMoney(item.prop * 100, undefined, true)}%` : 0
+          item.actionText = `中标单位 TOP3`
+          item.childrenShow = true
+          item.children = []
+          if (Array.isArray(item.topList)) {
+            item.topList.forEach((w, i) => {
+              const row = {
+                name: w.name,
+                id: w.id,
+                type: 'winner',
+                subInfo1: w.value ? `中标个数:${w.value}个` : '',
+                // subInfo2: w.prop ? `该细分市场占比:${utils.formatMoney(w.prop * 100, undefined, true)}%` : ''
+              }
+              item.children.push(row)
+            })
+          }
+        })
+        tableDataCount.rows = countTop3
+      }
+
+      const amountTop3 = data.scaleRefineAmountTop
+      if (Array.isArray(amountTop3)) {
+        amountTop3.forEach((item, index) => {
+          item.name = item.name
+          item.subInfo1 = item.value ? `项目金额:${utils.formatMoney(item.value / 10000, undefined, true)}万元` : ''
+          // item.subInfo2 = item.prop ? `全部占比:${utils.formatMoney(item.prop * 100, undefined, true)}%` : 0
+          item.actionText = `中标单位 TOP3`
+          item.childrenShow = true
+          item.children = []
+          if (Array.isArray(item.topList)) {
+            item.topList.forEach((w, i) => {
+              const row = {
+                name: w.name,
+                id: w.id,
+                type: 'winner',
+                subInfo1: w.value ? `中标金额:${utils.formatMoney(w.value / 10000, undefined, true)}万元` : '',
+                // subInfo2: w.prop ? `该细分市场占比:${utils.formatMoney(w.prop * 100, undefined, true)}%`: ''
+              }
+              item.children.push(row)
+            })
+          }
+        })
+        tableDataAmount.rows = amountTop3
+      }
+
+      if (tableDataCount.rows.length) {
+        this.$set(this.sections.market.refine, 'projectCountTop3', tableDataCount.rows)
+      }
+      if (tableDataAmount.rows.length) {
+        this.$set(this.sections.market.refine, 'projectAmountTop3', tableDataAmount.rows)
+      }
+    },
+    // 采购单位
+    sortBuyerclassData (data) {
+      const buyerclassChartData = {
+        columns: ['金额区间', '采购总金额占比', '采购单位数量占比'],
+        rows: []
+      }
+      let total = 0
+
+      const buyerclassList = data.buyer_time_distribution
+      if (Array.isArray(buyerclassList)) {
+        const field = {
+          [buyerclassChartData.columns[0]]: 'key',
+          [buyerclassChartData.columns[1]]: 'total_amount',
+          [buyerclassChartData.columns[2]]: 'total_number'
+        }
+        buyerclassList.forEach(item => {
+          const row = {}
+          buyerclassChartData.columns.forEach(column => {
+            if (field[column] === 'total_amount' || field[column] === 'total_number') {
+              row[column] = (item[field[column]] * 100).toFixed(2)
+              total += (item[field[column]] - 0)
+            } else {
+              row[column] = item[field[column]]
+            }
+          })
+          buyerclassChartData.rows.push(row)
+        })
+      }
+
+      if (total) {
+        buyerclassChartData.rows.reverse()
+        this.$set(this.sections.buyerclass, 'chartData', buyerclassChartData)
+
+        this.sections.buyerclass.dataAlready = true
+      }
+      
+      this.sortBuyerclassTableData(data)
+    },
+    sortBuyerclassTableData (data) {
+      const dataCount = {
+        columns: ['序号', '采购单位:采购数量(个)', '前3中标单位:中标数量(个)'], //,占比 |  ,占该采购单位
+        rows: []
+      }
+      const dataAmount = {
+        columns: ['序号', '采购单位:采购金额(万元)', '前3中标单位:中标金额(万元)'], //,占比 |  ,占该采购单位
+        rows: []
+      }
+
+      const countTop3 = data.buyer_count_top3
+      if (Array.isArray(countTop3)) {
+        countTop3.forEach((item, index) => {
+          item.name = item.name
+          item.type = 'buyer'
+          item.id = item.name
+          item.subInfo1 = item.number ? `项目数量:${item.number}个` : ''
+          // item.subInfo2 = item.accounted ? `全部占比:${utils.formatMoney(item.accounted * 100, undefined, true)}%` : ''
+          item.actionText = `中标单位 TOP3`
+          item.childrenShow = true
+          item.children = []
+          if (Array.isArray(item.winnertop3)) {
+            item.winnertop3.forEach((w, i) => {
+              const row = {
+                name: w.name,
+                id: w.id,
+                type: 'winner',
+                subInfo1: w.number ? `中标个数:${w.number}个` : '',
+                // subInfo2: w.accounted ? `占该采购单位:${utils.formatMoney(w.accounted * 100, undefined, true)}%` : ''
+              }
+              item.children.push(row)
+            })
+          }
+        })
+        dataCount.rows = countTop3
+      }
+
+      const amountTop3 = data.buyer_amount_top3
+      if (Array.isArray(amountTop3)) {
+        amountTop3.forEach((item, index) => {
+          item.name = item.name
+          item.type = 'buyer'
+          item.id = item.name
+          item.subInfo1 = item.amount ? `采购金额:${utils.formatMoney(item.amount / 10000, undefined, true)}万元` : ''
+          // item.subInfo2 = item.accounted ? `全部占比:${utils.formatMoney(item.accounted * 100, undefined, true)}%` : ''
+          item.actionText = `中标单位 TOP3`
+          item.childrenShow = true
+          item.children = []
+          if (Array.isArray(item.winnertop3)) {
+            item.winnertop3.forEach((w, i) => {
+              const row = {
+                name: w.name,
+                id: w.id,
+                type: 'winner',
+                subInfo1: w.amount ? `中标金额:${utils.formatMoney(w.amount / 10000, undefined, true)}万元` : '',
+                // subInfo2: w.accounted ? `该行业占比:${utils.formatMoney(w.accounted * 100, undefined, true)}%` : ''
+              }
+              item.children.push(row)
+            })
+          }
+        })
+        dataAmount.rows = amountTop3
+      }
+      if (dataCount.rows.length) {
+        this.$set(this.sections.buyerclass, 'projectCountTop3', dataCount.rows)
+      }
+      if (dataAmount.rows.length) {
+        this.$set(this.sections.buyerclass, 'projectAmountTop3', dataAmount.rows)
+      }
+    },
+    // 中标单位
+    sortWinnerData (data) {
+      const chartData = {
+        columns: ['金额区间', '中标总金额占比', '中标单位数量占比'],
+        rows: []
+      }
+      let total = 0
+
+      const chartLIst = data.winner_time_distribution
+      if (Array.isArray(chartLIst)) {
+        const field = {
+          [chartData.columns[0]]: 'key',
+          [chartData.columns[1]]: 'total_amount',
+          [chartData.columns[2]]: 'total_number'
+        }
+        chartLIst.forEach(item => {
+          const row = {}
+          chartData.columns.forEach(column => {
+            if (field[column] === 'total_amount' || field[column] === 'total_number') {
+              row[column] = (item[field[column]] * 100).toFixed(2)
+              total += (item[field[column]] - 0)
+            } else {
+              row[column] = item[field[column]]
+            }
+          })
+          chartData.rows.push(row)
+        })
+      }
+
+      if (total) {
+        chartData.rows.reverse()
+        this.$set(this.sections.winner, 'chartData', chartData)
+
+        this.sections.winner.dataAlready = true
+      }
+
+      this.sortWinnerTableData(data)
+    },
+    sortWinnerTableData (data) {
+      const dataCount = {
+        columns: ['序号', '中标单位:中标数量(个)', '前3采购单位:采购数量(个)'], // ,占比 | ,占该中标单位
+        rows: []
+      }
+      const dataAmount = {
+        columns: ['序号', '中标单位:中标金额(万元),占比', '前3采购单位:采购金额(万元),占该中标单位'], // ,占比 | ,占该中标单位
+        rows: []
+      }
+
+      const countTop3 = data.winner_count_top3
+      if (Array.isArray(countTop3)) {
+        countTop3.forEach((item, index) => {
+          item.name = item.name
+          item.type = 'winner'
+          item.id = item.id
+          item.subInfo1 = item.number ? `中标数量:${item.number}个` : ''
+          // item.subInfo2 = item.accounted ? `全部占比:${utils.formatMoney(item.accounted * 100, undefined, true)}%` : ''
+          item.actionText = `采购单位 TOP3`
+          item.childrenShow = true
+          item.children = []
+          if (Array.isArray(item.buyertop3)) {
+            item.buyertop3.forEach((w, i) => {
+              const row = {
+                name: w.name,
+                id: w.name,
+                type: 'buyer',
+                subInfo1: w.number ? `采购数量:${w.number}个` : '',
+                // subInfo2: w.accounted ? `占该中标单位:${utils.formatMoney(w.accounted * 100, undefined, true)}%` : ''
+              }
+              item.children.push(row)
+            })
+          }
+        })
+        dataCount.rows = countTop3
+      }
+
+      const amountTop3 = data.winner_amount_top3
+      if (Array.isArray(amountTop3)) {
+        amountTop3.forEach((item, index) => {
+          item.name = item.name
+          item.type = 'winner'
+          item.id = item.id
+          item.subInfo1 = item.amount ? `中标金额:${utils.formatMoney(item.amount / 10000, undefined, true)}万元` : ''
+          // item.subInfo2 = item.accounted ? `全部占比:${utils.formatMoney(item.accounted * 100, undefined, true)}%` : ''
+          item.actionText = `采购单位 TOP3`
+          item.childrenShow = true
+          item.children = []
+          if (Array.isArray(item.buyertop3)) {
+            item.buyertop3.forEach((w, i) => {
+              const row = {
+                name: w.name,
+                id: w.name,
+                type: 'buyer',
+                subInfo1: w.amount ? `采购金额:${utils.formatMoney(w.amount / 10000, undefined, true)}万元` : '',
+                // subInfo2: w.accounted ? `占该中标单位:${utils.formatMoney(w.accounted * 100, undefined, true)}%` : ''
+              }
+              item.children.push(row)
+            })
+          }
+        })
+        dataAmount.rows = amountTop3
+      }
+
+      if (dataCount.rows.length) {
+        this.$set(this.sections.winner, 'projectCountTop3', dataCount.rows)
+      }
+      if (dataAmount.rows.length) {
+        this.$set(this.sections.winner, 'projectAmountTop3', dataAmount.rows)
+      }
+    },
+    toAnalysisPage: function () {
+      this.rid = ''
+      this.analysis.loaded = false
+      this.filtersPageShow = true
+    },
+    moneyUnit (num, type, lv) {
+      const m = utils.moneyUnit(num, type, lv)
+      let unit = String(m).match(/[\u4e00-\u9fa5]/g)
+      if (unit && Array.isArray(unit)) {
+        unit = unit.join('')
+      } else {
+        unit = ''
+      }
+      let count = ''
+      if (unit) {
+        count = m.replace(unit, '') - 0
+      }
+      return {
+        unit,
+        count
+      }
+    },
+    anchorTo (item) {
+      if (!item.top) return
+      var offsetTop = item.top || 0
+      this.activeDimension = item.id
+      this.$nextTick(function () {
+        $('.search-result > .j-main')[0].scrollTop = offsetTop
+      })
+    },
+    showSetKeyTip: function () {
+      this.notSetKey = true
+    },
+    setKeyTip: function () {
+      this.showDialog({
+        title: '',
+        message: '分析内容为您订阅的关键词组,您<br />当前尚未订阅,请前往完善',
+        className: 'j-confirm-dialog text-center',
+        showConfirmButton: true,
+        showCancelButton: true,
+        confirmButtonText: '订阅管理',
+        confirmButtonColor: '#2abed1'
+      }).then(() => {
+        if (this.isSubCount) {
+          // 提示联系管理员
+          this.showToast('请联系管理员完善订阅的关键词')
+          // this.showDialog({
+          //   title: '',
+          //   message: '请联系管理员完善订阅的关键词',
+          //   className: 'j-confirm-dialog text-center',
+          //   showConfirmButton: true,
+          //   showCancelButton: false,
+          //   confirmButtonText: '我知道了',
+          //   confirmButtonColor: '#2abed1'
+          // })
+        } else {
+          this.toSubManage()
+        }
+      })
+    },
+    toSubManageButtonClick: function () {
+      if (this.isSubCount) {
+        this.showToast('请联系管理员完善订阅的关键词')
+      } else {
+        this.toSubManage()
+      }
+    },
+    toSubManage: function () {
+      location.href = '/jyapp/vipsubscribe/toSetKeyWordPage'
+    },
+    toArticleContent (item) {
+      this.saveState()
+      location.href = `/jyapp/article/content/${item._id}.html`
+    },
+    toPortrait (id, type) {
+      if (!type || !id) return
+      this.saveState()
+      if (type === 'winner') {
+        location.href = `./ent_portrait?eId=${id}`
+      } else if (type === 'buyer') {
+        location.href = `./unit_portrayal?entName=${id}`
+      }
+    }
+  }
+})

+ 222 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/report_analysis_history.js

@@ -0,0 +1,222 @@
+var vm = new Vue({
+  delimiters: ['${', '}'],
+  el: '#analysis',
+  components: {
+    reportListMobileComponent: reportListMobileComponent
+  },
+  data: {
+    sessStorageKey: '$data-report_analysis_history',
+    tabActiveName: 'history', // analysis/history
+    tabList: [
+      {
+        label: '定制化市场分析',
+        name: 'analysis'
+      },
+      {
+        label: '历史报告',
+        name: 'history'
+      }
+    ],
+    tabConf: {
+      titleActiveColor: '#2ABED1',
+      titleInactiveColor: '#5F5E64',
+      lineWidth: '24',
+      color: '#2ABED1'
+    },
+    historyPageState: {
+      scrollTop: 0,
+      listState: {
+        refreshing: false,
+        loaded: false,
+        loading: false,
+        finished: false,
+        pageNum: 1,
+        pageSize: 10,
+        offset: 100,
+        list: []
+      }
+    }
+  },
+  computed: {
+    tabActive: function () {
+      var _this = this
+      var active = {}
+      this.tabList.some(function (item) {
+        var findThis = item.name === _this.tabActiveName
+        if (findThis)  {
+          active = item
+          return findThis
+        }
+      })
+      return active
+    }
+  },
+  created: function () {},
+  mounted: function () {
+    this.reStoreState()
+    utils.iosBackRefresh()
+  },
+  methods: {
+    showLoading: function () {
+      return this.$toast.loading({
+        duration: 0,
+        forbidClick: true,
+        message: 'loading...',
+      })
+    },
+    showToast: function (message) {
+      return this.$toast({
+        duration: 1500,
+        forbidClick: true,
+        message: message,
+      })
+    },
+    showDialog: function (conf) {
+      var defaultConf = {
+        title: '提示',
+        message: 'message',
+        className: 'j-confirm-dialog',
+        showConfirmButton: true,
+        showCancelButton: true,
+        confirmButtonText: '确定',
+        confirmButtonColor: '#2abed1'
+      }
+      if (conf) {
+        Object.assign(defaultConf, conf)
+      }
+      return this.$dialog.confirm(defaultConf)
+    },
+    setScrollTop: function (scrollTop) {
+      this.$nextTick(function () {
+        var wrapper = document.querySelector('.van-tabs__content')
+        wrapper.scrollTop = scrollTop
+      })
+    },
+    saveScrollTop: function () {
+      var wrapper = document.querySelector('.van-tabs__content')
+      if (wrapper.scrollTop) {
+        this.historyPageState.listState.scrollTop = parseInt(wrapper.scrollTop)
+      }
+    },
+    beforeTabChange: function (name) {
+      if (name !== this.tabActiveName) {
+        this.saveState()
+        this.goToAnalysis()
+      }
+      return false
+    },
+    goToAnalysis: function (id) {
+      var href = './report_analysis'
+      if (id) {
+        href += ('?id=' + id)
+      }
+      location.replace(href)
+    },
+    // 重置列表数据
+    resetHistoryState: function () {
+      var rState = {
+        refreshing: false,
+        loaded: false,
+        loading: false,
+        finished: false,
+        pageNum: 1,
+        pageSize: 10,
+        list: []
+      }
+
+      this.historyPageState.scrollTop = 0
+      Object.assign(this.historyPageState.listState, rState)
+    },
+    // 加载历史记录数据
+    onHistoryListLoad: function () {
+      var _this = this
+      var t = this.historyPageState.listState
+      var query = {
+        pageNum: t.pageNum,
+        pageSize: t.pageSize
+      }
+
+      t.loading = true
+
+      $.ajax({
+        type: 'POST',
+        url: '/bigmember/marketAnalysis/analysisHistory?t=' + Date.now(),
+        data: query,
+        success: function (res) {
+          if (res) {
+            // 判断是否为刷新
+            if (t.refreshing) {
+              t.list = []
+              t.refreshing = false
+            }
+
+            // 列表赋值
+            var list = res.res
+            if (Array.isArray(list)) {
+              _this.preSortList(list)
+              t.list = t.list.concat(list)
+            }
+
+            // 加载状态结束
+            t.loaded = true
+            t.loading = false
+
+            // 翻页
+            if (res.hasNextPage) {
+              t.pageNum++
+            } else {
+              t.finished = true
+            }
+          } else {
+            t.loaded = true
+            t.loading = false
+            t.finished = true
+            _this.$toast('请求失败')
+          }
+        },
+        error: function (error) {
+          console.log(error)
+        }
+      })
+    },
+    // 刷新历史记录数据
+    onHistoryListRefresh: function () {
+      var t = this.historyPageState.listState
+      // 重置数据
+      t.pageNum = 1
+      // 解除加载完成状态
+      t.finished = false
+      // 重新加载数据
+      // 将 loading 设置为 true,表示处于加载状态
+      t.loading = true
+      // 请求数据
+      this.onHistoryListLoad()
+    },
+    // 保存页面状态
+    saveState: function () {
+      this.saveScrollTop()
+      var $data = {
+        historyPageState: this.historyPageState
+      }
+      sessionStorage.setItem(this.sessStorageKey, JSON.stringify($data))
+    },
+    reStoreState: function () {
+      var $data = sessionStorage.getItem(this.sessStorageKey)
+      if ($data) {
+        $data = JSON.parse($data)
+        Object.assign(this.historyPageState, $data.historyPageState)
+
+        if (this.tabActiveName === 'history') {
+          setTimeout(function () {
+            // 恢复滚动高度
+            this.setScrollTop(this.historyPageState.scrollTop)
+          }.bind(this), 0)
+        }
+
+        sessionStorage.removeItem(this.sessStorageKey)
+      }
+
+      return $data
+    }
+  }
+})

+ 26 - 3
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/unit_portrayal.js

@@ -132,7 +132,8 @@ var vNode = {
               visited: false,
               surplus: 0
             }, // 超级订阅用户画像浏览
-            freeTrial: false // 免费用户是否访问过当前画像
+            freeTrial: false, // 免费用户是否访问过当前画像
+            bannerTop: 0
         }
     },
     computed: {
@@ -187,7 +188,7 @@ var vNode = {
         // 展示超级订阅浏览次数
         superVipPort: function () {
           console.log(this.userInfo.vipStatus, this.userInfo.viper)
-          return this.userInfo.vipStatus > 0 && this.userInfo.viper && this.bigStatus <= 0
+          return this.userInfo.vipStatus > 0 && this.userInfo.viper && this.power.indexOf(5) ==  -1
         },
         // 超级订阅用户对应的按钮
         superVipBtnText: function () {
@@ -198,6 +199,10 @@ var vNode = {
             text = '前往升级'
           }
           return text 
+        },
+        // 留完资的用户(保含已体验和未体验的)
+        getfreeBuyerOpen: function () {
+          return this.userInfo.isFree && this.userInfo.freeBuyerPort != 0;
         }
     },
     watch: {
@@ -222,6 +227,11 @@ var vNode = {
         if (!params && storageClick) {
           this.$nextTick(function(){
             document.querySelector('.win-analyse').scrollIntoView()
+            if (this.getfreeBuyerOpen) {
+              $('.win-analyse').css({
+                "margin-top": '1.8rem'
+              })
+            }
             sessionStorage.removeItem('is-click-set')
           })
         }
@@ -244,10 +254,23 @@ var vNode = {
       window.removeEventListener("resize", this.init,20);
     },
     methods: {
+        onUnitScroll: utils.debounce(function () {
+          if (!this.getfreeBuyerOpen) return
+          var scrollTop = this.$refs.container.scrollTop
+          var setRefTop = this.$refs.setRefs.offsetTop
+          if (scrollTop >= setRefTop && this.getfreeBuyerOpen) {
+            $('.win-analyse').css({
+              "margin-top": '.24rem'
+            })
+          }
+        }, 300),
+        goOpenVip: function () {
+          location.href = "/jyapp/vipsubscribe/vipsubscribe_new"
+        },
         // 查询超级订阅采购单位画像浏览次数
         getUsage: function () {
           var _this = this
-          console.log(this.superVipPort)
+          // console.log(this.superVipPort)
           if (this.superVipPort) {
             $.ajax({
               type: 'POST',

+ 32 - 10
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/utils.js

@@ -91,14 +91,15 @@ var popupTip = {
 }
 
 var versionChangeLog = {
-    '0.0.1': 'init',
-    '0.0.2': 'utils.dateFromNow 函数逻辑修改,具体修改内容查看函数注释'
+    '0.0.1': ['init'],
+    '0.0.2': ['utils.dateFromNow 函数逻辑修改,具体修改内容查看函数注释'],
+    '0.0.3': ['utils.formatMoney 新增不使用,分割返回值的选项'],
 }
 
 
 var utils = {
     // utils版本号
-    version: '0.0.2',
+    version: '0.0.3',
     isWeiXinBrowser: navigator.userAgent.toLowerCase().indexOf('micromessenger') !== -1,
     isAndroid: navigator.userAgent.toLowerCase().indexOf('android') !== -1,
     isIos: /iphone|ipod|ipad|ios/.test(navigator.userAgent.toLowerCase()),
@@ -352,9 +353,13 @@ var utils = {
      * 格式化金钱的函数
      * @param {number} s 金额必传
      * @param {int:0-100} n 保留小数的位数(int:0-100)
+     * @param {Boolean} withoutComma 传true则表示不使用,分割返回值
      */
-    formatMoney: function (s, n) {
-        if (n === undefined) {
+    formatMoney: function (s, n, withoutComma) {
+        // 如果不传s或者s为空,则直接返回0
+        if (!s) return 0
+
+        if (n === undefined || n === null) {
             n = -1
         } else {
             n = n > 0 && n <= 20 ? n : 2;
@@ -383,13 +388,16 @@ var utils = {
             right = s.split('.')[1];
         }
 
-        t = '';
-        for (i = 0; i < left.length; i++) {
-            t += left[i] + ((i + 1) % 3 == 0 && (i + 1) != left.length ? ',' : '');
+        // 默认进行,拼接
+        if (!withoutComma) {
+            t = '';
+            for (i = 0; i < left.length; i++) {
+                t += left[i] + ((i + 1) % 3 == 0 && (i + 1) != left.length ? ',' : '');
+            }
+            return t.split('').reverse().join('') + point + right;
         }
 
-        var money = t.split('').reverse().join('') + point + right;
-        return money;
+        return left.reverse().join('') + point + right;;
     },
     // 金额大写,链接:https://juejin.im/post/5a2a7a5051882535cd4abfce
     // upDigit(1682) result:"人民币壹仟陆佰捌拾贰元整"
@@ -690,6 +698,20 @@ var utils = {
             }
         }
 
+        // 需要传入固定的lv(此时lv为 levelArr 中的一个)
+        function transfer (num, lvString) {
+            var index = levelArr.indexOf(lvString)
+            if (index === -1 || index === 0) {
+                return num
+            } else {
+                return (num / Math.pow(10000, index)).toFixed(2) + lvString
+            }
+        }
+
+        if (type === 'transfer') {
+            return transfer(num, lv)
+        }
+
         var result = num / Math.pow(10000, lv);
 
         if (result > 10000 && lv < 2) {

+ 3 - 1
src/jfw/modules/app/src/web/staticres/jyapp/js/historypush.js

@@ -643,7 +643,9 @@ var vm = new Vue({
         var count = data.count
         this.selectAreaList = areaCityRes
         if (!areaCityRes || Object.keys(areaCityRes).length === 0) {
-
+          this.area = ''
+          this.city = ''
+          $('.areaText').html('地区')
         } else {
           var obj = {
             p: [], // 省份全选

+ 22 - 5
src/jfw/modules/app/src/web/staticres/jyapp/me/js/mine.js

@@ -254,11 +254,28 @@ var mine = {
 	                        $('.buyer-follow-history').hide()
                             $('.my-filePackage').hide()
 	                    }
-	                } else {
-	                    $('.ent-follow-history').hide()
-	                    $('.buyer-follow-history').hide()
-
-	                }
+                    } else {
+                        // 有采购单位全景分析权限的 不显示画像记录 没有的判断是否是超级订阅新用户
+                        if (res.data.power && res.data.power.indexOf(5) > -1) {
+                          $('.buyer-follow-history').hide()
+                        } else {
+                          if(res.data.vipStatus > 0 && res.data.viper ) {
+                            $('.buyer-follow-history').show()
+                          } else {
+                              $('.buyer-follow-history').hide()
+                          }
+                        }
+                        // 有企业全景分析权限的 不显示画像记录 没有的判断是否是超级订阅新用户
+                        if (res.data.power && res.data.power.indexOf(4) > -1) {
+                            $('.ent-follow-history').hide()
+                        } else {
+                          if (res.data.vipStatus > 0 && res.data.viper) {
+                            $('.ent-follow-history').show()
+                          } else {
+                            $('.ent-follow-history').hide()
+                          }
+                        }
+                    }
                     if ($.isArray(res.data.power)) {
                         pageUserInfo.power = res.data.power
                         // 大会员没有附加下载包权限用户且新版超级订阅用户

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
src/jfw/modules/app/src/web/templates/big-member/page_contrast.html


+ 8 - 2
src/jfw/modules/app/src/web/templates/big-member/page_ent_portrait.html

@@ -81,7 +81,7 @@
 <body>
   <div class="j-container">
     {{include "/big-member/header.html"}}
-    <div id="ent-portrait" class="j-main" v-cloak>
+    <div id="ent-portrait" class="j-main" v-cloak ref="container"  @scroll="onEntScroll">
       <!-- <van-dialog
         v-model="setShow"
         show-cancel-button
@@ -226,7 +226,7 @@
           <template #title>
             <span :class="{bidinfo:!hasOnePower}">中标分析</span>
             <span v-if="isShowUpTip" class="bid_upgrade">升级</span>
-            <span v-if="isMember && (hasOnePower && surplus && isVip)" class="bid_surplus">剩余:${entvisit.total -
+            <span v-if="(hasOnePower && surplus && isVip)" class="bid_surplus">剩余:${entvisit.total -
               entvisit.usage}</span>
           </template>
           <div v-if="!showContacts" style="margin-top: .24rem;">
@@ -242,6 +242,12 @@
           <div class="bg-white tab-card cell-list history-list" v-else>
             <hispro-component type="winner" :id="entInfo.id"></hispro-component>
           </div>
+          <!-- 留完资的免费用户 已体验和未体验的展示去开通 -->
+          <div v-if="freeWinnerOpen" class="banner-sticky" ref="bannerRef">
+            <!-- <van-sticky offset-top="33.67vw"> -->
+              <img @click="goOpenVip" src="/jyapp/big-member/image/winner-open.png" alt="">
+            <!-- </van-sticky> -->
+          </div>
           <!-- 高级分析 -->
           <div class="win-analyse" ref="setRef">
             <span class="win-bid-title">中标分析</span>

+ 442 - 0
src/jfw/modules/app/src/web/templates/big-member/page_report_analysis.html

@@ -0,0 +1,442 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <!--引入公共资源头部-->
+    {{include "/big-member/meta.html"}}
+    <title>定制化市场分析报告</title>
+    <link rel="stylesheet" href=//cdn-common.jianyu360.com/cdn/lib/reset-css/5.0.1/reset.min.css />
+    <link rel="stylesheet" href=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/index.css />
+    <link rel="stylesheet" href=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/icon/local.css />
+    <link rel="stylesheet" href='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/collection/css/index.css?v={{Msg "seo" "version"}}'/>
+    <link rel="stylesheet" href='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/css/report_analysis.css?v={{Msg "seo" "version"}}' />
+    <style>
+        /* fix: --- 弹窗组件不能显示底部问题  */
+        .report-popup .j-main.unitTab {
+            height: unset;
+        }
+        .collection .unitTab {
+            flex: 1;
+        }
+        /* fix: --- end */
+    </style>
+</head>
+
+<body>
+<div class="j-container">
+    {{include "/big-member/header.html"}}
+    <div class="j-main" id="analysis" v-cloak>
+        <div class="j-container">
+            <van-tabs
+                class="analysis-tab"
+                :title-active-color="tabConf.titleActiveColor"
+                :title-inactive-color="tabConf.titleInactiveColor"
+                :line-width="tabConf.lineWidth"
+                :color="tabConf.color"
+                :before-change="beforeTabChange"
+                v-model="tabActiveName">
+                <van-tab
+                    v-for="(tab, index) in tabList"
+                    :key="index"
+                    :title="tab.label"
+                    :name="tab.name"></van-tab>
+            </van-tabs>
+            <section v-show="tabActiveName === 'analysis'" class="j-main analysis-content">
+                <div class="j-container search-filters bg-white" v-show="filtersPageShow && !rid">
+                    <div class="j-main">
+                        <div class="height8">height8</div>
+                        <div class="filters-title pd-lr16">
+                            <span>分析条件</span>
+                        </div>
+                        <van-cell-group class="filters-list">
+                            <van-cell center title="分析内容" is-link value-class="ellipsis" :value="resolveSelected('keys')" @click="clickCell('keys')"></van-cell>
+                            <van-cell center title="区域" is-link value-class="ellipsis" :value="resolveSelected('area')" @click="clickCell('area')"></van-cell>
+                            <van-cell center title="行业" is-link value-class="ellipsis" :value="resolveSelected('industry')" @click="clickCell('industry')"></van-cell>
+                            <van-cell center title="采购单位类型" value-class="ellipsis" is-link :value="resolveSelected('buyerclass')" @click="clickCell('buyerclass')"></van-cell>
+                            <div class="date-cell collection">
+                                <div class="cell-title">时间</div>
+                                <date-component
+                                    ref="dateSelector"
+                                    popup-container="body"
+                                    :diy="true"
+                                    :times="timeOptions"></date-component>
+                            </div>
+                        </van-cell-group>
+                        <div class="empty-container analysis-empty" v-show="emptyShow">
+                            <div class="empty-content-position">
+                                <div class="image">
+                                    <img src='/common-module/public/image/jy-sleep.png'>
+                                </div>
+                                <div class="empty-main tip-text" v-html="empty.msg"></div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="j-footer j-button-group">
+                        <button class="j-button-cancel" @click="resetAllFilters">重置</button>
+                        <button class="j-button-confirm" @click="startAnalysis">开始分析</button>
+                    </div>
+                </div>
+                <div class="j-container search-result" v-show="!filtersPageShow && rid">
+                    <div class="j-main">
+                        <div class="height8">height8</div>
+                        <van-cell-group class="filters-list">
+                            <van-cell center title="分析条件" is-link @click="toAnalysisPage"></van-cell>
+                        </van-cell-group>
+                        <div class="height8" v-show="false"></div>
+                        <section class="section bg-white dimension">
+                            <div class="section-title"> - 分析维度 -</div>
+                            <van-sticky class="section-sticky" z-index="99999999" :offset-top="stickyOffset">
+                                <div class="section-content dimension-list bg-white">
+                                    <div
+                                        class="j-button j-button-item dimension-item"
+                                        v-for="(item, index) in dimensionList"
+                                        :key="index"
+                                        v-text="item.name"
+                                        :class="{ active: item.id === activeDimension }"
+                                        @click="anchorTo(item)"
+                                    ></div>
+                                </div>
+                            </van-sticky>
+                            <div class="section-footer section-tip-text">
+                                <span>数据统计范围:</span>
+                                <span v-text="formatSelectTime(reportFilters.selectTime)"></span>
+                            </div>
+                        </section>
+                        <!-- 市场概况 -->
+                        <section class="section bg-white market-overview" id="market">
+                            <div class="section-title pd-16">市场概况</div>
+                            <div class="section-content market-overview-list">
+                                <div
+                                    class="market-overview-item"
+                                    v-for="(item, index) in sections.market.overview"
+                                    :key="index">
+                                    <span class="m-overview-name">${ item.label }</span>
+                                    <span class="m-overview-unit">(${ item.unit })</span>
+                                    <span class="m-overview-count">${ item.count }</span>
+                                    <span class="m-overview-type" v-if="item.ringRatio">环比</span>
+                                    <span
+                                        class="m-overview-ratio"
+                                        v-show="overviewRateTotal"
+                                        :class="{
+                                            red: item.ringRatio > 0,
+                                            green: item.ringRatio < 0
+                                        }">
+                                        <van-icon name="down" :class="{ 'icon-reverse': item.ringRatio >= 0 }" v-if="item.ringRatio"></van-icon>
+                                        <span>${ item.ringRatio ? (Math.abs(item.ringRatio) + '%') : '-' }</span>
+                                    </span>
+                                </div>
+                            </div>
+                            <div class="section-footer section-tip-text pd-16">
+                                环比:统计学术语,是表示连续2个统计周期(比如连<br />续两月)内的量的变化比。
+                            </div>
+                        </section>
+                        <!-- 项目规模分布 -->
+                        <section class="section bg-white pd-16 project-scatter" v-if="sections.projectScatter.dataAlready">
+                            <div class="section-title">项目规模分布</div>
+                            <div class="section-content">
+                                <project-scatter :chart-data="sections.projectScatter.chartData"></project-scatter>
+                            </div>
+                        </section>
+                        <!-- 项目规模TOP10 -->
+                        <section class="section bg-white pd-16 project-scatter" v-if="sections.projectScatter.tableData.length">
+                            <div class="section-title">项目规模TOP10</div>
+                            <div class="section-content project-top-list">
+                                <div
+                                    class="project-top-item"
+                                    v-for="(item, index) in sections.projectScatter.tableData"
+                                    :key="index">
+                                    <div class="p-t-i-hd">
+                                        <div
+                                            class="p-t-i-hd-l table-index-rect"
+                                            :class="{
+                                                red: index === 0,
+                                                orange: index === 1,
+                                                'soft-orange': index === 2
+                                            }">
+                                            ${ index + 1 }</div>
+                                        <div class="p-t-i-hd-r" @click="toArticleContent(item)">
+                                            <div class="project-name">${ item.projectname }</div>
+                                            <div class="project-info">
+                                                <div class="project-tags">
+                                                    <div class="j-tag tag-orange" v-if="item.sortprice">项目金额:${ item.sortprice }万元</div>
+                                                    <div class="j-tag tag-plain" v-if="item.area">${ item.area }</div>
+                                                    <div class="j-tag tag-plain" v-if="item.city">${ item.city }</div>
+                                                </div>
+                                                <div class="project-right">${ item.jgtime }</div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                    <div class="p-t-i-ft" v-if="item.winner_s.length">
+                                        <div class="p-t-i-ft-title">中标单位</div>
+                                        <div
+                                            class="p-t-i-ft-winner"
+                                            :class="{ disabled: !winner.id }"
+                                            v-for="(winner, i) in item.winner_s"
+                                            :key="index"
+                                            v-text="winner.name"
+                                            @click="toPortrait(winner.id, 'winner')"></div>
+                                    </div>
+                                </div>
+                            </div>
+                        </section>
+                        <!-- 时间分布 -->
+                        <section class="section bg-white pd-16 time-scatter" v-if="sections.timeScatter.dataAlready">
+                            <div class="section-header">
+                                <div class="section-title">时间分布</div>
+                                <div class="section-actions">
+                                    <div
+                                        class="action-button"
+                                        :class="{ active: sections.timeScatter.activeAction == 'month' }"
+                                        @click="sections.timeScatter.activeAction = 'month'">
+                                        月度数据</div>
+                                    <div
+                                        class="action-button"
+                                        :class="{ active: sections.timeScatter.activeAction == 'year' }"
+                                        @click="sections.timeScatter.activeAction = 'year'">
+                                        年度数据</div>
+                                </div>
+                            </div>
+                            <div class="section-content">
+                                <div class="sub-section-content">
+                                    <market-time-scatter width="100%" :chart-data="sections.timeScatter[sections.timeScatter.activeAction].count"></market-time-scatter>
+                                </div>
+                                <div class="sub-section-content">
+                                    <market-time-scatter width="100%" :chart-data="sections.timeScatter[sections.timeScatter.activeAction].amount"></market-time-scatter>
+                                </div>
+                            </div>
+                        </section>
+                        <!-- 地区分布 -->
+                        <div class="section bg-white pd-16 area-scatter" v-if="sections.areaScatter.dataAlready && oneAreaFilter">
+                            <div class="section-title">地区分布</div>
+                            <div class="section-content">
+                                <market-area-scatter :chart-data="sections.areaScatter.chartData"></market-area-scatter>
+                            </div>
+                        </div>
+                        <div class="section bg-white pd-16" v-if="sections.areaScatter.projectCountTop3">
+                            <div class="section-title">项目数量TOP3地区的重点中标单位</div>
+                            <div class="section-content">
+                                <market-top3-table :table-data="sections.areaScatter.projectCountTop3" type="count" @save="saveState"></market-top3-table>
+                            </div>
+                        </div>
+                        <div class="section bg-white pd-16" v-if="sections.areaScatter.projectAmountTop3">
+                            <div class="section-title">项目金额TOP3地区的重点中标单位</div>
+                            <div class="section-content">
+                                <market-top3-table :table-data="sections.areaScatter.projectAmountTop3" type="amount" @save="saveState"></market-top3-table>
+                            </div>
+                        </div>
+                        <!-- 客户分布 -->
+                        <div class="section bg-white pd-16 user-scatter" v-if="sections.userScatter.list.length">
+                            <div class="section-title">客户分布</div>
+                            <div class="section-content">
+                                <market-user-scatter :chart-data="sections.userScatter.list"></market-user-scatter>
+                            </div>
+                        </div>
+                        <div class="section bg-white pd-16" v-if="sections.userScatter.projectCountTop3">
+                            <div class="section-title">项目数量TOP3客户类型的重点中标单位</div>
+                            <div class="section-content">
+                                <market-top3-table :table-data="sections.userScatter.projectCountTop3" type="count" @save="saveState"></market-top3-table>
+                            </div>
+                        </div>
+                        <div class="section bg-white pd-16" v-if="sections.userScatter.projectAmountTop3">
+                            <div class="section-title">项目金额TOP3客户类型的重点中标单位</div>
+                            <div class="section-content">
+                                <market-top3-table :table-data="sections.userScatter.projectAmountTop3" type="amount" @save="saveState"></market-top3-table>
+                            </div>
+                        </div>
+                        <!-- 细分市场 - 项目数量 -->
+                        <div class="section bg-white pd-16 market-refine" v-if="sections.market.refine.dataAlready">
+                            <div class="section-title">细分市场 - 项目数量</div>
+                            <div class="section-content">
+                                <market-segment :chart-data="sections.market.refine.projectCountData" type="count"></market-segment>
+                            </div>
+                        </div>
+                        <div class="section bg-white pd-16" v-if="sections.market.refine.projectCountTop3">
+                            <div class="section-title">细分市场的重点中标单位-项目数量</div>
+                            <div class="section-content">
+                                <market-top3-table :table-data="sections.market.refine.projectCountTop3" type="count" @save="saveState"></market-top3-table>
+                            </div>
+                        </div>
+                        <!-- 细分市场 - 项目金额 -->
+                        <div class="section bg-white pd-16 market-refine" v-if="sections.market.refine.dataAlready">
+                            <div class="section-title">细分市场 - 项目金额</div>
+                            <div class="section-content">
+                                <market-segment :chart-data="sections.market.refine.projectAmountData" type="amount"></market-segment>
+                            </div>
+                        </div>
+                        <div class="section bg-white pd-16" v-if="sections.market.refine.projectAmountTop3">
+                            <div class="section-title">细分市场的重点中标单位-项目金额</div>
+                            <div class="section-content">
+                                <market-top3-table :table-data="sections.market.refine.projectAmountTop3" type="amount" @save="saveState"></market-top3-table>
+                            </div>
+                        </div>
+                        <!-- 采购规模分布 -->
+                        <div class="section bg-white pd-16 buyerclass-scatter" id="buyer" v-if="sections.buyerclass.dataAlready">
+                            <div class="section-title">采购规模分布</div>
+                            <div class="section-content">
+                                <line-chart-scatter :chart-data="sections.buyerclass.chartData"></line-chart-scatter>
+                            </div>
+                        </div>
+                        <div class="section bg-white pd-16" v-if="sections.buyerclass.projectCountTop3">
+                            <div class="section-title">项目数量TOP3采购单位及其重点合作中标单位</div>
+                            <div class="section-content">
+                                <market-top3-table :table-data="sections.buyerclass.projectCountTop3" type="count" @save="saveState"></market-top3-table>
+                            </div>
+                        </div>
+                        <div class="section bg-white pd-16" v-if="sections.buyerclass.projectAmountTop3">
+                            <div class="section-title">采购金额TOP3采购单位及其重点合作中标单位</div>
+                            <div class="section-content">
+                                <market-top3-table :table-data="sections.buyerclass.projectAmountTop3" type="amount" @save="saveState"></market-top3-table>
+                            </div>
+                        </div>
+                        <!-- 采购规模分布 -->
+                        <div class="section bg-white pd-16 winner-scatter" id="winner" v-if="sections.winner.dataAlready">
+                            <div class="section-title">中标规模分布</div>
+                            <div class="section-content">
+                                <line-chart-scatter :chart-data="sections.winner.chartData"></line-chart-scatter>
+                            </div>
+                        </div>
+                        <div class="section bg-white pd-16" v-if="sections.winner.projectCountTop3">
+                            <div class="section-title">项目数量TOP3中标单位及其重点合作采购单位</div>
+                            <div class="section-content">
+                                <market-top3-table :table-data="sections.winner.projectCountTop3" type="count" @save="saveState"></market-top3-table>
+                            </div>
+                        </div>
+                        <div class="section bg-white pd-16" v-if="sections.winner.projectAmountTop3">
+                            <div class="section-title">中标金额TOP3中标单位及其重点合作采购单位</div>
+                            <div class="section-content">
+                                <market-top3-table :table-data="sections.winner.projectAmountTop3" type="amount" @save="saveState"></market-top3-table>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="fixed-bottom-right clickable scroll-to-top" style="display: none;">
+                        <van-icon name="arrow-up"></van-icon>
+                    </div>
+                </div>
+            </section>
+        </div>
+        <van-popup
+            v-model="filterDialogShow.keys"
+            closeable
+            round
+            position="bottom"
+            close-icon="clear"
+            class="j-popup collection"
+            overlay-class="j-overlay"
+            :lazy-render="false"
+            :style="{ height: '60%' }"
+            get-container="body">
+            <div class="j-container keys-popup">
+                <div class="popup-header">
+                    <div class="header-top">
+                        <div class="header-title">选择分析内容</div>
+                        <div class="header-action" @click="toSubManageButtonClick">订阅管理</div>
+                    </div>
+                    <div class="header-bottom">注:如需新增分析内容,请完善您的订阅关键词</div>
+                </div>
+                <div class="j-main">
+                    <keyword-component
+                        ref="keywordSelector"
+                        protype="bigmember"
+                        :use-key-card="true"
+                        @nokeys="showSetKeyTip"
+                        @cancel="cancel($event, 'keys')"
+                        @confirm="confirm($event, 'keys')"
+                        :selectkeywordlist="filters.selectKeysArr"></keyword-component>
+                </div>
+            </div>
+        </van-popup>
+        <van-popup
+            v-model="filterDialogShow.area"
+            closeable
+            round
+            position="bottom"
+            close-icon="clear"
+            :lazy-render="false"
+            class="j-popup collection"
+            overlay-class="j-overlay"
+            :style="{ height: '60%' }"
+            get-container="body">
+            <div class="j-container report-popup">
+                <div class="popup-header header-title">选择区域</div>
+                <div class="j-main">
+                    <area-city-mobile
+                        ref="areaCitySelector"
+                        @cancel="cancel($event, 'area')"
+                        @confirm="confirm($event, 'area')"></area-city-mobile>
+                </div>
+            </div>
+        </van-popup>
+        <van-popup
+            v-model="filterDialogShow.industry"
+            closeable
+            round
+            position="bottom"
+            close-icon="clear"
+            class="j-popup collection"
+            overlay-class="j-overlay"
+            :lazy-render="false"
+            :style="{ height: '60%' }"
+            get-container="body">
+            <div class="j-container report-popup">
+                <div class="popup-header header-title">选择行业</div>
+                <div class="j-main">
+                    <industry-component
+                        ref="industrySelector"
+                        :selectindustrylist="filters.industry"
+                        @cancel="cancel($event, 'industry')"
+                        @confirm="confirm($event, 'industry')"></industry-component>
+                </div>
+            </div>
+        </van-popup>
+        <van-popup
+            v-model="filterDialogShow.buyerclass"
+            closeable
+            round
+            position="bottom"
+            close-icon="clear"
+            class="j-popup collection"
+            :lazy-render="false"
+            overlay-class="j-overlay"
+            :style="{ height: '60%' }"
+            get-container="body">
+            <div class="j-container report-popup">
+                <div class="popup-header header-title">选择采购单位类型</div>
+                <div class="j-main">
+                    <cate-component
+                        ref="buyerclassSelector"
+                        :selectcatelist="filters.buyerclass"
+                        @cancel="cancel($event, 'buyerclass')"
+                        @confirm="confirm($event, 'buyerclass')"></cate-component>
+                </div>
+            </div>
+        </van-popup>
+    </div>
+</div>
+
+<script src=//cdn-common.jianyu360.com/cdn/lib/vue/2.6.11/vue.min.js></script>
+<!-- <script src=//cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js></script> -->
+<script src=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/vant.min.js></script>
+<script src=//cdn-common.jianyu360.com/cdn/lib/zepto/1.2.0/zepto.min.js></script>
+<script src=//cdn-common.jianyu360.com/cdn/lib/lodash/4.17.21/lodash.min.js></script>
+<script src=//cdn-common.jianyu360.com/cdn/lib/echarts/4.8.0/echarts.min.js></script>
+<script src=//cdn-common.jianyu360.com/cdn/lib/v-charts/1.19.0/index.min.js></script>
+{{include "/big-member/commonjs.html"}}
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/public/js/china-map-data.js'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/collection/js/keyword-mobile.js?v={{Msg "seo" "version"}}'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/collection/js/date-mobile.js?v={{Msg "seo" "version"}}'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/collection/js/area-city-mobile.js?v={{Msg "seo" "version"}}'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/collection/js/industry-mobile.js?v={{Msg "seo" "version"}}'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/collection/js/cate-mobile.js?v={{Msg "seo" "version"}}'></script>
+<!-- components -->
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/echarts_option.js'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/components/projectScatter.js'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/components/marketTimeScatter.js'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/components/marketAreaScatter.js'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/components/marketTop3Table.js'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/components/marketUserScatter.js'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/components/marketSegment.js'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/components/lineChartScatter.js'></script>
+<!-- main.js -->
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/report_analysis.js?v={{Msg "seo" "version"}}'></script>
+
+</body>
+</html>

+ 49 - 0
src/jfw/modules/app/src/web/templates/big-member/page_report_analysis_history.html

@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <!--引入公共资源头部-->
+    {{include "/big-member/meta.html"}}
+    <title>定制化市场分析报告</title>
+    <link rel="stylesheet" href=//cdn-common.jianyu360.com/cdn/lib/reset-css/5.0.1/reset.min.css />
+    <link rel="stylesheet" href=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/index.css />
+    <link rel="stylesheet" href=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/icon/local.css />
+    <link rel="stylesheet" href='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/css/report_analysis.css?v={{Msg "seo" "version"}}' />
+    <link rel="stylesheet" href='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/diy-report/css/report-list.css?v={{Msg "seo" "version"}}' />
+</head>
+
+<body>
+<div class="j-container">
+    {{include "/big-member/header.html"}}
+    <div class="j-main" id="analysis" v-cloak>
+        <div class="j-container">
+            <van-tabs
+                :title-active-color="tabConf.titleActiveColor"
+                :title-inactive-color="tabConf.titleInactiveColor"
+                :line-width="tabConf.lineWidth"
+                :color="tabConf.color"
+                :before-change="beforeTabChange"
+                v-model="tabActiveName">
+                <van-tab
+                    v-for="(tab, index) in tabList"
+                    :key="index"
+                    :title="tab.label"
+                    :name="tab.name"></van-tab>
+            </van-tabs>
+            <section v-show="tabActiveName === 'analysis'" class="j-main analysis-content"></section>
+            <section v-show="tabActiveName === 'history'" class="j-main history-content">
+                <report-list-mobile-component ref="list" @go-report="goToAnalysis"></report-list-mobile-component>
+            </section>
+        </div>
+    </div>
+</div>
+
+<script src=//cdn-common.jianyu360.com/cdn/lib/vue/2.6.11/vue.min.js></script>
+<script src=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/vant.min.js></script>
+<script src=//cdn-common.jianyu360.com/cdn/lib/zepto/1.2.0/zepto.min.js></script>
+{{include "/big-member/commonjs.html"}}
+
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/diy-report/js/report-list.js?v={{Msg "seo" "version"}}'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/report_analysis_history.js?v={{Msg "seo" "version"}}'></script>
+
+</body>
+</html>

+ 1 - 20
src/jfw/modules/app/src/web/templates/big-member/page_set_area.html

@@ -66,27 +66,8 @@
             }
         }
 
-         // 其他页面自定义方法
-        //  var custom = {
-        //     _setting_save: function (data) {
-        //         $.ajax({
-        //             type:'POST',
-        //             url:'/bigmember/subscribe/area/update',
-        //             contentType: 'application/json;charset=utf-8',
-        //             data: JSON.stringify(data),
-        //             success:function(res){
-        //                 if(res.data.status == 1){
-        //                     history.back()
-        //                     sessionStorage.removeItem('big-setArea')
-        //                 }else if(res.data.status == -1){
-        //                     vueComponent.$toast(res.data.error_msg)
-        //                 }
-        //             }
-        //         })
-        //     }
-        // }
         var bigIndustry = ''
-         function infoAjax () {
+        function infoAjax () {
             $.ajax({
                 type:'POST',
                 url:'/bigmember/use/info',

+ 18 - 12
src/jfw/modules/app/src/web/templates/big-member/page_unit_portrayal.html

@@ -95,31 +95,37 @@
 <body>
 <div class="j-container">
     {{include "/big-member/header.html"}}
-    <div id="unit_portrayal" class="j-main" v-cloak @click="doubleBar.showTooltip = false">
+    <div id="unit_portrayal" ref="container" class="j-main" v-cloak @click="doubleBar.showTooltip = false" @scroll="onUnitScroll">
         <div v-if="chartLoading" class="skeleton">
             <img class="working"  src="/jyapp/big-member/image/working.gif" alt="">
         </div>
         <div v-else>
-            <div class="u-header">
-                <div class="company">
-                    <span class="j-icon icon-company"></span>
-                    <span class="ent-title">${buyer.name || '--'}</span>
-                </div>
-                <p class="region">所在地:${statistics.province || '--'} ${statistics.city}</p>
-                <p class="buyer-type">采购单位类型:${statistics.buyerClass || '--'}</p>
+            <div class="u-header" style="padding-bottom: .24rem;">
+              <div class="company">
+                  <span class="j-icon icon-company"></span>
+                  <span class="ent-title">${buyer.name || '--'}</span>
+              </div>
+              <p class="region">所在地:${statistics.province || '--'} ${statistics.city}</p>
+              <p class="buyer-type">采购单位类型:${statistics.buyerClass || '--'}</p>
+            </div>
+            <!-- 留完资的免费用户 已体验和未体验的展示去开通 -->
+            <div v-if="getfreeBuyerOpen">
+              <van-sticky offset-top="21.33333vw">
+                <img @click="goOpenVip" src="/jyapp/big-member/image/buyer-open.png" alt="">
+              </van-sticky>
             </div>
             <!-- 免费用户采购单位全景分析提示 -->
-            <div v-if="getfreeBuyerPort" style="margin-top: .24rem; " class="free-give">
+            <div v-if="getfreeBuyerPort" class="free-give">
                 <div class="go-text"> 免费赠送1次【采购单位全景分析】权益体验机会!</div>
                 <div class="go-btn"  @click="goGiveAnalysis">去解锁</div>
             </div>
             <!-- 超级订阅用户展示  -->
-            <div v-if="superVipPort" style="margin-top: .24rem; " class="free-give">
+            <div v-if="superVipPort" class="free-give">
               <div class="balance-text"> 当月采购单位画像余额:<em class="highlight-text">${usageInfo.surplus}</em></div>
               <div class="go-btn" @click="goUpgradeOrConcat(superVipBtnText)">${superVipBtnText}</div>
             </div>
             <!-- 采购单位通讯录 -->
-            <div v-if="getStatus" style="margin-top: .24rem;">
+            <div v-if="getStatus">
               <div class="vip_component" style="height:10.8rem;background:url('/common-module/collection/image/buyer/01-bg.png') no-repeat;background-size:100% 100%">
                 <p class="example-title win-bid-title">采购单位通讯录</p>
                 <buyer-example :useage="usageInfo" :userinfo="userInfo" :status="bigStatus" :power="power" type="item_1" imgurl='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/collection/image/buyer/01.png'></buyer-example>
@@ -129,7 +135,7 @@
             <hispro-component v-else class="history-list" type="buyer" :status="bigStatus" :buyer="buyer.name"></hispro-component>
             <!-- 高级分析设置 -->
             <!-- 高级分析 -->
-            <div class="win-analyse">
+            <div class="win-analyse" ref="setRefs">
               <span class="win-bid-title">采购单位分析</span>
               <div class="high-link" @click="goHighSet">
                 <span>高级分析设置</span>

+ 4 - 2
src/jfw/modules/app/src/web/templates/weixin/historypush.html

@@ -1812,7 +1812,8 @@ function hasNoData() {
                     if(myInfo.userType=="vip") {
                         window.location.href = '/jyapp/vipsubscribe/toSetKeyWordPage'
                     } else {
-                        window.location.href = '/jyapp/wxkeyset/keyset/filterset?type=add&index=0&from=historypush';
+                        window.location.href = '/jyapp/vipsubscribe/toSetKeyWordPage'
+                        // window.location.href = '/jyapp/wxkeyset/keyset/filterset?type=add&index=0&from=historypush';
                     }
                 }
             }
@@ -1827,7 +1828,8 @@ function hasNoData() {
                 if(myInfo.userType=="vip") {
                     window.location.href = '/jyapp/vipsubscribe/toSetKeyWordPage'
                 } else {
-                    window.location.href = '/jyapp/wxkeyset/keyset/filterset?type=add&index=0&from=historypush';
+                    window.location.href = '/jyapp/vipsubscribe/toSetKeyWordPage'
+                    // window.location.href = '/jyapp/wxkeyset/keyset/filterset?type=add&index=0&from=historypush';
                 }
             }
         }

+ 51 - 5
src/jfw/modules/app/src/web/templates/weixin/wxinfocontent.html

@@ -123,6 +123,28 @@
           overflow: hidden;
           margin: 0 auto;
       }
+      .free-open-tip{
+        display: flex;
+        align-items: center;
+        height: .4rem;
+        margin-left: .24rem;
+        background: rgba(42, 189, 209, 0.1);
+        border-radius: 10px;
+      }
+      .free-open-tip .down-more-text{
+        color: #2ABDD1;
+        font-size: .22rem;
+        padding: 0 .08rem 0 .16rem;
+      }
+      .free-open-tip .open-vip-btn{
+        height: 100%;
+        background-color: #2ABDD1;
+        border-radius: 10px;
+        color: #fff;
+        padding: 0 .22rem;
+        font-size: .22rem;
+        line-height: .4rem;
+      }
       #h_content table{
         /* border: 1px solid #EBEBEB; */
         border-collapse: collapse!important;
@@ -130,6 +152,7 @@
       }
       #h_content table tr td,.h_content table th{
         border: 1px solid #EBEBEB;
+        text-align: center;
       }
     </style>
 </head>
@@ -688,7 +711,11 @@
                             <span class="file-count-tip">本月剩余:<em class="file-count"></em>个</span>
                             <span class="icon-help"></span>
                             <span class="concat-kf">联系客服</span>
-                            <span class="go-buy-file-pack" style="display: none">立即充值</span>
+							<span class="go-buy-file-pack" style="display: none">立即充值</span>
+                            <span class="free-open-tip" style="display: none;">
+                              <span class="down-more-text">下载更多附件</span>
+                              <span class="open-vip-btn">开通超级订阅</span>
+                            </span>
                         </div>
                     </a>
                 </div>
@@ -1041,7 +1068,6 @@
         }
         return ad
     }
-
     function isOpening() {
         $.ajax({
             type:'GET',
@@ -1104,8 +1130,16 @@
                     $('.bigvip_drain').hide()
                 }
                 // 免费用户展示可下载一次提示(免费用户且没有体验过附件下载权益的展示)
-                if (res.data && res.data.isFree && res.data.freeFile == 0) {
-                  $('.free-down-text').css('display', 'inline-block')
+                if (res.data && res.data.isFree) {
+                  if (res.data.freeFile == 0) {
+                    $('.free-down-text').css('display', 'inline-block')
+                  } else {
+                    // 留过资 体验过的 提示开通超级订阅
+                    $('.free-open-tip').css('display', 'flex')
+                    $('.free-open-tip .open-vip-btn').click(function(){
+                      location.href= '/jyapp/vipsubscribe/vipsubscribe_new'
+                    })
+                  }
                 }
                 //非大会员或大会员无此功能 且是新超级订阅用户
                 if (res.data && res.data.vipStatus > 0 && res.data.viper&&!window.isMemberAndPower) {
@@ -1371,7 +1405,8 @@
                           }
                         }
                         // 是大会员自定义版本没有下载权限 或 非超级订阅的商机管理用户 (弹框提醒联系客服)
-                        if (window.isNoMember == true || (window.vipStatus <=0 && window.entniche)) {
+                        var memberNoVip = window.isNoMember == true && !(window.vipStatus >0 && window.viper)
+                        if (memberNoVip || (window.vipStatus <=0 && window.entniche)) {
                           vant.Dialog.alert({
                             message: '您未购买此服务,如需使用请联系您的客户经理或客服升级套餐,谢谢!',
                             className: 'custom-dialog',
@@ -2487,6 +2522,17 @@
       })
     }
     $(function(){
+      var u = navigator.userAgent;
+      var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
+      var isPageHide = false;
+      window.addEventListener('pageshow', function () {
+          if (isPageHide && isiOS) {
+          window.location.reload();
+          }
+      });
+      window.addEventListener('pagehide', function () {
+          isPageHide = true;
+      });
       // 收藏
       $('.collec_star').on('click', function () {
         var $this = $(this)

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

@@ -65,5 +65,10 @@
     "mainWebDomain": "https://jianyu360.com",
     "createPdfServer": "http://192.168.3.11:8081/api/to-pdf/%s?dir=%s&url=https://web-wky.jydev.jianyu360.com/swordfish/frontPage/report/free/report?pid=%s",
     "pdfDataApiWhiteList": ["1.192.62.131","127.0.0.1"],
-    "pdfServerPoor" : 5
+    "pdfServerPoor" : 5,
+    "marketAnalysisPool": {
+      "limit": 5,
+      "timeOut": 20,
+      "projectNumLimit": 8000000
+    }
 }

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

@@ -38,7 +38,14 @@ type config struct {
 	PdfServerPoor       int            //生成pdf线程数量控制
 	PdfDataApiWhiteList []string       //pdf数据接口白名单
 	MainWebDomain       string         //附件剑鱼地址
+	marketAnalysisPool  int
+	MarketAnalysisPool  struct {
+		Limit           int `json:"limit"`           //查询并发池
+		TimeOut         int `json:"timeOut"`         //并发池等待超时时长,单位秒
+		ProjectNumLimit int `json:"projectNumLimit"` //自定义报告限制项目个数
+	} `json:"marketAnalysisPool"` //市场分析
 }
+
 type customerInfo struct {
 	Name string `json:"name"`
 	Wxer string `json:"wxer"`

+ 125 - 0
src/jfw/modules/bigmember/src/entity/marketAnalysis/commonSearch.go

@@ -0,0 +1,125 @@
+package marketAnalysis
+
+import (
+	"fmt"
+	qutil "qfw/util"
+	"strings"
+)
+
+const (
+	localMultiMatch     = `{"multi_match": {"query": %s,"type": "phrase", "fields": ["purchasing","pname"]}}`
+	query_bool_must_and = `{"bool": {"must": [%s]%s}}`
+	PSearch_DecMust     = `"bidstatus": ["中标","成交","合同","单一"]`
+	query_bool_must     = `{"terms": {%s}}`
+)
+
+//GetCommonQuerySql 公共筛选
+func (mae *MarketAnalysisEntity) GetCommonQuerySql() string {
+	var musts, bools []string
+	//时间
+	musts = append(musts, fmt.Sprintf(`{"range":{"firsttime":{"gte":%d,"lte":%d}}}`, mae.FormatParam.STime, mae.FormatParam.ETime))
+	//地区
+	if len(mae.FormatParam.Area) > 0 || len(mae.FormatParam.City) > 0 {
+		var areaCity []string
+		if len(mae.FormatParam.Area) > 0 {
+			areaCity = append(areaCity, fmt.Sprintf(`{"terms":{"area":["%s"]}}`, strings.Join(mae.FormatParam.Area, `","`)))
+		}
+		if len(mae.FormatParam.City) > 0 {
+			areaCity = append(areaCity, fmt.Sprintf(`{"terms":{"city":["%s"]}}`, strings.Join(mae.FormatParam.City, `","`)))
+		}
+		musts = append(musts, fmt.Sprintf(`{"bool":{"should":[%s],"minimum_should_match": 1}}`, strings.Join(areaCity, ",")))
+	}
+	//行业
+	if len(mae.FormatParam.Industry) > 0 {
+		musts = append(musts, fmt.Sprintf(`{"terms":{"s_subscopeclass":["%s"]}}`, strings.Join(mae.FormatParam.Industry, `","`)))
+	}
+	//类型
+	if len(mae.FormatParam.BuyerClass) > 0 {
+		musts = append(musts, fmt.Sprintf(`{"terms":{"buyerclass":["%s"]}}`, strings.Join(mae.FormatParam.BuyerClass, `","`)))
+	}
+	//分析报告中标状态限制
+	musts = append(musts, fmt.Sprintf(query_bool_must, PSearch_DecMust))
+	//订阅词
+	for _, v := range getAllKeywordArr(mae.FormatParam.KeysItems) {
+		if sql := getKeyWordSql(v); sql != "" {
+			bools = append(bools, sql)
+		}
+	}
+
+	return fmt.Sprintf(`{"query":{"bool":{"must":[%s],"should":[%s],"minimum_should_match": %d}}%s}`, strings.Join(musts, ","), strings.Join(bools, ","), qutil.If(len(bools) > 0, 1, 0).(int), "%s")
+}
+
+//GetCommonQuerySqlWithAggs 此方法用于聚合查询
+func (mae *MarketAnalysisEntity) GetCommonQuerySqlWithAggs() string {
+	return fmt.Sprintf(mae.GetCommonQuerySql(), `,"aggs":{%s},"size":0`)
+}
+
+//getGroupKeywordArr 模糊拆分为多个精准匹配
+func getGroupKeywordArr(res []viewKeyWord) (rData []viewKeyWord) {
+	for _, kw := range res {
+		if kw.MatchWay == 1 {
+			for _, kk := range kw.Keyword {
+				rData = append(rData, viewKeyWord{
+					Keyword: []string{kk},
+					Exclude: kw.Exclude,
+				})
+			}
+			for _, kk := range kw.Appended {
+				rData = append(rData, viewKeyWord{
+					Keyword: []string{kk},
+					Exclude: kw.Exclude,
+				})
+			}
+		} else {
+			rData = append(rData, kw)
+		}
+	}
+	return
+}
+
+//getAllKeywordArr 获取所有匹配词
+func getAllKeywordArr(res []keyWordGroup) (rData []viewKeyWord) {
+	for _, kwg := range res {
+		rData = append(rData, getGroupKeywordArr(kwg.A_Key)...)
+	}
+	return
+}
+
+func getKeyWordSql(v viewKeyWord) string {
+	var shoulds, must_not []string
+	//附加词
+	for _, vv := range v.Keyword {
+		vv = strings.TrimSpace(vv)
+		if vv == "" {
+			continue
+		}
+		shoulds = append(shoulds, fmt.Sprintf(localMultiMatch, "\""+vv+"\""))
+	}
+
+	for _, vv := range v.Appended {
+		vv = strings.TrimSpace(vv)
+		if vv == "" {
+			continue
+		}
+		shoulds = append(shoulds, fmt.Sprintf(localMultiMatch, "\""+vv+"\""))
+	}
+
+	//排除词
+	for _, vv := range v.Exclude {
+		vv = strings.TrimSpace(vv)
+		if vv == "" {
+			continue
+		}
+		must_not = append(must_not, fmt.Sprintf(localMultiMatch, "\""+vv+"\""))
+	}
+
+	//添加
+	if len(shoulds) > 0 {
+		notStr := ""
+		if len(must_not) > 0 {
+			notStr = fmt.Sprintf(`,"must_not":[%s]`, strings.Join(must_not, ","))
+		}
+		return fmt.Sprintf(query_bool_must_and, strings.Join(shoulds, ","), notStr)
+	}
+	return ""
+}

+ 915 - 0
src/jfw/modules/bigmember/src/entity/marketAnalysis/customizad_distribution.go

@@ -0,0 +1,915 @@
+package marketAnalysis
+
+import (
+	"config"
+	"encoding/json"
+	"fmt"
+	elastic1 "gopkg.in/olivere/elastic.v1"
+	"log"
+	"math"
+	"strings"
+	"time"
+	"util"
+)
+
+const (
+	//市场分析聚合查询
+	aggs_market_analysis = `"%s": {"range": {"field": "firsttime","ranges": [%s]},"aggs":{"project_count": {"filter": {}},"project_amount":{"sum":{"field":"sortprice"}},"project_avgMoney": {"filter": {"range": {"sortprice": {"gt": 0}}},"aggs": {"avg_amount": {"avg": {"field": "sortprice"}}}} ,"buyer_count":{"cardinality":{"field":"buyer"}},"winner_count":{"cardinality":{"field":"s_winner"}}}}`
+	//aggs_market_analysis = `"%s": {"range": {"field": "firsttime","ranges": [%s]},"aggs":{"project_count": {"filter": {"range": {"sortprice": {"gt": 0}}}},"project_amount":{"sum":{"field":"sortprice"}},"project_avgMoney": {"filter": {"range": {"sortprice": {"gt": 0}}},"aggs": {"avg_amount": {"avg": {"field": "sortprice"}}}},"buyer_count":{"filter": {"range": {"sortprice": {"gt": 0}}},"aggs": {"cardinality_buyer_count": {"cardinality": {"field": "buyer"}}}},"winner_count":{"filter": {"range": {"sortprice": {"gt": 0}}},"aggs": {"cardinality_winner_count": {"cardinality": {"field": "s_winner"}}}}}}`
+
+	//时间分布统计
+	project_time_distribution = `"%s": {"range": { "field": "firsttime","ranges": [%s]},"aggs":{ "scale_amount": {"sum": {"field": "sortprice"}}, "scale_total": {"filter": {}}}}`
+
+	//采购单位聚合查询
+	//buyer_procurement_scale = `"project_count":{"filter":{}},"project_amount":{"sum":{"field":"sortprice"}},"buyer_count":{"filter": {"range": {"sortprice": {"gt": 0}}},"aggs": {"cardinality_buyer_count": {"cardinality": {"field": "buyer"}}}},"buyer_time_distribution": {"range": { "field": "sortprice","ranges": [%s]},"aggs":{"buyer_count": {"cardinality": {"field": "buyer"}}}},"buyer_amount_distribution": {"terms": {"field": "buyer","size": 0},"aggs": {"amount": {"sum": {"field": "sortprice"}}}}`
+	buyer_procurement_scale = `"project_amount":{"sum":{"field":"sortprice"}},"buyer_amount_distribution": {"terms": {"field": "buyer","size": 0},"aggs": {"amount": {"sum": {"field": "sortprice"}}}}`
+
+	//采购单位top3(价格)buyer_sortprice
+	buyer_sortprice = `"buyer_amount_top3": {"terms": {"field": "buyer","order": [{"buyer_amount": "desc"}],"size": 3},"aggs": {"buyer_amount": {"sum": {"field": "sortprice"}},"s_winner_top": {"terms": {"field": "entidlist","exclude":["-"],"order": [{"buyer_winner_amount": "desc"}],"size": 3},"aggs": {"buyer_winner_amount": {"sum": {"field": "sortprice"}}}}}}`
+	//采购单位top3(数量)
+	//buyer_count = `"buyer_count_top3": {"terms": {"field": "buyer","order": [{"buyer_count": "desc"}],"size": 3},"aggs": {"buyer_count": {"cardinality": {"field": "buyer"}},"s_winner_top": {"terms": {"field": "s_winner","order": [{"buyer_winner_count": "desc"}],"size": 3},"aggs": {"buyer_winner_count": {"cardinality": {"field": "s_winner"}}}}}}`
+	buyer_count = `"buyer_count_top3": {"terms": {"field": "buyer","order": [{"buyer_count": "desc"}],"size": 3},"aggs": {"buyer_count": {"filter":{}},"s_winner_top": {"terms": {"field": "entidlist","exclude":["-"],"order": [{"buyer_winner_count": "desc"}],"size": 3},"aggs": { "buyer_winner_count": {"filter":{}}}}}}`
+
+	//中标单位
+	//winner_procurement_scale = `"winner_count":{"filter": {"range": {"sortprice": {"gt": 0}}},"aggs": {"cardinality_winner_count": {"cardinality": {"field": "s_winner"}}}},"winner_time_distribution": {"range": { "field": "sortprice","ranges": [%s]},"aggs":{"s_winner_count": {"cardinality": {"field": "s_winner"}}}},"winner_amount_distribution": {"terms": {"field": "s_winner","size": 0},"aggs": {"amount": {"sum": {"field": "sortprice"}}}}`
+	winner_procurement_scale = `"winner_amount_distribution": {"terms": {"field": "entidlist","size": 0},"aggs": {"amount": {"sum": {"field": "sortprice"}}}}`
+
+	//中标单位top3(价格)
+	winner_sortprice = `"winner_amount_top3": {"terms": {"field": "entidlist","exclude":["-"],"order": [{"s_winner_amount": "desc"}],"size": 3},"aggs": {"s_winner_amount": {"sum": {"field": "sortprice"}},"buyer_top": {"terms": {"field": "buyer","order": [{"buyer_winner_amount": "desc"}],"size": 3},"aggs": {"buyer_winner_amount": {"sum": {"field": "sortprice"}}}}}}`
+	//中标单位(数量)
+	//winner_count = `"winner_count_top3": {"terms": {"field": "s_winner","order": [{"s_winner_count": "desc"}],"size": 3},"aggs": {"s_winner_count": {"cardinality": {"field": "s_winner"}},"buyer_top": {"terms": {"field": "buyer","order": [{"buyer_winner_count": "desc"}],"size": 3},"aggs": {"buyer_winner_count": {"cardinality": {"field": "buyer"}}}}}}`
+	winner_count = `"winner_count_top3": {"terms": {"field": "entidlist","exclude":["-"],"order": [{"s_winner_count": "desc"}],"size": 3},"aggs": {"s_winner_count": {"filter":{}},"buyer_top": {"terms": {"field": "buyer","order": [{"buyer_winner_count": "desc"}],"size": 3},"aggs": {"buyer_winner_count": {"filter":{}}}}}}`
+)
+
+var y_m_day = map[int]int{1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31}
+
+type SWinner struct {
+	Buckets []struct {
+		Key               string `json:"key"`
+		DocCount          int    `json:"doc_count"`
+		BuyerWinnerAmount struct {
+			Value float64 `json:"value"`
+		} `json:"buyer_winner_amount"`
+	} `json:"buckets"`
+}
+
+func getPreviousMarket(sTime, eTime time.Time) int64 {
+	var os_time int64
+	s_time := sTime
+	if SEMonth(sTime, eTime) {
+		var min int
+		//统计月份
+		for sTime.Before(eTime) {
+			sTime = sTime.AddDate(0, 1, 0)
+			min++
+		}
+		os_time = s_time.AddDate(0, -min, 0).Unix()
+	} else {
+		os_time = s_time.AddDate(0, 0, -int(math.Ceil(eTime.Sub(sTime).Hours()/24))).Unix()
+	}
+
+	return os_time
+}
+
+//判断是否月初到月末
+func SEMonth(sTime, eTime time.Time) bool {
+	var day int
+	month := int(eTime.Month())
+	if month == 2 {
+		if eTime.Year()%4 == 0 {
+			day = 29
+		} else {
+			day = 28
+		}
+	} else {
+		day = y_m_day[month]
+	}
+
+	if sTime.Day() == 1 && eTime.Day() == day {
+		return true
+	}
+	return false
+}
+
+func Rest(res elastic1.Aggregations, thisRow *marketTime) {
+	for name, object := range res {
+		bArr, err := object.MarshalJSON()
+		if len(bArr) == 0 || err != nil {
+			continue
+		}
+		if name == "thismarket" {
+			if json.Unmarshal(bArr, &thisRow.Thismarket) != nil {
+				continue
+			}
+		} else if name == "oldmarket" {
+			if json.Unmarshal(bArr, &thisRow.Oldmarket) != nil {
+				continue
+			}
+		} else if name == "monthtime" {
+			if json.Unmarshal(bArr, &thisRow.Monthtime) != nil {
+				continue
+			}
+		} else if name == "yeartime" {
+			if json.Unmarshal(bArr, &thisRow.Yeartime) != nil {
+				continue
+			}
+		}
+	}
+}
+
+func GetMonthData(sTime, eTime time.Time) (bool, string) {
+	var _b bool
+	//整月多取一个月进行环比
+	if SEMonth(sTime, eTime) {
+		_b = true
+		sTime = sTime.AddDate(0, -1, 0)
+	}
+
+	return _b, getBidamountStatistics(sTime, eTime)
+}
+
+func getBidamountStatistics(sTime, eTime time.Time) string {
+	timeRange := ``
+	tmpTime, rTime, tEndTime := sTime, sTime, getMonthRange(eTime, false)
+	for rTime.Before(tEndTime) {
+		ts, te := getMonthRange(tmpTime, true), getMonthRange(tmpTime, false)
+		if sTime == tmpTime {
+			ts = sTime
+		}
+		if te == tEndTime {
+			te = eTime
+		}
+		if ts.Before(te) {
+			timeRange += fmt.Sprintf(`{"key":"%s","from":%d,"to":%d},`, fmt.Sprintf("%d-%d", ts.Year(), ts.Month()), ts.Unix(), te.Unix())
+		}
+		rTime = rTime.AddDate(0, 1, 0)
+		if int(rTime.Month())-int(tmpTime.Month()) > 1 {
+			rTime = rTime.AddDate(0, -1, 0)
+		}
+		tmpTime = rTime
+	}
+	if timeRange == `` {
+		return ""
+	}
+	return timeRange[:len(timeRange)-1]
+}
+
+//getMonthRange获取月份范围
+//isStart true本月月初  false 本月月末(下月月初)
+func getMonthRange(t time.Time, isStart bool) time.Time {
+	if isStart {
+		return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
+	}
+	return time.Date(t.Year(), t.Month()+1, 1, 0, 0, 0, 0, t.Location())
+}
+
+func GetYearData(sTime, eTime time.Time) (bool, string) {
+	var _b bool
+	//整月多取一个月进行环比
+	if sTime.Month() == 1 && sTime.Day() == 1 && eTime.Month() == 12 && eTime.Day() == 31 {
+		_b = true
+		sTime = sTime.AddDate(-1, 0, 0)
+	}
+	return _b, getCommonYearStatistics(sTime, eTime)
+}
+
+//getYearRange获取月份范围
+//isStart true本月月初  false 本月月末(下月月初)
+func getYearRange(t time.Time, isStart bool) time.Time {
+	if isStart {
+		return time.Date(t.Year(), 1, 1, 0, 0, 0, 0, t.Location())
+	}
+	return time.Date(t.Year()+1, 1, 1, 0, 0, 0, 0, t.Location())
+}
+
+//年份统计
+func getCommonYearStatistics(sTime, eTime time.Time) string {
+	timeRange := ``
+	tmpTime, rTime, tEndTime := sTime, sTime, getYearRange(eTime, false)
+	for rTime.Before(tEndTime) {
+		ts, te := getYearRange(tmpTime, true), getYearRange(tmpTime, false)
+		if sTime == tmpTime {
+			ts = sTime
+		}
+		if te == tEndTime {
+			te = eTime
+		}
+		if ts.Before(te) {
+			timeRange += fmt.Sprintf(`{"key":"%d","from":%d,"to":%d},`, ts.Year(), ts.Unix(), te.Unix())
+		}
+		rTime = rTime.AddDate(1, 0, 0)
+		tmpTime = rTime
+	}
+	if timeRange == `` {
+		return ""
+	}
+	return timeRange[:len(timeRange)-1]
+}
+
+type marketTime struct {
+	Thismarket struct {
+		Buckets []marketBuckets `json:"buckets"`
+	} `json:"thismarket"`
+	Oldmarket struct {
+		Buckets []marketBuckets `json:"buckets"`
+	} `json:"oldmarket"`
+	Monthtime struct {
+		Buckets []Buckets `json:"buckets"`
+	} `json:"monthtime"`
+	Yeartime struct {
+		Buckets []Buckets `json:"buckets"`
+	} `json:"yeartime"`
+}
+type marketBuckets struct {
+	ProjectCount struct {
+		DocCount int `json:"doc_count"`
+	} `json:"project_count"`
+	ProjectAmount struct {
+		Value float64 `json:"value"`
+	} `json:"project_amount"`
+	BuyerCount struct {
+		Value int `json:"value"`
+	} `json:"buyer_count"`
+	WinnerCount struct {
+		Value int `json:"value"`
+	} `json:"winner_count"`
+	ProjectAvgMoney struct {
+		DocCount  int `json:"doc_count"`
+		AvgAmount struct {
+			Value float64 `json:"value"`
+		} `json:"avg_amount"`
+	} `json:"project_avgMoney"`
+}
+type Buckets struct {
+	Key          string `json:"key"`
+	From         int    `json:"from"`
+	FromAsString string `json:"from_as_string"`
+	To           int    `json:"to"`
+	ToAsString   string `json:"to_as_string"`
+	DocCount     int    `json:"doc_count"`
+	ScaleTotal   struct {
+		DocCount int `json:"doc_count"`
+	} `json:"scale_total"`
+	ScaleAmount struct {
+		Value float64 `json:"value"`
+	} `json:"scale_amount"`
+}
+
+func sequential(now, old float64) interface{} {
+	if old == 0 {
+		return nil
+	}
+	return (now - old) / old
+}
+
+//市场概况+时间分布
+func (mae *MarketAnalysisEntity) MarketTime() (map[string]interface{}, error) {
+	var (
+		sql                   []string
+		monthB, yearB         bool
+		MonthRange, YearRange string
+	)
+	sql = append(sql, fmt.Sprintf(aggs_market_analysis, "thismarket", fmt.Sprintf(`{"key":"%s","from":%d,"to":%d}`, "market", mae.FormatParam.STime, mae.FormatParam.ETime)))
+	n_stime := mae.FormatParam.STime
+	var n_mae MarketAnalysisEntity
+	n_mae.FormatParam = mae.FormatParam
+	n_mae.BaseParam = mae.BaseParam
+	n_mae.MgoRecordId = mae.MgoRecordId
+	n_mae.FormatParam.ETime = mae.FormatParam.ETime
+	if time.Unix(mae.FormatParam.STime, 0).AddDate(1, 0, 0).Unix() >= time.Unix(mae.FormatParam.ETime, 0).Unix() {
+		n_stime = getPreviousMarket(time.Unix(mae.FormatParam.STime, 0), time.Unix(mae.FormatParam.ETime, 0))
+		sql = append(sql, fmt.Sprintf(aggs_market_analysis, "oldmarket", fmt.Sprintf(`{"key":"%s","from":%d,"to":%d}`, "market", n_stime, mae.FormatParam.STime)))
+	}
+
+	if time.Unix(mae.FormatParam.STime, 0).AddDate(0, 1, 0).Unix() < time.Unix(mae.FormatParam.ETime, 0).Unix() {
+		var mon_time, year_time int64
+		stime, etime := time.Unix(mae.FormatParam.STime, 0), time.Unix(mae.FormatParam.ETime, 0)
+		monthB, MonthRange = GetMonthData(stime, etime)
+		sql = append(sql, fmt.Sprintf(project_time_distribution, "monthtime", MonthRange))
+		if monthB {
+			mon_time = stime.AddDate(0, -1, 0).Unix()
+		} else {
+			mon_time = mae.FormatParam.STime
+		}
+		//年度数据
+		yearB, YearRange = GetYearData(stime, etime)
+		sql = append(sql, fmt.Sprintf(project_time_distribution, "yeartime", YearRange))
+		if yearB {
+			year_time = stime.AddDate(-1, 0, 0).Unix()
+		} else {
+			year_time = mae.FormatParam.STime
+		}
+
+		if n_stime > mon_time {
+			n_stime = mon_time
+		}
+		if n_stime > year_time {
+			n_stime = year_time
+		}
+	}
+
+	n_mae.FormatParam.STime = n_stime
+	finalSql := fmt.Sprintf(n_mae.GetCommonQuerySqlWithAggs(), strings.Join(sql, ","))
+	log.Printf("final marketScaleRefineQuery sql: %s", finalSql)
+	rMap := make(map[string]interface{})
+	rMapData := make(map[string]interface{})
+	thisRow := marketTime{}
+	res, _ := util.GetAggs("projectset", "projectset", finalSql)
+	if res == nil || len(res) == 0 {
+		return nil, fmt.Errorf("未查询到项目")
+	}
+	Rest(res, &thisRow)
+	if thisRow.Thismarket.Buckets != nil && len(thisRow.Thismarket.Buckets) != 0 {
+		Projectmarket := thisRow.Thismarket.Buckets[0]
+		if Projectmarket.ProjectCount.DocCount == 0 {
+			return nil, fmt.Errorf("未查询到项目数据")
+		}
+		if Projectmarket.ProjectCount.DocCount > config.Config.MarketAnalysisPool.ProjectNumLimit {
+			return nil, fmt.Errorf("项目数量超出上限")
+		}
+		rMapData["project_count"] = Projectmarket.ProjectCount.DocCount
+		rMapData["projctamout"] = Projectmarket.ProjectAmount.Value
+		rMapData["projectavgmoney"] = Projectmarket.ProjectAvgMoney.AvgAmount.Value
+		rMapData["buyercount"] = Projectmarket.BuyerCount.Value
+		rMapData["winnercount"] = Projectmarket.WinnerCount.Value
+		if thisRow.Oldmarket.Buckets != nil && len(thisRow.Oldmarket.Buckets) != 0 {
+			oldProjectmarket := thisRow.Oldmarket.Buckets[0]
+			//环比数据
+			rMapData["projctamount_ratio"] = sequential(Projectmarket.ProjectAmount.Value, oldProjectmarket.ProjectAmount.Value)
+			rMapData["project_count_ratio"] = sequential(float64(Projectmarket.ProjectCount.DocCount), float64(oldProjectmarket.ProjectCount.DocCount))
+			rMapData["projectavgmoney_ratio"] = sequential(Projectmarket.ProjectAvgMoney.AvgAmount.Value, oldProjectmarket.ProjectAvgMoney.AvgAmount.Value)
+			rMapData["buyercount_ratio"] = sequential(float64(Projectmarket.BuyerCount.Value), float64(oldProjectmarket.BuyerCount.Value))
+			rMapData["winnercount_ratio"] = sequential(float64(Projectmarket.WinnerCount.Value), float64(oldProjectmarket.WinnerCount.Value))
+		}
+	}
+	rMap["market_profile"] = rMapData
+
+	if thisRow.Monthtime.Buckets != nil && len(thisRow.Monthtime.Buckets) != 0 {
+		rMap["month_distribution"] = n_mae.TimeData(monthB, thisRow.Monthtime.Buckets)
+	}
+	if thisRow.Yeartime.Buckets != nil && len(thisRow.Yeartime.Buckets) != 0 {
+		rMap["year_distribution"] = n_mae.TimeData(yearB, thisRow.Yeartime.Buckets)
+	}
+	return rMap, nil
+}
+
+//时间分布月,年通用数据处理
+func (mae *MarketAnalysisEntity) TimeData(_b bool, thisRow []Buckets) map[string]interface{} {
+	var count_ss, amout_ss []map[string]interface{}
+
+	for k, v := range thisRow {
+		//环比多取一期数据
+		if _b && k == 0 {
+			continue
+		}
+		count := make(map[string]interface{})
+		amount := make(map[string]interface{})
+		count["minth"] = v.Key
+		count["value"] = v.ScaleTotal.DocCount
+		amount["minth"] = v.Key
+		amount["value"] = v.ScaleAmount.Value
+		//整月,年统计环比
+		if _b {
+			doccount := thisRow[k-1].ScaleTotal.DocCount
+			amountvalue := thisRow[k-1].ScaleAmount.Value
+
+			count["ratio"] = sequential(float64(v.ScaleTotal.DocCount), float64(doccount))
+			amount["ratio"] = sequential(v.ScaleAmount.Value, amountvalue)
+		}
+		count_ss = append(count_ss, count)
+		amout_ss = append(amout_ss, amount)
+	}
+	rMapData := make(map[string]interface{})
+	rMapData["project_count"] = count_ss
+	rMapData["project_amount"] = amout_ss
+	return rMapData
+}
+
+func amountDistribution(v float64, data map[string]*distributionTrend) {
+	if v <= 0 {
+		return
+	}
+	if v < 100000 {
+		if data["<10万"] == nil {
+			data["<10万"] = new(distributionTrend)
+		}
+		data["<10万"].Amount += v
+		data["<10万"].Count++
+	} else if v < 500000 {
+		if data["10万-50万"] == nil {
+			data["10万-50万"] = new(distributionTrend)
+		}
+		data["10万-50万"].Amount += v
+		data["10万-50万"].Count++
+	} else if v < 1000000 {
+		if data["50万-100万"] == nil {
+			data["50万-100万"] = new(distributionTrend)
+		}
+		data["50万-100万"].Amount += v
+		data["50万-100万"].Count++
+	} else if v < 1000000*5 {
+		if data["100万-500万"] == nil {
+			data["100万-500万"] = new(distributionTrend)
+		}
+		data["100万-500万"].Amount += v
+		data["100万-500万"].Count++
+	} else if v < 1000000*10 {
+		if data["500万-1000万"] == nil {
+			data["500万-1000万"] = new(distributionTrend)
+		}
+		data["500万-1000万"].Amount += v
+		data["500万-1000万"].Count++
+	} else if v < 100000000 {
+		if data["1000万-1亿"] == nil {
+			data["1000万-1亿"] = new(distributionTrend)
+		}
+		data["1000万-1亿"].Amount += v
+		data["1000万-1亿"].Count++
+	} else if v >= 100000000 {
+		if data["≥1亿"] == nil {
+			data["≥1亿"] = new(distributionTrend)
+		}
+		data["≥1亿"].Amount += v
+		data["≥1亿"].Count++
+	}
+
+}
+
+type BuyerWinnerRow struct {
+	BuyerAmountDistribution struct {
+		Buckets []struct {
+			Key      string `json:"key"`
+			DocCount int    `json:"doc_count"`
+			Amount   struct {
+				Value float64 `json:"value"`
+			} `json:"amount"`
+		} `json:"buckets"`
+	} `json:"buyer_amount_distribution"`
+
+	ProjectAmount struct {
+		Value float64 `json:"value"`
+	} `json:"project_amount"`
+	BuyerCountTop3 struct {
+		Buckets []struct {
+			Key        string `json:"key"`
+			BuyerCount struct {
+				//Value int64 `json:"value"`
+				Value int64 `json:"doc_count"`
+			} `json:"buyer_count"`
+			SWinnerTop struct {
+				Buckets []struct {
+					Key           string `json:"key"`
+					DocCount      int64  `json:"doc_count"`
+					ProjectDetail struct {
+						Hits struct {
+							Total    int `json:"total"`
+							MaxScore int `json:"max_score"`
+							Hits     []struct {
+								Source struct {
+									Entidlist []string `json:"entidlist"`
+									SWinner   string   `json:"s_winner"`
+								} `json:"_source"`
+							} `json:"hits"`
+						} `json:"hits"`
+					} `json:"project_detail"`
+					BuyerWinnerAmount struct {
+						//Value int64 `json:"value"`
+						Value int64 `json:"doc_count"`
+					} `json:"buyer_winner_count"`
+				} `json:"buckets"`
+				Value float64 `json:"value"`
+			} `json:"s_winner_top"`
+		} `json:"buckets"`
+	} `json:"buyer_count_top3"`
+	BuyerAmountTop3 struct {
+		Buckets []struct {
+			Key         string `json:"key"`
+			BuyerAmount struct {
+				Value float64 `json:"value"`
+			} `json:"buyer_amount"`
+			SWinnerTop struct {
+				Buckets []struct {
+					Key           string `json:"key"`
+					DocCount      int64  `json:"doc_count"`
+					ProjectDetail struct {
+						Hits struct {
+							Total    int `json:"total"`
+							MaxScore int `json:"max_score"`
+							Hits     []struct {
+								Source struct {
+									Entidlist []string `json:"entidlist"`
+									SWinner   string   `json:"s_winner"`
+								} `json:"_source"`
+							} `json:"hits"`
+						} `json:"hits"`
+					} `json:"project_detail"`
+					BuyerWinnerAmount struct {
+						Value float64 `json:"value"`
+					} `json:"buyer_winner_amount"`
+				} `json:"buckets"`
+				Value float64 `json:"value"`
+			} `json:"s_winner_top"`
+		} `json:"buckets"`
+	} `json:"buyer_amount_top3"`
+	WinnerAmountDistribution struct {
+		Buckets []struct {
+			Key      string `json:"key"`
+			DocCount int    `json:"doc_count"`
+			Amount   struct {
+				Value float64 `json:"value"`
+			} `json:"amount"`
+		} `json:"buckets"`
+	} `json:"winner_amount_distribution"`
+	WinnerCountTop3 struct {
+		SWinnerCount []struct {
+			Key           string `json:"key"`
+			ProjectDetail struct {
+				Hits struct {
+					Total    int `json:"total"`
+					MaxScore int `json:"max_score"`
+					Hits     []struct {
+						Id     string `json:"_id"`
+						Source struct {
+							Entidlist []string `json:"entidlist"`
+							SWinner   string   `json:"s_winner"`
+						} `json:"_source"`
+					} `json:"hits"`
+				} `json:"hits"`
+			} `json:"project_detail"`
+			BuyerCount struct {
+				//Value int64 `json:"value"`
+				Value int64 `json:"doc_count"`
+			} `json:"s_winner_count"`
+			BuyerTop struct {
+				Buckets []struct {
+					Key               string `json:"key"`
+					DocCount          int64  `json:"doc_count"`
+					BuyerWinnerAmount struct {
+						//Value int64 `json:"value"`
+						Value int64 `json:"doc_count"`
+					} `json:"buyer_winner_count"`
+				} `json:"buckets"`
+				Value float64 `json:"value"`
+			} `json:"buyer_top"`
+		} `json:"buckets"`
+	} `json:"winner_count_top3"`
+	WinnerAmountTop3 struct {
+		SWinnerAmount []struct {
+			Key           string `json:"key"`
+			ProjectDetail struct {
+				Hits struct {
+					Total    int `json:"total"`
+					MaxScore int `json:"max_score"`
+					Hits     []struct {
+						Source struct {
+							Entidlist []string `json:"entidlist"`
+							SWinner   string   `json:"s_winner"`
+						} `json:"_source"`
+					} `json:"hits"`
+				} `json:"hits"`
+			} `json:"project_detail"`
+			SWinnerAmount struct {
+				Value float64 `json:"value"`
+			} `json:"s_winner_amount"`
+			BuyerTop struct {
+				Buckets []struct {
+					Key               string `json:"key"`
+					DocCount          int64  `json:"doc_count"`
+					BuyerWinnerAmount struct {
+						Value float64 `json:"value"`
+					} `json:"buyer_winner_amount"`
+				} `json:"buckets"`
+				Value float64 `json:"value"`
+			} `json:"buyer_top"`
+		} `json:"buckets"`
+	} `json:"winner_amount_top3"`
+}
+
+// 采购单位分析
+func (mae *MarketAnalysisEntity) BuyerWinnerAnalysis() map[string]interface{} {
+	var datas []string
+	//采购单位-采购规模分布
+	//buyer_scalefmt := fmt.Sprintf(buyer_procurement_scale, sortprice_str)
+
+	//采购单位-项目数量 采购单位-项目金额
+	datas = append(datas, buyer_procurement_scale, buyer_count, buyer_sortprice)
+	//中标单位-规模分布
+	//winner_scalefmt := fmt.Sprintf(winner_procurement_scale, sortprice_str)
+
+	//中标单位-项目数量 中标单位-项目金额
+	datas = append(datas, winner_procurement_scale, winner_count, winner_sortprice)
+	finalSql := fmt.Sprintf(mae.GetCommonQuerySqlWithAggs(), strings.Join(datas, ","))
+	log.Printf("final PurchasingAnalysiseQuery sql: %s", finalSql)
+	res, _ := util.GetAggs("projectset", "projectset", finalSql)
+	if res == nil || len(res) == 0 {
+		return nil
+	}
+	var thisBuyerWinnerRow BuyerWinnerRow
+	for name, object := range res {
+		bArr, err := object.MarshalJSON()
+		if len(bArr) == 0 || err != nil {
+			continue
+		}
+		if name == "project_amount" {
+			if json.Unmarshal(bArr, &thisBuyerWinnerRow.ProjectAmount) != nil {
+				continue
+			}
+		} else if name == "buyer_amount_distribution" {
+			if json.Unmarshal(bArr, &thisBuyerWinnerRow.BuyerAmountDistribution) != nil {
+				continue
+			}
+		} else if name == "buyer_count_top3" {
+			if json.Unmarshal(bArr, &thisBuyerWinnerRow.BuyerCountTop3) != nil {
+				continue
+			}
+		} else if name == "buyer_amount_top3" {
+			if json.Unmarshal(bArr, &thisBuyerWinnerRow.BuyerAmountTop3) != nil {
+				continue
+			}
+		} else if name == "winner_amount_distribution" {
+			if json.Unmarshal(bArr, &thisBuyerWinnerRow.WinnerAmountDistribution) != nil {
+				continue
+			}
+		} else if name == "winner_count_top3" {
+			if json.Unmarshal(bArr, &thisBuyerWinnerRow.WinnerCountTop3) != nil {
+				continue
+			}
+		} else if name == "winner_amount_top3" {
+			if json.Unmarshal(bArr, &thisBuyerWinnerRow.WinnerAmountTop3) != nil {
+				continue
+			}
+		}
+	}
+	var winnerKeys []string
+	winnerKeyMap := make(map[string]int)
+	for _, v := range thisBuyerWinnerRow.BuyerCountTop3.Buckets {
+		for _, v1 := range v.SWinnerTop.Buckets {
+			winnerKeyMap[v1.Key]++
+		}
+	}
+	for _, v := range thisBuyerWinnerRow.BuyerAmountTop3.Buckets {
+		for _, v1 := range v.SWinnerTop.Buckets {
+			winnerKeyMap[v1.Key]++
+		}
+	}
+	for _, v := range thisBuyerWinnerRow.WinnerCountTop3.SWinnerCount {
+		winnerKeyMap[v.Key]++
+	}
+	for _, v := range thisBuyerWinnerRow.WinnerAmountTop3.SWinnerAmount {
+		winnerKeyMap[v.Key]++
+	}
+	for k, _ := range winnerKeyMap {
+		winnerKeys = append(winnerKeys, k)
+	}
+	winnerName := GetEntNameByIds(winnerKeys)
+	rMap := make(map[string]interface{})
+	BuyerAnalysis(thisBuyerWinnerRow, rMap, winnerName)
+	WinningAnalysis(thisBuyerWinnerRow, rMap, winnerName)
+	return rMap
+}
+
+type distributionTrend struct {
+	Key    string
+	Count  int
+	Amount float64
+}
+
+var Analysis = []string{"<10万", "10万-50万", "50万-100万", "100万-500万", "500万-1000万", "1000万-1亿", "≥1亿"}
+
+func BuyerAnalysis(thisBuyerRow BuyerWinnerRow, rMap map[string]interface{}, winnerName map[string]string) {
+	type buyer struct {
+		Name        string      `json:"key"`
+		TotalAmount interface{} `json:"total_amount"`
+		TotalNumber interface{} `json:"total_number"`
+	}
+	//采购单位-采购规模分布
+	buyerMap := []interface{}{}
+
+	//计算采购单位各区间金额
+	buyerA := make(map[string]*distributionTrend)
+	for _, v := range thisBuyerRow.BuyerAmountDistribution.Buckets {
+		amountDistribution(v.Amount.Value, buyerA)
+	}
+	var count_b int
+	for _, v := range buyerA {
+		count_b = count_b + v.Count
+	}
+
+	for _, v := range Analysis {
+		var data buyer
+		data.Name = v
+		if vlu, ok := buyerA[v]; ok && count_b != 0 {
+			data.TotalNumber = float64(vlu.Count) / float64(count_b)
+		}
+		if vlu, ok := buyerA[v]; ok && thisBuyerRow.ProjectAmount.Value != 0 {
+			data.TotalAmount = vlu.Amount / thisBuyerRow.ProjectAmount.Value
+		}
+		buyerMap = append(buyerMap, data)
+	}
+
+	type number_projects struct {
+		Name   string `json:"name"`
+		Number int64  `json:"number"`
+		//Accounted interface{} `json:"accounted"`
+		Data interface{} `json:"winnertop3"`
+	}
+	type number_project struct {
+		Id     interface{} `json:"id"`
+		Name   string      `json:"name"`
+		Number int64       `json:"number"`
+		//Accounted interface{} `json:"accounted"`
+	}
+
+	//采购单位-项目数量TOP3
+	countMap := []interface{}{}
+	for _, v := range thisBuyerRow.BuyerCountTop3.Buckets {
+		var _d number_projects
+		_d.Name = v.Key
+		_d.Number = v.BuyerCount.Value
+		/*if thisBuyerRow.ProjectCount.Value != 0 {
+			_d.Accounted = float64(v.BuyerCount.Value) / float64(thisBuyerRow.ProjectCount.Value)
+		}*/
+		var ss []interface{}
+		for _, v1 := range v.SWinnerTop.Buckets {
+			var _dd number_project
+			_dd.Number = v1.BuyerWinnerAmount.Value
+			if winnerName[v1.Key] == "" {
+				continue
+			}
+			_dd.Name = winnerName[v1.Key]
+			_dd.Id = util.EncodeId(v1.Key)
+
+			/*if _d.Number != 0 {
+				_dd.Accounted = float64(v1.BuyerWinnerAmount.Value) / float64(_d.Number)
+			}*/
+			ss = append(ss, _dd)
+		}
+		_d.Data = ss
+		countMap = append(countMap, _d)
+	}
+
+	//采购单位-项目金额TOP3
+	type amount_projects struct {
+		Name   string  `json:"name"`
+		Amount float64 `json:"amount"`
+		//Accounted interface{} `json:"accounted"`
+		Data interface{} `json:"winnertop3"`
+	}
+	type amount_project struct {
+		Id     interface{} `json:"id"`
+		Name   string      `json:"name"`
+		Amount float64     `json:"amount"`
+		//Accounted interface{} `json:"accounted"`
+	}
+	amountMap := []interface{}{}
+	for _, v := range thisBuyerRow.BuyerAmountTop3.Buckets {
+		if v.BuyerAmount.Value == 0 {
+			continue
+		}
+		var _d amount_projects
+		_d.Name = v.Key
+		_d.Amount = v.BuyerAmount.Value
+		/*if thisBuyerRow.ProjectAmount.Value != 0 {
+			_d.Accounted = v.BuyerAmount.Value / thisBuyerRow.ProjectAmount.Value
+		}*/
+
+		var ss []interface{}
+		for _, v1 := range v.SWinnerTop.Buckets {
+			if v1.BuyerWinnerAmount.Value == 0 || winnerName[v1.Key] == "" {
+				continue
+			}
+			var _dd amount_project
+			_dd.Amount = v1.BuyerWinnerAmount.Value
+
+			_dd.Name = winnerName[v1.Key]
+			_dd.Id = util.EncodeId(v1.Key)
+			/*	if _d.Amount != 0 {
+				_dd.Accounted = v1.BuyerWinnerAmount.Value / _d.Amount
+			}*/
+
+			ss = append(ss, _dd)
+		}
+		_d.Data = ss
+		amountMap = append(amountMap, _d)
+	}
+	rMap["buyer_time_distribution"] = buyerMap
+	rMap["buyer_count_top3"] = countMap
+	rMap["buyer_amount_top3"] = amountMap
+}
+
+//中标单位分析
+func WinningAnalysis(thisWinnerRow BuyerWinnerRow, rMap map[string]interface{}, winnerName map[string]string) {
+	type s_Winner struct {
+		Name        string      `json:"key"`
+		TotalAmount interface{} `json:"total_amount"`
+		TotalNumber interface{} `json:"total_number"`
+	}
+	//中标单位-中标规模分布
+	winnerA := make(map[string]*distributionTrend)
+	for _, v := range thisWinnerRow.WinnerAmountDistribution.Buckets {
+		amountDistribution(v.Amount.Value, winnerA)
+	}
+	var count_b int
+	for _, v := range winnerA {
+		count_b = count_b + v.Count
+	}
+	buyerMap := []interface{}{}
+	for _, v := range Analysis {
+		var data s_Winner
+		data.Name = v
+		if vlu, ok := winnerA[v]; ok && count_b != 0 {
+			data.TotalNumber = float64(vlu.Count) / float64(count_b)
+		}
+		if vlu, ok := winnerA[v]; ok && thisWinnerRow.ProjectAmount.Value != 0 {
+			data.TotalAmount = vlu.Amount / thisWinnerRow.ProjectAmount.Value
+		}
+		buyerMap = append(buyerMap, data)
+	}
+
+	type number_projects struct {
+		Id     interface{} `json:"id"`
+		Name   string      `json:"name"`
+		Number int64       `json:"number"`
+		//Accounted interface{} `json:"accounted"`
+		Data interface{} `json:"buyertop3"`
+	}
+	type number_project struct {
+		Name   string `json:"name"`
+		Number int64  `json:"number"`
+		//Accounted interface{} `json:"accounted"`
+	}
+
+	//中标单位-项目数量TOP3
+	countMap := []interface{}{}
+	for _, v := range thisWinnerRow.WinnerCountTop3.SWinnerCount {
+		var _d number_projects
+		_d.Number = v.BuyerCount.Value
+		if winnerName[v.Key] == "" {
+			continue
+		}
+		_d.Name = winnerName[v.Key]
+		_d.Id = util.EncodeId(v.Key)
+		/*if thisWinnerRow.ProjectCount.Value != 0 {
+			_d.Accounted = float64(v.BuyerCount.Value) / float64(thisWinnerRow.ProjectCount.Value)
+		}*/
+
+		var ss []interface{}
+		for _, v1 := range v.BuyerTop.Buckets {
+			var _dd number_project
+			_dd.Name = v1.Key
+			_dd.Number = v1.BuyerWinnerAmount.Value
+			/*if _d.Number != 0 {
+				_dd.Accounted = float64(v1.BuyerWinnerAmount.Value) / float64(_d.Number)
+			}*/
+			ss = append(ss, _dd)
+		}
+		_d.Data = ss
+		countMap = append(countMap, _d)
+	}
+
+	//中标单位-项目金额TOP3
+	type amount_projects struct {
+		Id     interface{} `json:"id"`
+		Name   string      `json:"name"`
+		Amount float64     `json:"amount"`
+		//Accounted interface{} `json:"accounted"`
+		Data interface{} `json:"buyertop3"`
+	}
+	type buyertop3 struct {
+		Name   string  `json:"name"`
+		Amount float64 `json:"amount"`
+		//Accounted interface{} `json:"accounted"`
+	}
+	amountMap := []interface{}{}
+	for _, v := range thisWinnerRow.WinnerAmountTop3.SWinnerAmount {
+		if v.SWinnerAmount.Value == 0 || winnerName[v.Key] == "" {
+			continue
+		}
+		var _d amount_projects
+		_d.Amount = v.SWinnerAmount.Value
+		_d.Name = winnerName[v.Key]
+		_d.Id = util.EncodeId(v.Key)
+		/*if thisWinnerRow.ProjectAmount.Value != 0 {
+			_d.Accounted = v.SWinnerAmount.Value / thisWinnerRow.ProjectAmount.Value
+		}*/
+
+		var ss []interface{}
+		for _, v1 := range v.BuyerTop.Buckets {
+			if v1.BuyerWinnerAmount.Value == 0 {
+				continue
+			}
+			var _dd buyertop3
+			_dd.Name = v1.Key
+			_dd.Amount = v1.BuyerWinnerAmount.Value
+			/*if _d.Amount != 0 {
+				_dd.Accounted = v1.BuyerWinnerAmount.Value / _d.Amount
+			}*/
+			ss = append(ss, _dd)
+		}
+		_d.Data = ss
+		amountMap = append(amountMap, _d)
+	}
+	rMap["winner_time_distribution"] = buyerMap
+	rMap["winner_count_top3"] = countMap
+	rMap["winner_amount_top3"] = amountMap
+}

+ 577 - 0
src/jfw/modules/bigmember/src/entity/marketAnalysis/customized_analysis.go

@@ -0,0 +1,577 @@
+package marketAnalysis
+
+import (
+	"encoding/json"
+	"fmt"
+	"qfw/util"
+	"qfw/util/elastic"
+	"strings"
+	util2 "util"
+)
+
+const (
+	query_aggs_sortprice       = `"sortprice_ranges": {"range":{"field":"sortprice","ranges":[%s]},"aggs":{"sum_sortprice":{"sum":{"field":"sortprice"}}}}`
+	aggs_area                  = `"area_distribution": {"terms": {"field": "area"},"aggs": {"area_amount": {"sum": {"field": "sortprice"}},"area_total": {"filter": {}}}}`
+	query_top10                = `,"sort": [{"sortprice": "desc"}],"from": 0,"size": 10`
+	aggs_area_amounttop3       = `"area_amount_top3":{"terms":{"field":"area","exclude":["全国"],"order":[{"area_amount":"desc"}],"size":3},"aggs":{"area_amount":{"sum":{"field":"sortprice"}},"winner_top":{"terms":{"field":"entidlist","exclude": ["-"],"order":[{"area_winner_amount":"desc"}],"size":3},"aggs":{"area_winner_amount":{"sum":{"field":"sortprice"}}}}}}`
+	aggs_area_counttop3        = `"area_count_top3":{"terms":{"field":"area","exclude":["全国"],"order":[{"area_count":"desc"}],"size":3},"aggs":{"area_count":{"filter":{}},"winner_top":{"terms":{"field":"entidlist","exclude": ["-"],"order":[{"area_winner_count":"desc"}],"size":3},"aggs":{"area_winner_count":{"filter":{}}}}}}`
+	aggs_buyerclass            = `"buyerclass_scale":{"terms":{"field":"buyerclass","exclude":["其它",""]},"aggs":{"buyerclass_amount":{"sum":{"field":"sortprice"}},"buyerclass_total":{"filter":{}}}}`
+	aggs_buyerclass_counttop3  = `"buyerclass_count_top3":{"terms":{"field":"buyerclass","exclude":["其它",""],"order":[{"buyerclass_count":"desc"}],"size":3},"aggs":{"buyerclass_count":{"filter":{}},"bidcount_top":{"terms":{"field":"entidlist","exclude": ["-"],"order":[{"buyer_winner_count":"desc"}],"size":3},"aggs":{"buyer_winner_count":{"filter":{}}}}}}`
+	aggs_buyerclass_amounttop3 = `"buyerclass_amount_top3":{"terms":{"field":"buyerclass","exclude":["其它",""],"order":[{"buyerclass_amount":"desc"}],"size":3},"aggs":{"buyerclass_amount":{"sum":{"field":"sortprice"}},"winner_top":{"terms":{"field":"entidlist","exclude": ["-"],"order":[{"buyer_winner_amount":"desc"}],"size":3},"aggs":{"buyer_winner_amount":{"sum":{"field":"sortprice"}}}}}}`
+	sortprice_str              = `{"key":"<10万","from":0.0000000000001,"to":100000},{"key":"10万-50万","from":100000,"to":500000},{"key":"50万-100万","from":500000,"to":1000000},{"key":"100万-500万","from":1000000,"to":5000000},{"key":"500万-1000万","from":5000000,"to":10000000},{"key":"1000万-1亿","from":10000000,"to":100000000},{"key":"≥1亿","from":100000000}`
+	aggs_all_c_m               = `"project_count": {"filter": {}},"project_count_not0": {"filter": {"range": {"sortprice": {"gt": 0}}}},"project_amount": {"sum": {"field": "sortprice"}}`
+	query_id                   = `{"query": {"bool": {"must": [{"term": {"entidlist": "%s"}}]}},"size": 1}`
+	query_idto                 = `{"query": {"bool": {"must": [{"terms": {"qyxy.id": ["%s"]}}]}},"_source":["_id","company_name"],"size": %d}`
+)
+
+type AreaCTop struct {
+	Total     int64 `json:"doc_count"`
+	CountNot0 struct {
+		Count int64 `json:"doc_count"`
+	} `json:"project_count_not0"`
+	Amount struct {
+		Value float64 `json:"value"`
+	} `json:"project_amount"`
+	SortpriceRanges struct {
+		Buckets []struct {
+			Name         string `json:"key"`
+			Total        int64  `json:"doc_count"`
+			SumSortprice struct {
+				Value float64 `json:"value"`
+			} `json:"sum_sortprice"`
+		}
+	} `json:"sortprice_ranges"`
+	AreaDistribution struct {
+		Buckets []struct {
+			Area       string `json:"key"`
+			AreaTotal  int64  `json:"doc_count"`
+			AreaAmount struct {
+				Value float64 `json:"value"`
+			} `json:"area_amount"`
+			BuyclassAmount struct {
+				Value float64 `json:"value"`
+			} `json:"buyerclass_amount"`
+		}
+	} `json:"area_distribution"`
+	BuyerclassScale struct {
+		Buckets []struct {
+			Area       string `json:"key"`
+			AreaTotal  int64  `json:"doc_count"`
+			AreaAmount struct {
+				Value float64 `json:"value"`
+			} `json:"area_amount"`
+			BuyclassAmount struct {
+				Value float64 `json:"value"`
+			} `json:"buyerclass_amount"`
+		}
+	} `json:"buyerclass_scale"`
+	AreaAmountTop3 struct {
+		Buckets []struct {
+			Key        string `json:"key"`
+			Total      int64  `json:"doc_count"`
+			AreaAmount struct {
+				Amount float64 `json:"value"`
+			} `json:"area_amount"`
+			WinnerTop struct {
+				Buckets []struct {
+					Winner       string `json:"key"`
+					WinnerTotal  int64  `json:"doc_count"`
+					WinnerAmount struct {
+						Amount float64 `json:"value"`
+					} `json:"area_winner_amount"`
+					ProjectDetail struct {
+						Hits struct {
+							Hits []struct {
+								Source struct {
+									Entidlist []string `json:"entidlist"`
+									SWinner   string   `json:"s_winner"`
+								} `json:"_source"`
+							}
+						}
+					} `json:"project_detail"`
+				}
+			} `json:"winner_top"`
+		}
+	} `json:"area_amount_top3"`
+	AreaCountTop3 struct {
+		Buckets []struct {
+			Area      string `json:"key"`
+			Total     int64  `json:"doc_count"`
+			WinnerTop struct {
+				Buckets []struct {
+					Winner        string `json:"key"`
+					WinnerTotal   int64  `json:"doc_count"`
+					ProjectDetail struct {
+						Hits struct {
+							Hits []struct {
+								Source struct {
+									Entidlist []string `json:"entidlist"`
+									SWinner   string   `json:"s_winner"`
+								} `json:"_source"`
+							}
+						}
+					} `json:"project_detail"`
+				}
+			} `json:"winner_top"`
+		}
+	} `json:"area_count_top3"`
+	BuyclassAmountTop3 struct {
+		Buckets []struct {
+			Key        string `json:"key"`
+			Total      int64  `json:"doc_count"`
+			AreaAmount struct {
+				Amount float64 `json:"value"`
+			} `json:"buyerclass_amount"`
+			WinnerTop struct {
+				Buckets []struct {
+					Winner       string `json:"key"`
+					WinnerTotal  int64  `json:"doc_count"`
+					WinnerAmount struct {
+						Amount float64 `json:"value"`
+					} `json:"buyer_winner_amount"`
+					ProjectDetail struct {
+						Hits struct {
+							Hits []struct {
+								Source struct {
+									Entidlist []string `json:"entidlist"`
+									SWinner   string   `json:"s_winner"`
+								} `json:"_source"`
+							}
+						}
+					} `json:"project_detail"`
+				}
+			} `json:"winner_top"`
+		}
+	} `json:"buyerclass_amount_top3"`
+	BuyclassCountTop3 struct {
+		Buckets []struct {
+			Buyclass    string `json:"key"`
+			Total       int64  `json:"doc_count"`
+			BidcountTop struct {
+				Buckets []struct {
+					Winner        string `json:"key"`
+					WinnerTotal   int64  `json:"doc_count"`
+					ProjectDetail struct {
+						Hits struct {
+							Hits []struct {
+								Source struct {
+									Entidlist []string `json:"entidlist"`
+									SWinner   string   `json:"s_winner"`
+								} `json:"_source"`
+							}
+						}
+					} `json:"project_detail"`
+				}
+			} `json:"bidcount_top"`
+		}
+	} `json:"buyerclass_count_top3"`
+}
+
+//企业id查企业名
+func IdToWinner(id string) (entname string) {
+	finalSql := fmt.Sprintf(query_id, id)
+	hits := elastic.Get("projectset", "projectset", finalSql)
+	source := *hits
+	var idx int
+	entname = ""
+	if len(source) > 0 {
+		res := source[0]
+		for i, vv := range InterToSliceString(res["entidlist"]) {
+			if vv == id {
+				idx = i
+				break
+			}
+		}
+		w_s := strings.Split(util.ObjToString(res["s_winner"]), ",")
+		if len(w_s) > 0 && len(w_s) > idx {
+			entname = w_s[idx]
+		}
+	}
+	return
+}
+
+//企业id查企业名 传入数组
+func IDToName(ids []string) (iMap map[string]string) {
+	iMap = map[string]string{}
+	d := strings.Join(ids, `","`)
+	finalSql := fmt.Sprintf(query_idto, d, len(ids))
+	hits := elastic.Get("qyxy", "qyxy", finalSql)
+	if hits == nil || len(*hits) == 0 {
+		return
+	}
+	for _, item := range *hits {
+		id, _ := item["_id"].(string)
+		name, _ := item["company_name"].(string)
+		if id != "" && name != "" {
+			iMap[id] = name
+		}
+	}
+	return
+}
+
+func (mae *MarketAnalysisEntity) AllData() (rMap map[string]interface{}, err error) {
+	rMap = map[string]interface{}{}
+	var aggs []string
+	area := mae.FormatParam.Area
+	city := mae.FormatParam.City
+	buyclass := mae.FormatParam.BuyerClass
+	aggs = append(aggs, aggs_all_c_m, fmt.Sprintf(query_aggs_sortprice, sortprice_str))
+	if (len(area) + len(city)) != 1 {
+		aggs = append(aggs, aggs_area, aggs_area_amounttop3, aggs_area_counttop3)
+	}
+	if len(buyclass) != 1 {
+		aggs = append(aggs, aggs_buyerclass, aggs_buyerclass_amounttop3, aggs_buyerclass_counttop3)
+	}
+	finalSql := fmt.Sprintf(mae.GetCommonQuerySqlWithAggs(), strings.Join(aggs, ","))
+	res, _ := util2.GetAggs("projectset", "projectset", finalSql)
+	if res == nil || len(res) == 0 {
+		return
+	}
+	thisRow := AreaCTop{}
+	for name, object := range res {
+		bArr, err := object.MarshalJSON()
+		if len(bArr) == 0 || err != nil {
+			continue
+		}
+		if name == "project_amount" {
+			if json.Unmarshal(bArr, &thisRow.Amount) != nil {
+				continue
+			}
+		} else if name == "project_count" {
+			if json.Unmarshal(bArr, &thisRow) != nil {
+				continue
+			}
+		} else if name == "project_count_not0" {
+			if json.Unmarshal(bArr, &thisRow.CountNot0) != nil {
+				continue
+			}
+		} else if name == "sortprice_ranges" {
+			if json.Unmarshal(bArr, &thisRow.SortpriceRanges) != nil {
+				continue
+			}
+		} else if name == "area_distribution" {
+			if json.Unmarshal(bArr, &thisRow.AreaDistribution) != nil {
+				continue
+			}
+		} else if name == "buyerclass_scale" {
+			if json.Unmarshal(bArr, &thisRow.BuyerclassScale) != nil {
+				continue
+			}
+		} else if name == "area_amount_top3" {
+			if json.Unmarshal(bArr, &thisRow.AreaAmountTop3) != nil {
+				continue
+			}
+		} else if name == "area_count_top3" {
+			if json.Unmarshal(bArr, &thisRow.AreaCountTop3) != nil {
+				continue
+			}
+		} else if name == "buyerclass_amount_top3" {
+			if json.Unmarshal(bArr, &thisRow.BuyclassAmountTop3) != nil {
+				continue
+			}
+		} else if name == "buyerclass_count_top3" {
+			if json.Unmarshal(bArr, &thisRow.BuyclassCountTop3) != nil {
+				continue
+			}
+		}
+	}
+	data := ProjectScale(thisRow)
+	area_data := AreaDistribute(thisRow)
+	customer_data := CustomerDistribute(thisRow)
+	var ids []string
+	for _, v := range thisRow.AreaAmountTop3.Buckets {
+		for _, va := range v.WinnerTop.Buckets {
+			ids = append(ids, va.Winner)
+		}
+	}
+	for _, v := range thisRow.BuyclassAmountTop3.Buckets {
+		for _, va := range v.WinnerTop.Buckets {
+			ids = append(ids, va.Winner)
+		}
+	}
+	for _, v := range thisRow.AreaCountTop3.Buckets {
+		for _, va := range v.WinnerTop.Buckets {
+			ids = append(ids, va.Winner)
+		}
+	}
+	for _, v := range thisRow.BuyclassCountTop3.Buckets {
+		for _, va := range v.BidcountTop.Buckets {
+			ids = append(ids, va.Winner)
+		}
+	}
+	eid := IDToName(ids)
+	rMap["projectScale"] = data
+	rMap["area_infos"] = area_data
+	rMap["customer_scale"] = customer_data
+	rMap["scaleAreaAmountTop"] = AmountCompute(thisRow, "area", eid)
+	rMap["scaleBuyclassAmountTop"] = AmountCompute(thisRow, "buyclass", eid)
+	rMap["scaleAreaCountTop"] = CountCompute(thisRow, "area", eid)
+	rMap["scaleBuyclassCountTop"] = CountCompute(thisRow, "buyclass", eid)
+	return
+}
+
+//项目规模分布
+func ProjectScale(thisRow AreaCTop) (data []interface{}) {
+	ammount := thisRow.Amount.Value
+	total := thisRow.CountNot0.Count
+	buckets := thisRow.SortpriceRanges.Buckets
+	type Scale struct {
+		Name      string
+		Persent_c float64
+		Persent_a float64
+	}
+	for _, v := range buckets {
+		name := v.Name
+		percent_a := Formula(float64(v.Total), float64(total))
+		percent_c := Formula(v.SumSortprice.Value, ammount)
+		sc := Scale{
+			Name:      name,
+			Persent_c: percent_c,
+			Persent_a: percent_a,
+		}
+		data = append(data, sc)
+	}
+	return
+}
+
+func InterToSliceString(obj interface{}) []string {
+	var sli = make([]string, 0)
+	if obj == nil {
+		return sli
+	}
+
+	if _, ok := obj.([]interface{}); ok {
+		for _, i := range obj.([]interface{}) {
+			sli = append(sli, i.(string))
+		}
+	}
+
+	if _, ok := obj.([]string); ok {
+		return obj.([]string)
+	}
+
+	return sli
+}
+
+//top10
+func (mae *MarketAnalysisEntity) ProjectTop10() (rMap map[string]interface{}, err error) {
+	finalSql := fmt.Sprintf(mae.GetCommonQuerySql(), query_top10)
+	hits := elastic.Get("projectset", "projectset", finalSql)
+	rMap = map[string]interface{}{}
+	bArr := []map[string]interface{}{}
+	source := *hits
+	for _, v := range source {
+		bA := map[string]interface{}{}
+		if v["ids"] != nil && len(InterToSliceString(v["ids"])) > 0 {
+			idss := InterToSliceString(v["ids"])
+			bA["_id"] = util2.EncodeId(idss[len(idss)-1])
+		} else {
+			bA["_id"] = nil
+		}
+		if v["area"] == "" {
+			bA["city"] = nil
+		} else {
+			bA["area"] = v["area"]
+		}
+		if v["city"] == "" {
+			bA["city"] = nil
+		} else {
+			bA["city"] = v["city"]
+		}
+		bA["jgtime"] = v["jgtime"]
+		bA["projectname"] = v["s_projectname"]
+		bA["sortprice"] = v["sortprice"]
+		ids := v["entidlist"]
+		var id_s []string
+		var winner_s []string
+		for _, i := range InterToSliceString(ids) {
+			iid := util2.EncodeId(i)
+			id_s = append(id_s, iid)
+		}
+		bA["eidlist"] = id_s
+		bA["winner_s"] = nil
+		if util.ObjToString(v["s_winner"]) != "" {
+			w_s := strings.Split(util.ObjToString(v["s_winner"]), ",")
+			for _, vv := range w_s {
+				winner_s = append(winner_s, vv)
+			}
+			bA["winner_s"] = winner_s
+		}
+		bArr = append(bArr, bA)
+	}
+	rMap["ProjectTop10"] = bArr
+	return
+}
+
+//地区分布
+func AreaDistribute(thisRow AreaCTop) (data []map[string]interface{}) {
+	for _, v := range thisRow.AreaDistribution.Buckets {
+		rM := map[string]interface{}{}
+		rM["area"] = v.Area
+		rM["total"] = v.AreaTotal
+		rM["amount"] = v.AreaAmount.Value
+		data = append(data, rM)
+	}
+	return
+}
+
+//客户分布
+func CustomerDistribute(thisRow AreaCTop) (data []map[string]interface{}) {
+	for _, v := range thisRow.BuyerclassScale.Buckets {
+		rM := map[string]interface{}{}
+		rM["buyclass"] = v.Area
+		rM["total"] = v.AreaTotal
+		rM["amount"] = v.BuyclassAmount.Value
+		data = append(data, rM)
+	}
+	return
+}
+
+//top3金额计算
+func AmountCompute(thisRow AreaCTop, types string, eid map[string]string) (rData []map[string]interface{}) {
+	if types == "area" {
+		area_infos := thisRow.AreaAmountTop3
+		for _, v := range area_infos.Buckets {
+			if v.AreaAmount.Amount == 0 {
+				break
+			}
+			rM := map[string]interface{}{}
+			rWinner := []map[string]interface{}{}
+			rM["name"] = v.Key
+			rM["area_amount"] = v.AreaAmount.Amount
+			for _, va := range v.WinnerTop.Buckets {
+				if va.WinnerAmount.Amount == 0 {
+					break
+				}
+				rW := map[string]interface{}{}
+				id := util2.EncodeId(va.Winner)
+				rW["id"] = id
+				rW["winner"] = eid[va.Winner]
+				if eid[va.Winner] == "" {
+					continue
+				}
+				rW["winner_amount"] = va.WinnerAmount.Amount
+				//rW["amount_scale"] = va.WinnerAmount.Amount / v.AreaAmount.Amount
+				rWinner = append(rWinner, rW)
+			}
+			rM["winner"] = rWinner
+
+			vv := v.AreaAmount.Amount / thisRow.Amount.Value
+			rM["area_scale"] = vv
+			rData = append(rData, rM)
+		}
+	} else {
+		area_infos := thisRow.BuyclassAmountTop3
+		for _, v := range area_infos.Buckets {
+			if v.AreaAmount.Amount == 0 {
+				break
+			}
+			rM := map[string]interface{}{}
+			rWinner := []map[string]interface{}{}
+			rM["name"] = v.Key
+			rM["buyclass_amount"] = v.AreaAmount.Amount
+			for _, va := range v.WinnerTop.Buckets {
+				if va.WinnerAmount.Amount == 0 {
+					break
+				}
+				rW := map[string]interface{}{}
+				id := util2.EncodeId(va.Winner)
+				rW["id"] = id
+				rW["winner"] = eid[va.Winner]
+				if eid[va.Winner] == "" {
+					continue
+				}
+				rW["winner_amount"] = va.WinnerAmount.Amount
+				//rW["amount_scale"] = va.WinnerAmount.Amount / v.AreaAmount.Amount
+				rWinner = append(rWinner, rW)
+			}
+			rM["winner"] = rWinner
+
+			vv := v.AreaAmount.Amount / thisRow.Amount.Value
+			rM["buyclass_scale"] = vv
+			rData = append(rData, rM)
+		}
+	}
+	return
+}
+
+//top3数量计算
+func CountCompute(thisRow AreaCTop, types string, eid map[string]string) (rData []map[string]interface{}) {
+	if types == "area" {
+		area_infos := thisRow.AreaCountTop3
+		for _, v := range area_infos.Buckets {
+			if v.Total == 0 {
+				break
+			}
+			rM := map[string]interface{}{}
+			rWinner := []map[string]interface{}{}
+			rM["name"] = v.Area
+			rM["area_count"] = v.Total
+			for _, va := range v.WinnerTop.Buckets {
+				if va.WinnerTotal == 0 {
+					break
+				}
+				rW := map[string]interface{}{}
+				id := util2.EncodeId(va.Winner)
+				rW["id"] = id
+				rW["winner"] = eid[va.Winner]
+				if eid[va.Winner] == "" {
+					continue
+				}
+				rW["winner_total"] = va.WinnerTotal
+				rWinner = append(rWinner, rW)
+			}
+			if len(rWinner) == 0 {
+				continue
+			}
+			rM["winner"] = rWinner
+
+			vv := float64(v.Total) / float64(thisRow.Total)
+			rM["area_scale"] = vv
+			rData = append(rData, rM)
+		}
+	} else {
+		area_infos := thisRow.BuyclassCountTop3
+		for _, v := range area_infos.Buckets {
+			if v.Total == 0 {
+				break
+			}
+			rM := map[string]interface{}{}
+			rWinner := []map[string]interface{}{}
+			rM["name"] = v.Buyclass
+			rM["buyclass_count"] = v.Total
+			for _, va := range v.BidcountTop.Buckets {
+				if va.WinnerTotal == 0 {
+					break
+				}
+				rW := map[string]interface{}{}
+				id := util2.EncodeId(va.Winner)
+				rW["id"] = id
+				rW["winner"] = eid[va.Winner]
+				if eid[va.Winner] == "" {
+					continue
+				}
+				rW["winner_total"] = va.WinnerTotal
+				rWinner = append(rWinner, rW)
+			}
+			if len(rWinner) == 0 {
+				continue
+			}
+			rM["winner"] = rWinner
+
+			vv := float64(v.Total) / float64(thisRow.Total)
+			rM["buyclass_scale"] = vv
+			rData = append(rData, rM)
+		}
+	}
+	return
+}
+
+//计算公式
+func Formula(current, total float64) (result float64) {
+	if total == 0 {
+		return 0
+	}
+	result = current / total
+	return
+}

+ 322 - 0
src/jfw/modules/bigmember/src/entity/marketAnalysis/marketAnalysisEntity.go

@@ -0,0 +1,322 @@
+package marketAnalysis
+
+import (
+	"config"
+	"db"
+	"encoding/json"
+	"fmt"
+	"log"
+	"mongodb"
+	qutil "qfw/util"
+	"qfw/util/elastic"
+	"qfw/util/redis"
+	"strings"
+	"time"
+	"util"
+)
+
+const (
+	marketQueryItem      = iota //回显查询条件
+	marketScaleMain             //市场规模
+	marketTopProject            //项目规模TOP10
+	marketProjectAllData        //项目规模 地区分布 客户分布 地区客户top3
+	marketScaleRefine           //细化市场
+	marketBuyerAndWinner        //市场-采购单位&&中标企业
+
+	ReportHistoryTable = "marketAnalysisReport"
+	ReportCacheDB      = "other"
+	ReportCacheKey     = "marketAnalysis_%s_%d"
+	ReportCacheTime    = 60 * 5
+)
+
+var MarketAnalysisPool chan bool
+
+func init() {
+	MarketAnalysisPool = make(chan bool, config.Config.MarketAnalysisPool.Limit)
+	for i := 0; i < config.Config.MarketAnalysisPool.Limit; i++ {
+		MarketAnalysisPool <- true
+	}
+}
+
+//AnalysisRequestParam 接口原请求参数
+type AnalysisRequestParam struct {
+	KeysItemsStr   string //分析内容【字符串】结构和o_member_jy.a_items保持一致
+	RangeTime      string //时间【字符串】 时间戳开始-结束时间戳
+	RangeTimeExtra string //时间【字符串】前段回显使用
+	Area           string //省份【对象字符串】
+	Industry       string //行业【对象字符串】
+	BuyerClass     string //采购单位类型【字符串】多个采购单位类型用逗号拼接
+}
+
+type viewKeyWord struct {
+	Keyword  []string `json:"key"`       //关键词
+	Appended []string `json:"appendkey"` //附加词
+	Exclude  []string `json:"notkey"`    //排除词
+	MatchWay int      `json:"matchway"`  //匹配模式
+}
+
+//keyWordGroup 订阅词结构体
+type keyWordGroup struct {
+	A_Key      []viewKeyWord `json:"a_key"`
+	ItemName   string        `json:"s_item"`
+	UpdateTime int64         `json:"updatetime"`
+}
+
+//AnalysisRequestFormat 格式化后参数
+type AnalysisRequestFormat struct {
+	KeysItems    []keyWordGroup
+	Area, City   []string //省份城市
+	STime, ETime int64    //开始结束时间
+	Industry     []string //行业
+	BuyerClass   []string //采购单位类型
+}
+
+type MarketAnalysisEntity struct {
+	MgoRecordId string
+	BaseParam   AnalysisRequestParam
+	FormatParam AnalysisRequestFormat
+	UId, Pid    string
+}
+
+//ForMatData 获取格式化请求参数
+func (mae *MarketAnalysisEntity) ForMatData() error {
+	//格式化订阅词
+	if err := json.Unmarshal([]byte(mae.BaseParam.KeysItemsStr), &mae.FormatParam.KeysItems); err != nil {
+		return fmt.Errorf("关键词组格式异常")
+	}
+	if mae.FormatParam.KeysItems == nil || len(mae.FormatParam.KeysItems) == 0 {
+		return fmt.Errorf("请选择关键词组")
+	}
+	//格式化时间段
+	if timeArr := strings.Split(mae.BaseParam.RangeTime, "-"); len(timeArr) == 2 {
+		mae.FormatParam.STime = qutil.Int64All(timeArr[0])
+		mae.FormatParam.ETime = qutil.Int64All(timeArr[1])
+		if mae.FormatParam.STime == 0 || mae.FormatParam.ETime == 0 {
+			return fmt.Errorf("开始时间和结束时间不能为空")
+		}
+	} else {
+		return fmt.Errorf("时间戳格式异常")
+	}
+	//格式化省份、城市
+	if areaStr := strings.TrimSpace(mae.BaseParam.Area); areaStr != "" {
+		imap := map[string][]string{}
+		if err := json.Unmarshal([]byte(mae.BaseParam.Area), &imap); err != nil {
+			return fmt.Errorf("非法地区信息")
+		}
+		var city, area []string
+		for name, v := range imap {
+			if len(v) == 0 {
+				area = append(area, name)
+			} else {
+				for _, vv := range v {
+					city = append(city, vv)
+				}
+			}
+		}
+		mae.FormatParam.Area = area
+		mae.FormatParam.City = city
+	}
+	//格式化行业
+	if industryStr := strings.TrimSpace(mae.BaseParam.Industry); industryStr != "" {
+		imap := map[string][]string{}
+		if err := json.Unmarshal([]byte(industryStr), &imap); err != nil {
+			return fmt.Errorf("非法行业信息")
+		}
+		var farr []string
+		for name, v := range imap {
+			for _, vv := range v {
+				farr = append(farr, fmt.Sprintf("%s_%s", name, vv))
+			}
+		}
+		mae.FormatParam.Industry = farr
+	}
+	//格式化类型
+	if buyerClassStr := strings.TrimSpace(mae.BaseParam.BuyerClass); buyerClassStr != "" {
+		mae.FormatParam.BuyerClass = strings.Split(buyerClassStr, ",")
+	}
+	return nil
+}
+
+//SaveAnalysisRecord 保存分析记录
+func (mae *MarketAnalysisEntity) SaveAnalysisRecord() error {
+	mae.MgoRecordId = db.Mgo.Save(ReportHistoryTable, map[string]interface{}{
+		"s_keysItems":      mae.BaseParam.KeysItemsStr,
+		"s_rangeTime":      mae.BaseParam.RangeTime,
+		"s_rangeTimeExtra": mae.BaseParam.RangeTimeExtra,
+		"s_area":           mae.BaseParam.Area,
+		"s_industry":       mae.BaseParam.Industry,
+		"s_buyerClass":     mae.BaseParam.BuyerClass,
+		"s_userId":         mae.UId,
+		"s_parentId":       mae.Pid,
+		"l_createTime":     time.Now().Unix(),
+	})
+	if mae.MgoRecordId == "" {
+		return fmt.Errorf("分析创建异常")
+	}
+	return nil
+}
+
+//GetAnalysisFromMgoDb 从数据库中获取分析记录
+func (mae *MarketAnalysisEntity) GetAnalysisFromMgoDb() error {
+	if mae.MgoRecordId == "" {
+		return fmt.Errorf("缺少参数")
+	}
+	queryMap := map[string]interface{}{
+		"_id":   mongodb.StringTOBsonId(mae.MgoRecordId),
+		"i_del": map[string]interface{}{"$ne": 1},
+	}
+	if mae.UId == mae.Pid { //主账号
+		queryMap["s_parentId"] = mae.Pid
+	} else {
+		queryMap["s_userId"] = mae.UId
+	}
+	res, _ := db.Mgo.FindOne(ReportHistoryTable, queryMap)
+	if res == nil || len(*res) == 0 {
+		return fmt.Errorf("未查询到相关数据")
+	}
+	mae.BaseParam.KeysItemsStr, _ = (*res)["s_keysItems"].(string)
+	mae.BaseParam.RangeTime, _ = (*res)["s_rangeTime"].(string)
+	mae.BaseParam.RangeTimeExtra, _ = (*res)["s_rangeTimeExtra"].(string)
+	mae.BaseParam.Area, _ = (*res)["s_area"].(string)
+	mae.BaseParam.Industry, _ = (*res)["s_industry"].(string)
+	mae.BaseParam.BuyerClass, _ = (*res)["s_buyerClass"].(string)
+	return nil
+}
+
+// removeEmptyRecord 删除空报告记录
+func (mae *MarketAnalysisEntity) removeEmptyRecord() {
+	queryMap := map[string]interface{}{
+		"_id": mongodb.StringTOBsonId(mae.MgoRecordId),
+	}
+	if mae.UId == mae.Pid { //主账号
+		queryMap["s_parentId"] = mae.Pid
+	} else {
+		queryMap["s_userId"] = mae.UId
+	}
+	db.Mgo.Update(ReportHistoryTable, queryMap, map[string]interface{}{
+		"$set": map[string]interface{}{"i_del": 1},
+	}, false, false)
+	log.Println("删除空报告", queryMap)
+}
+
+//GetRecordList 获取分析记录
+func (mae *MarketAnalysisEntity) GetRecordList(pageNum, PageSize int) (total int, list []map[string]interface{}) {
+	queryMap := map[string]interface{}{
+		"i_del": map[string]interface{}{"$ne": 1},
+	}
+	if mae.UId == mae.Pid { //主账号
+		queryMap["s_parentId"] = mae.Pid
+	} else {
+		queryMap["s_userId"] = mae.UId
+	}
+	if pageNum == 1 {
+		total = db.Mgo.Count(ReportHistoryTable, queryMap)
+		if total == 0 {
+			return
+		}
+	} else {
+		total = -1
+	}
+	res, _ := db.Mgo.Find(ReportHistoryTable, queryMap, `{"l_createTime":-1}`, nil, false, (pageNum-1)*PageSize, PageSize)
+	if res == nil || len(*res) == 0 {
+		return
+	}
+	for _, row := range *res {
+		list = append(list, map[string]interface{}{
+			"id":               util.EncodeId(mongodb.BsonIdToSId(row["_id"])),
+			"keysItems":        qutil.ObjToString(row["s_keysItems"]),
+			"area":             qutil.ObjToString(row["s_area"]),
+			"industry":         qutil.ObjToString(row["s_industry"]),
+			"buyerclass":       qutil.ObjToString(row["s_buyerClass"]),
+			"rangeTime":        qutil.ObjToString(row["s_rangeTime"]),
+			"s_rangeTimeExtra": qutil.ObjToString(row["s_rangeTimeExtra"]),
+			"createTime":       qutil.Int64All(row["l_createTime"]),
+		})
+	}
+	return
+}
+
+// GetQueryItem 获取查询条件,前端回显使用
+func (mae *MarketAnalysisEntity) getQueryItem() (map[string]interface{}, error) {
+	return map[string]interface{}{
+		"keysItems":        mae.BaseParam.KeysItemsStr,
+		"area":             mae.BaseParam.Area,
+		"industry":         mae.BaseParam.Industry,
+		"buyerclass":       mae.BaseParam.BuyerClass,
+		"rangeTime":        mae.BaseParam.RangeTime,
+		"s_rangeTimeExtra": mae.BaseParam.RangeTimeExtra,
+	}, nil
+}
+
+//GetPartResult 分块儿获取报告内容
+func (mae *MarketAnalysisEntity) GetPartResult(flag int) (map[string]interface{}, error) {
+	defer qutil.Catch()
+	if flag == marketQueryItem { //返回查询内容
+		return mae.getQueryItem()
+	}
+	thisCacheKey := fmt.Sprintf(ReportCacheKey, mae.MgoRecordId, flag)
+	if cacheData := redis.Get(ReportCacheDB, thisCacheKey); cacheData != nil {
+		if cacheMap, ok := cacheData.(map[string]interface{}); ok && len(cacheMap) > 0 {
+			return cacheMap, nil
+		}
+	}
+	rData, err := func() (map[string]interface{}, error) {
+		//控制并发&&超时返回超时异常
+		select {
+		case <-time.After(time.Duration(config.Config.MarketAnalysisPool.TimeOut) * time.Second * 20):
+			return nil, fmt.Errorf("查询超时,请稍后重试")
+		case <-MarketAnalysisPool:
+		}
+		start := time.Now()
+		defer func() {
+			MarketAnalysisPool <- true
+			log.Printf("report %s[%d] speed %d ms\n", mae.MgoRecordId, flag, time.Now().Sub(start).Milliseconds())
+		}()
+		//校验报告是否合法
+		if flag != marketScaleMain {
+			if exists, _ := redis.Exists(ReportCacheDB, fmt.Sprintf(ReportCacheKey, mae.MgoRecordId, 1)); !exists {
+				return nil, fmt.Errorf("报告异常请求,请刷新重试")
+			}
+		}
+		switch flag {
+		case marketScaleMain:
+			rData, err := mae.MarketTime()
+			if err != nil { //若无报告内容,删除报告记录
+				go mae.removeEmptyRecord()
+			}
+			return rData, err
+		case marketTopProject:
+			return mae.ProjectTop10()
+		case marketProjectAllData:
+			return mae.AllData()
+		case marketScaleRefine:
+			return mae.marketScaleRefineQuery()
+		case marketBuyerAndWinner:
+			return mae.BuyerWinnerAnalysis(), nil
+		}
+		return nil, fmt.Errorf("未知请求")
+	}()
+	if err == nil && rData != nil && len(rData) > 0 {
+		redis.Put(ReportCacheDB, thisCacheKey, rData, ReportCacheTime)
+	}
+	return rData, err
+}
+
+func GetEntNameByIds(ids []string) (returnMap map[string]string) {
+	returnMap = map[string]string{}
+	if len(ids) == 0 {
+		return
+	}
+	list := elastic.Get("qyxy", "qyxy", fmt.Sprintf(`{"query":{"bool":{"must":[{"terms":{"_id":["%s"]}}]}},"_source":["_id","company_name"],"size":%d}`, strings.Join(ids, `","`), len(ids)))
+	if list == nil || len(*list) == 0 {
+		return
+	}
+	for _, item := range *list {
+		id, _ := item["_id"].(string)
+		name, _ := item["company_name"].(string)
+		if id != "" && name != "" {
+			returnMap[id] = name
+		}
+	}
+	return
+}

+ 258 - 0
src/jfw/modules/bigmember/src/entity/marketAnalysis/scaleRefineQuery.go

@@ -0,0 +1,258 @@
+package marketAnalysis
+
+import (
+	"encoding/json"
+	"fmt"
+	"sort"
+	"strings"
+	"util"
+)
+
+const (
+	_ = iota
+	onlyTotal
+	onlyAmount
+	totalAndAmount
+
+	topWinnerLimit = 3 //细分市场展示前x个企业
+	topItemLimit   = 3 //返回前x组关键词
+)
+
+type scaleRefineData struct {
+	Data       []*scaleRefineRow
+	Total      simpleTotal
+	Amount     simpleSum
+	IdSwitch   map[string]string
+	ReturnData struct {
+		Overall             []map[string]interface{}
+		TotalTop, AmountTop []*returnItem
+	}
+}
+
+type simpleTotal struct {
+	Total int64 `json:"doc_count"`
+}
+
+type simpleSum struct {
+	Value float64 `json:"value"`
+}
+
+type scaleRefineRow struct {
+	Total          int64     `json:"doc_count"`
+	TotalProp      float64   `json:"total_prop"`
+	Amount         simpleSum `json:"project_amount"`
+	AmountProp     float64   `json:"amount_prop"`
+	WinnerTotalTop struct {
+		Buckets []*struct {
+			EntId   string  `json:"key"`
+			EntName string  `json:"entName"`
+			Total   int64   `json:"doc_count"`
+			Prop    float64 `json:"prop"`
+		} `json:"buckets"`
+	} `json:"winner_total_top"`
+	WinnerAmountTop struct {
+		Buckets []*struct {
+			EntId   string `json:"key"`
+			EntName string `json:"entName"`
+			Amount  struct {
+				Value float64 `json:"value"`
+			} `json:"refine_winner_amount"`
+			Prop float64 `json:"prop"`
+		} `json:"buckets"`
+	} `json:"winner_amount_top"`
+	ItemName   string `json:"itemName"`
+	UpdateTime int64  `json:"updateTime"`
+}
+
+type returnItem struct {
+	Name    string      `json:"name"`
+	Value   interface{} `json:"value"`
+	Prop    interface{} `json:"prop"`
+	TopList []*entValue `json:"topList"`
+}
+
+type entValue struct {
+	Id    string      `json:"id"`
+	Name  string      `json:"name"`
+	Value interface{} `json:"value"`
+	Prop  interface{} `json:"prop"`
+}
+
+//marketScaleRefineQuery 细化聚合
+func (mae *MarketAnalysisEntity) marketScaleRefineQuery() (rMap map[string]interface{}, err error) {
+	//关键词分组聚合
+	var aggsGroup []string
+	//获取总金额及总数
+	aggsGroup = append(aggsGroup, `"projectAmount":{"sum":{"field":"sortprice"}}`)
+	aggsGroup = append(aggsGroup, `"projectTotal":{"filter":{}}`)
+	itemDataMap := map[string]int64{}
+	for _, group := range mae.FormatParam.KeysItems {
+		var bools []string
+		for _, v := range getGroupKeywordArr(group.A_Key) {
+			if sql := getKeyWordSql(v); sql != "" {
+				bools = append(bools, sql)
+			}
+		}
+		if len(bools) > 0 {
+			aggsGroup = append(aggsGroup, fmt.Sprintf(`"%s":{"filter":{"query":{"bool":{"should":[%s],"minimum_should_match": 1}}},"aggs":{"project_count":{"filter":{}},"project_amount":{"sum":{"field":"sortprice"}},"winner_total_top":{"terms":{"field":"entidlist","exclude":["-"],"order":[{"refine_winner_total":"desc"}],"size":%d},"aggs":{"refine_winner_total":{"filter":{}}}},"winner_amount_top":{"terms":{"field":"entidlist","exclude":["-"],"order":[{"refine_winner_amount":"desc"}],"size":%d},"aggs":{"refine_winner_amount":{"sum":{"field":"sortprice"}}}}}}`, group.ItemName, strings.Join(bools, ","), topWinnerLimit, topWinnerLimit))
+		}
+		itemDataMap[group.ItemName] = group.UpdateTime
+	}
+	finalSql := fmt.Sprintf(mae.GetCommonQuerySqlWithAggs(), strings.Join(aggsGroup, ","))
+	//fmt.Println("finalSql-----4", finalSql)
+	rMap = map[string]interface{}{}
+	res, _ := util.GetAggs("projectset", "projectset", finalSql)
+	if res == nil || len(res) == 0 {
+		return
+	}
+	scale := scaleRefineData{IdSwitch: map[string]string{}}
+	for name, object := range res {
+		bArr, err := object.MarshalJSON()
+		if len(bArr) == 0 || err != nil {
+			continue
+		}
+		if name == "projectTotal" {
+			st := simpleTotal{}
+			if err := json.Unmarshal(bArr, &st); err == nil {
+				scale.Total = st
+			}
+			continue
+		} else if name == "projectAmount" {
+			ss := simpleSum{}
+			if err := json.Unmarshal(bArr, &ss); err == nil {
+				scale.Amount = ss
+			}
+			continue
+		}
+		thisRow := scaleRefineRow{}
+		if err := json.Unmarshal(bArr, &thisRow); err != nil {
+			continue
+		}
+		thisRow.ItemName = name
+		thisRow.UpdateTime = itemDataMap[name]
+		scale.Data = append(scale.Data, &thisRow)
+	}
+	scale.formatData() //获取所需数据
+	scale.doIdSwitch() //补充企业名称
+	return map[string]interface{}{
+		"scaleRefineAll":       scale.ReturnData.Overall,
+		"scaleRefineTotalTop":  scale.ReturnData.TotalTop,
+		"scaleRefineAmountTop": scale.ReturnData.AmountTop,
+	}, nil
+}
+
+//doIdSwitch 补充企业名称
+func (srd *scaleRefineData) doIdSwitch() {
+	if len(srd.IdSwitch) == 0 {
+		return
+	}
+	var ids []string
+	for id, _ := range srd.IdSwitch {
+		ids = append(ids, id)
+	}
+	srd.IdSwitch = GetEntNameByIds(ids)
+	for _, v := range srd.ReturnData.TotalTop {
+		for _, vv := range v.TopList {
+			vv.Name, _ = srd.IdSwitch[vv.Id]
+			vv.Id = util.EncodeId(vv.Id)
+		}
+	}
+	for _, v := range srd.ReturnData.AmountTop {
+		for _, vv := range v.TopList {
+			vv.Name, _ = srd.IdSwitch[vv.Id]
+			vv.Id = util.EncodeId(vv.Id)
+		}
+	}
+}
+
+//formatData 计算百分比&获取企业对应名称
+func (srd *scaleRefineData) formatData() {
+	for _, v := range srd.Data {
+		v.TotalProp = float64(v.Total) / float64(srd.Total.Total)
+		v.AmountProp = v.Amount.Value / srd.Amount.Value
+
+		for _, vv := range v.WinnerTotalTop.Buckets {
+			vv.Prop = float64(vv.Total) / float64(v.Total)
+		}
+		for _, vv := range v.WinnerAmountTop.Buckets {
+			vv.Prop = vv.Amount.Value / v.Amount.Value
+		}
+	}
+	srd.ReturnData.Overall = srd.sortBy(totalAndAmount).getOverallData()
+	srd.ReturnData.AmountTop = srd.sortBy(onlyAmount).getFormatTop(topItemLimit, onlyAmount)
+	srd.ReturnData.TotalTop = srd.sortBy(onlyTotal).getFormatTop(topItemLimit, onlyTotal)
+}
+
+//getOverallData 获取分类总览数据
+func (srd *scaleRefineData) getOverallData() (rData []map[string]interface{}) {
+	for _, Value := range srd.Data {
+		rData = append(rData, map[string]interface{}{
+			"name":   Value.ItemName,
+			"total":  Value.Total,
+			"amount": Value.Amount.Value,
+		})
+	}
+	return
+}
+
+//getArrayFormatTop 获取前n个数据,并格式化
+//limit 获取前x条
+//flag 1仅返回数量统计 2仅返回金额统计
+func (srd *scaleRefineData) getFormatTop(limit, flag int) (rData []*returnItem) {
+	for index, Value := range srd.Data {
+		if index >= limit && limit > -1 {
+			return
+		}
+		thisRow := &returnItem{
+			Name: Value.ItemName,
+		}
+		if flag == 1 || flag == 3 { //返回数量相关数据
+			thisRow.Value = Value.Total
+			if flag != 3 {
+				for _, v := range Value.WinnerTotalTop.Buckets {
+					thisRow.TopList = append(thisRow.TopList, &entValue{
+						Id:    v.EntId,
+						Name:  v.EntName,
+						Value: v.Total,
+						Prop:  v.Prop,
+					})
+					srd.IdSwitch[v.EntId] = ""
+				}
+				thisRow.Prop = Value.TotalProp
+			}
+		}
+		if flag == 2 || flag == 3 { //返回金额相关数据
+			thisRow.Value = Value.Amount.Value
+			if flag != 3 {
+				for _, v := range Value.WinnerAmountTop.Buckets {
+					thisRow.TopList = append(thisRow.TopList, &entValue{
+						Id:    v.EntId,
+						Name:  v.EntName,
+						Value: v.Amount.Value,
+						Prop:  v.Prop,
+					})
+					srd.IdSwitch[v.EntId] = ""
+				}
+				thisRow.Prop = Value.TotalProp
+			}
+		}
+		rData = append(rData, thisRow)
+	}
+	return
+}
+
+//getScaleRefineAll 根据订阅词组创建时间排序
+func (srd *scaleRefineData) sortBy(flag int) *scaleRefineData {
+	sort.Slice(srd.Data, func(i, j int) bool {
+		switch flag {
+		case onlyTotal:
+			return srd.Data[i].Total > srd.Data[j].Total
+		case onlyAmount:
+			return srd.Data[i].Amount.Value > srd.Data[j].Amount.Value
+		case totalAndAmount:
+			return srd.Data[i].UpdateTime > srd.Data[j].UpdateTime
+		}
+		return false
+	})
+	return srd
+}

+ 55 - 12
src/jfw/modules/bigmember/src/entity/portrailUtil.go

@@ -93,25 +93,68 @@ type SimpleStringKeyValue struct {
 //获取中标金额聚合查询语句(近三年统计月份,5-3年统计年份)
 func getBidamountStatistics(sTime, eTime time.Time) string {
 	timeRange := ``
-	//三年外统计年份
-	tmpTime := sTime
-	//近三年统计月份
-	for sTime.Before(eTime) {
-		sTime = sTime.AddDate(0, 1, 0)
-		timeRange += fmt.Sprintf(`{"key":"%s","from":%d,"to":%d},`, fmt.Sprintf("%d-%d", tmpTime.Year(), tmpTime.Month()), tmpTime.Unix(), sTime.Unix())
-		tmpTime = sTime
+	tmpTime, rTime, tEndTime := sTime, sTime, getMonthRange(eTime, false)
+	for rTime.Before(tEndTime) {
+		ts, te := getMonthRange(tmpTime, true), getMonthRange(tmpTime, false)
+		if sTime == tmpTime {
+			ts = sTime
+		}
+		if te == tEndTime {
+			te = eTime
+		}
+		if ts.Before(te) {
+			timeRange += fmt.Sprintf(`{"key":"%s","from":%d,"to":%d},`, fmt.Sprintf("%d-%d", ts.Year(), ts.Month()), ts.Unix(), te.Unix())
+		}
+		rTime = rTime.AddDate(0, 1, 0)
+		if int(rTime.Month())-int(tmpTime.Month()) > 1 { //防止01-30 加一月 返回 03-01
+			rTime = rTime.AddDate(0, -1, 0)
+		}
+		tmpTime = rTime
+	}
+	if timeRange == `` {
+		return ""
 	}
 	return timeRange[:len(timeRange)-1]
 }
 
+//getMonthRange获取月份范围
+//isStart true本月月初  false 本月月末(下月月初)
+func getMonthRange(t time.Time, isStart bool) time.Time {
+	if isStart {
+		return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
+	}
+	return time.Date(t.Year(), t.Month()+1, 1, 0, 0, 0, 0, t.Location())
+}
+
+//getYearRange获取月份范围
+//isStart true本月月初  false 本月月末(下月月初)
+func getYearRange(t time.Time, isStart bool) time.Time {
+	if isStart {
+		return time.Date(t.Year(), 1, 1, 0, 0, 0, 0, t.Location())
+	}
+	return time.Date(t.Year()+1, 1, 1, 0, 0, 0, 0, t.Location())
+}
+
 //年份统计
 func getCommonYearStatistics(sTime, eTime time.Time) string {
 	timeRange := ``
-	tmpTime := sTime
-	for sTime.Before(eTime) {
-		sTime = sTime.AddDate(1, 0, 0)
-		timeRange += fmt.Sprintf(`{"key":"%d","from":%d,"to":%d},`, tmpTime.Year(), tmpTime.Unix(), sTime.Unix())
-		tmpTime = sTime
+	tmpTime, rTime, tEndTime := sTime, sTime, getYearRange(eTime, false)
+	for rTime.Before(tEndTime) {
+		ts, te := getYearRange(tmpTime, true), getYearRange(tmpTime, false)
+		if sTime == tmpTime {
+			ts = sTime
+		}
+		if te == tEndTime {
+			te = eTime
+		}
+		if ts.Before(te) {
+			timeRange += fmt.Sprintf(`{"key":"%d","from":%d,"to":%d},`, ts.Year(), ts.Unix(), te.Unix())
+		}
+		rTime = rTime.AddDate(1, 0, 0)
+		tmpTime = rTime
+	}
+	if timeRange == `` {
+		return ""
 	}
 	return timeRange[:len(timeRange)-1]
 }

+ 1 - 1
src/jfw/modules/bigmember/src/entity/portraitBuyerSearch.go

@@ -133,7 +133,7 @@ func BuyerPortraitSearch(screen *PortraitScreen) (map[string]interface{}, error)
 
 	tBegin := time.Now()
 	doSearchSql := fmt.Sprintf(buyerPortraitSearchSql, strings.Join(mustQueryArr, ","), bidamountTimeRange, getMoneyRange(), comminTimeRange, comminTimeRange)
-	res, count := GetAggs("projectset", "projectset", doSearchSql)
+	res, count := util.GetAggs("projectset", "projectset", doSearchSql)
 	if res == nil {
 		return nil, errors.New(fmt.Sprintf("%s采购单位画像查询异常\n", screen.Ent))
 	}

+ 1 - 1
src/jfw/modules/bigmember/src/entity/portraitWinnerSearch.go

@@ -152,7 +152,7 @@ func GetWinnerPortraitSearch(screen *PortraitScreen) (map[string]interface{}, er
 	//开始查询
 	tBegin := time.Now()
 	doSearchSql := fmt.Sprintf(winnerPortraitSearchSql, strings.Join(mustQueryArr, ","), comminTimeRange, comminTimeRange, bidamountTimeRange)
-	res, docCount := GetAggs("projectset", "projectset", doSearchSql)
+	res, docCount := util.GetAggs("projectset", "projectset", doSearchSql)
 	if res == nil {
 		return nil, errors.New(fmt.Sprintf("%s中标企业画像查询异常\n", screen.Ent))
 	}

+ 1 - 1
src/jfw/modules/bigmember/src/entity/portrait_screen.go

@@ -118,7 +118,7 @@ func (ps *PortraitScreen) GetProjectSelectItems(isWinner bool) (map[string]inter
 	}
 	doSearchSql := fmt.Sprintf(newBiddingSearchShowSql, entMatch, time.Date(time.Now().Year()-4, 1, 1, 0, 0, 0, 0, time.Local).Unix())
 	//log.Println("GetProjectSelectItems doSearchSql", doSearchSql)
-	res, _ := GetAggs(projectIndex, projectType, doSearchSql)
+	res, _ := util.GetAggs(projectIndex, projectType, doSearchSql)
 	if res == nil {
 		return nil, fmt.Errorf("此企业无信息或获取信息列表检索条件出错")
 	}

+ 1 - 1
src/jfw/modules/bigmember/src/service/analysis/decision.go

@@ -605,7 +605,7 @@ func getDecInfo(decQuery, buyer_buyerClass string, dec *DecParam) map[string]int
 						var entId = ""
 						if group_entidlist != nil && group_entidlist["buckets"] != nil {
 							buckets := qutil.ObjArrToMapArr(group_entidlist["buckets"].([]interface{}))
-							if buckets == nil || len(buckets) == 0 {
+							if buckets == nil || len(buckets) == 0 || (buckets[0]["key"] != nil && len(qutil.ObjToString(buckets[0]["key"])) < 10) {
 								continue
 							}
 							entId = util.EncodeId(qutil.ObjToString(buckets[0]["key"]))

+ 1 - 1
src/jfw/modules/bigmember/src/service/init.go

@@ -30,5 +30,5 @@ func init() {
 	xweb.AddAction(&report.Report{})
 	xweb.AddAction(&trial.Trial{})
 	xweb.AddAction(&bidfile.Bidfile{})
-
+	xweb.AddAction(&report.MarketAnalysis{})
 }

+ 127 - 0
src/jfw/modules/bigmember/src/service/report/marketAnalysis.go

@@ -0,0 +1,127 @@
+package report
+
+import (
+	. "api"
+	"db"
+	"entity/marketAnalysis"
+	"fmt"
+	"github.com/go-xweb/xweb"
+	"log"
+	qutil "qfw/util"
+	"qfw/util/jy"
+	"util"
+)
+
+//MarketAnalysis 市场分析报告路由定义
+type MarketAnalysis struct {
+	*xweb.Action
+	doAnalysis        xweb.Mapper `xweb:"/marketAnalysis/doAnalysis"`        //市场分析分析查询(此接口只做为保存查询条件,返回记录id)
+	getAnalysisResult xweb.Mapper `xweb:"/marketAnalysis/getAnalysisResult"` //获取分析报告结果(根据记录id查询报告结果)
+	analysisHistory   xweb.Mapper `xweb:"/marketAnalysis/analysisHistory"`   //市场分析报告历史记录
+}
+
+//checkPower 权限校验
+func checkPower(userId string) (string, error) {
+	if userId == "" {
+		return "", fmt.Errorf("未登录")
+	}
+	//仅购买《周报/月报/定制化市场分析报告》的大会员有权限
+	bigMeg := jy.GetBigVipUserBaseMsg(userId, db.Mysql, db.Mgo)
+	if bigMeg.Status <= 0 || !bigMeg.CheckBigVipBackPower("report") {
+		return "", fmt.Errorf("非法请求")
+	}
+	return bigMeg.Pid, nil
+}
+
+//DoAnalysis 开始分析报告
+func (this *MarketAnalysis) DoAnalysis() {
+	userId := qutil.ObjToString(this.GetSession("userId"))
+	rData, errMsg := func() (interface{}, error) {
+		pid, powerErr := checkPower(userId)
+		if powerErr != nil {
+			return nil, powerErr
+		}
+		//接受参数
+		bParam := marketAnalysis.AnalysisRequestParam{
+			KeysItemsStr:   this.GetString("keysItems"),      //分析内容【字符串】结构和o_member_jy.a_items保持一致
+			RangeTime:      this.GetString("rangeTime"),      //时间【字符串】 时间戳开始-结束时间戳
+			RangeTimeExtra: this.GetString("rangeTimeExtra"), //时间【字符串】 时间戳开始-结束时间戳
+			Area:           this.GetString("area"),           //省份【字符串】多个省份用逗号拼接
+			Industry:       this.GetString("industry"),       //行业【字符串】多个行业用逗号拼接
+			BuyerClass:     this.GetString("buyerclass"),     //采购单位类型【字符串】多个采购单位类型用逗号拼接
+		}
+		mae := &marketAnalysis.MarketAnalysisEntity{BaseParam: bParam, UId: userId, Pid: pid}
+		if err := mae.ForMatData(); err != nil {
+			return nil, err
+		}
+		//存储分析记录
+		if err := mae.SaveAnalysisRecord(); err != nil {
+			return nil, err
+		}
+		return util.EncodeId(mae.MgoRecordId), nil
+	}()
+	if errMsg != nil {
+		log.Printf("%s MarketAnalysis DoAnalysis Error:%s\n", userId, errMsg.Error())
+	}
+	this.ServeJson(NewResult(rData, errMsg))
+}
+
+//GetAnalysisResult 获取分析结果
+func (this *MarketAnalysis) GetAnalysisResult() {
+	userId := qutil.ObjToString(this.GetSession("userId"))
+	rData, errMsg := func() (interface{}, error) {
+		pid, powerErr := checkPower(userId)
+		if powerErr != nil {
+			return nil, powerErr
+		}
+		mae := &marketAnalysis.MarketAnalysisEntity{MgoRecordId: util.DecodeId(this.GetString("rid")), UId: userId, Pid: pid}
+		if err := mae.GetAnalysisFromMgoDb(); err != nil {
+			return nil, err
+		}
+		//二次校验数据
+		if err := mae.ForMatData(); err != nil {
+			return nil, err
+		}
+		//查询
+		flag, _ := this.GetInteger("flag")
+		rData, err := mae.GetPartResult(flag)
+		if err != nil {
+			return nil, err
+		}
+		return rData, nil
+	}()
+	if errMsg != nil {
+		log.Printf("%s MarketAnalysis GetAnalysisResult Error:%s\n", userId, errMsg.Error())
+	}
+	this.ServeJson(NewResult(rData, errMsg))
+}
+
+//AnalysisHistory 分析报告历史
+func (this *MarketAnalysis) AnalysisHistory() {
+	userId := qutil.ObjToString(this.GetSession("userId"))
+	rData, errMsg := func() (interface{}, error) {
+		pid, powerErr := checkPower(userId)
+		if powerErr != nil {
+			return nil, powerErr
+		}
+		//接受参数
+		pageNum, pageNumErr := this.GetInteger("pageNum") //页码
+		if pageNumErr != nil {
+			pageNum = 1
+		}
+		pageSize, pageSizeErr := this.GetInteger("pageSize") //每页数量
+		if pageSizeErr != nil {
+			pageSize = 10
+		}
+		mae := &marketAnalysis.MarketAnalysisEntity{UId: userId, Pid: pid}
+		total, list := mae.GetRecordList(pageNum, pageSize)
+		return map[string]interface{}{
+			"total": total,
+			"list":  list,
+		}, nil
+	}()
+	if errMsg != nil {
+		log.Printf("%s MarketAnalysis AnalysisHistory Error:%s\n", userId, errMsg.Error())
+	}
+	this.ServeJson(NewResult(rData, errMsg))
+}

+ 10 - 3
src/jfw/modules/bigmember/src/service/use/use.go

@@ -305,7 +305,7 @@ func (u *Use) Echo() {
 				  "size": 0
 				}
 		`
-		res, _ := entity.GetAggs(db.DbConf.Elascit_index, db.DbConf.Elascit_type, fmt.Sprintf(query, name))
+		res, _ := util.GetAggs(db.DbConf.Elascit_index, db.DbConf.Elascit_type, fmt.Sprintf(query, name))
 		echo_map["area"] = GetData(res, "group_area")    //地区
 		echo_map["buyer"] = GetData(res, "group_buyer")  //采购单位集合
 		industrys := GetData(res, "group_topscopeclass") //industry行业
@@ -394,7 +394,7 @@ func (u *Use) Echo() {
 		by := `"` + strings.Replace(buyer, `,`, `","`, -1) + `"`
 		industry := StringArrToString(industrys)
 		is := `"` + strings.Replace(industry, `,`, `","`, -1) + `"`
-		res2, _ := entity.GetAggs(db.DbConf.Elascit_index, db.DbConf.Elascit_type, fmt.Sprintf(query2, by, is))
+		res2, _ := util.GetAggs(db.DbConf.Elascit_index, db.DbConf.Elascit_type, fmt.Sprintf(query2, by, is))
 		winners, ids := []string{}, []string{}
 		if winners := GetData(res2, "g_winner"); len(winners) > 0 {
 			winners, ids = gitWinnersIds(winners)
@@ -601,6 +601,13 @@ func (u *Use) IsAdd() {
 		if userid == "" {
 			return Result{Data: nil, Error_msg: "未登录"}
 		}
+		var hasKey bool
+		user, ok := db.Mgo.FindById("user", userid, `{"o_jy":1,"i_vip_status":1,"l_vip_endtime":1,"o_vipjy":1,"o_member_jy":1}`)
+		if ok && user != nil {
+			o_jy, _ := (*user)["o_jy"].(map[string]interface{})
+			a_key, _ := o_jy["a_key"].([]interface{})
+			hasKey = len(a_key) > 0
+		}
 		//获取用户权限详情
 		power := []int{} //GetNewPower(userid)
 		bigPower := jy.GetBigVipUserBaseMsg(userid, db.Mysql, db.Mgo)
@@ -629,7 +636,7 @@ func (u *Use) IsAdd() {
 		filePackNum := redis.GetInt(jy.PowerCacheDb, filePackKey)
 		d["fileNum"] = config.Config.FileUploadNum[uk] - redis.GetInt(jy.PowerCacheDb, fmt.Sprintf(jy.VipFileUploadNumKey, userid, fmt.Sprint(time.Now().Month()))) + filePackNum
 		//新用户->新订阅设置页面
-		if config.Config.NewFreeUser < bigPower.Registedate {
+		if config.Config.NewFreeUser < bigPower.Registedate|| !hasKey  {
 			d["isUpgrade"] = true
 		}
 		uid := userid

+ 2 - 2
src/jfw/modules/bigmember/src/entity/aggsSearchUtil.go → src/jfw/modules/bigmember/src/util/aggsSearchUtil.go

@@ -1,4 +1,4 @@
-package entity
+package util
 
 import (
 	elastic1 "gopkg.in/olivere/elastic.v1"
@@ -8,7 +8,7 @@ import (
 	"runtime"
 )
 
-//聚合查询
+//GetAggs 聚合查询
 func GetAggs(index, itype, query string) (aggs elastic1.Aggregations, count int64) {
 	defer util.Catch()
 	client := elastic.GetEsConn()

+ 1 - 1
src/jfw/modules/bigmember/src/util/util.go

@@ -8,7 +8,7 @@ import (
 var ClearHtml = regexp.MustCompile("<[^>]*>")
 
 func EncodeId(sid string) string {
-	if sid == "" {
+	if sid == "" || sid == "-" { //不存在的id为-
 		return ""
 	}
 	return qutil.EncodeArticleId2ByCheck(sid)

+ 40 - 9
src/jfw/modules/common/src/qfw/util/dataexport/dataexport.go

@@ -310,10 +310,12 @@ func GetSqlObjFromId(mongo mg.MongodbSim, _id string) *SieveCondition {
 }
 
 //数据导出-查询结果数量
-func GetDataExportSearchCountByScdId(sim mg.MongodbSim, elasticAddress, id string) (count int) {
+func GetDataExportSearchCountByScdId(sim, bid mg.MongodbSim, biddingName, elasticAddress, id string) (count int) {
 	scd := GetSqlObjFromId(sim, id) //用户筛选条件
 	if scd.SelectIds != nil {
-		return len(scd.SelectIds)
+		//部分数据可能已删除、不存在;此处需要统计返回实际数量
+		//return len(scd.SelectIds)
+		return int(GetDataExportSelectReallyCount(bid, biddingName, scd.SelectIds))
 	}
 	return GetDataExportSearchCountBySieveCondition(scd, elasticAddress)
 }
@@ -406,19 +408,48 @@ func GetDataExportIdArrByScdId(sim mg.MongodbSim, elasticAddress, id string, che
 //收藏导出
 var contentfilterReg = regexp.MustCompile("<[^>]+>")
 
+//GetDataExportSelectReallyCount 查询实际可调导出数量
+func GetDataExportSelectReallyCount(bid mg.MongodbSim, biddingName string, ids []string) int64 {
+	sess := bid.GetMgoConn()
+	defer bid.DestoryMongoConn(sess)
+	if ids == nil || len(ids) == 0 {
+		return 0
+	}
+	var queryIds []interface{}
+	for _, idStr := range ids {
+		queryIds = append(queryIds, mg.StringTOBsonId(idStr))
+	}
+	lenNum := int64(len(ids))
+	num1, err1 := sess.DB(biddingName).C("bidding").Find(map[string]interface{}{"_id": map[string]interface{}{
+		"$in": queryIds,
+	}}).Count()
+	if err1 == nil {
+		if num1 == lenNum {
+			return lenNum
+		}
+		num2, err2 := sess.DB(biddingName).C("bidding_back").Find(map[string]interface{}{"_id": map[string]interface{}{
+			"$in": queryIds,
+		}}).Count()
+		if err2 == nil {
+			if num2+num1 == lenNum {
+				return lenNum
+			} else if num1+num2 > lenNum {
+				return lenNum
+			} else if num1+num2 < lenNum {
+				return num1 + num2
+			}
+		}
+	}
+	return -2
+}
+
 func GetDataExportSelectResult(bidding mg.MongodbSim, biddingName string, scd *SieveCondition, dataType string, checkCount int) (*[]map[string]interface{}, error) {
 	sess := bidding.GetMgoConn()
 	defer bidding.DestoryMongoConn(sess)
-	if checkCount == -1 {
-		checkCount = len(scd.SelectIds)
-	}
 	var queryIds []interface{}
 	for _, idStr := range scd.SelectIds {
 		queryIds = append(queryIds, mg.StringTOBsonId(idStr))
 	}
-	if queryIds == nil || len(queryIds) != checkCount {
-		return nil, fmt.Errorf("选择数据导出异常 id数量不一致 期望%d 实际%d", checkCount, len(queryIds))
-	}
 	selectMap := map[string]interface{}{
 		"_id": 1, "title": 1, "detail": 1, "area": 1, "city": 1, "publishtime": 1, "projectname": 1, "buyer": 1, "s_winner": 1, "bidamount": 1, "subtype": 1, "toptype": 1,
 	}
@@ -455,7 +486,7 @@ func GetDataExportSelectResult(bidding mg.MongodbSim, biddingName string, scd *S
 		returnLsit = append(returnLsit, m)
 		m = make(map[string]interface{})
 	}
-	if len(returnLsit) == checkCount {
+	if len(returnLsit) == checkCount || checkCount == -1 {
 		return &returnLsit, nil
 	}
 	return nil, fmt.Errorf("选择数据导出异常 数据量期望%d条,实际查询%d条", checkCount, len(returnLsit))

+ 1 - 1
src/jfw/modules/common/src/qfw/util/dataexport/entdataexport.go

@@ -31,7 +31,7 @@ func GetEntDataExportCount(sim, bid mg.MongodbSim, bidMgoDBName, elasticAddress,
 	var (
 		searchsWaitGroup = &sync.WaitGroup{}
 	)
-	count = GetDataExportSearchCountByScdId(sim, elasticAddress, _id)
+	count = GetDataExportSearchCountByScdId(sim, bid, bidMgoDBName, elasticAddress, _id)
 	if count > maxCount || count == -1 {
 		count = maxCount
 	}

+ 5 - 0
src/jfw/modules/publicapply/src/userbase/bigmembermenu.json

@@ -91,6 +91,11 @@
 				"name":"月报",
 				"url":"/swordfish/page_big_pc/bigvip_subreport_month",
 				"isusable":false
+			},
+			{
+				"name":"定制化分析报告",
+				"url":"/swordfish/page_big_pc/desktop/report_analysis",
+				"isusable":false
 			}
 		]
 	},

+ 8 - 0
src/jfw/modules/publicapply/src/userbase/commonfunctions.json

@@ -143,6 +143,14 @@
 				"img":"/commonFunctions/pc_subreport_month.png"
 			}
 		},
+		{
+			"name":"定制化分析报告",
+			"charge":true,
+			"pc":{
+				"url":"/swordfish/page_big_pc/desktop/report_analysis",
+				"img":"/commonFunctions/analysis_report.png"
+			}
+		},
 		{
 			"name":"我的订单",
 			"charge":false,

+ 1 - 1
src/jfw/modules/publicapply/src/userbase/entity/entity.go

@@ -163,7 +163,7 @@ func IsPower(name, userId string) (b bool) {
 			b = BigPower.PowerMap[6]
 		case "潜在项目预测":
 			b = BigPower.PowerMap[9]
-		case "周报", "月报":
+		case "周报", "月报", "定制化分析报告":
 			b = BigPower.PowerMap[10]
 		case "订阅管理":
 			b = util.If(BigPower.Pid == "", true, false).(bool)

+ 2 - 2
src/jfw/modules/subscribepay/src/service/dataExportPay.go

@@ -71,12 +71,12 @@ func (p *DataExportPay) CreateOrder() {
 		data_spec = "高级字段包"
 	}
 
-	data_count := dataexport.GetDataExportSearchCountByScdId(util.MQFW, config.Config.Elasticsearch, id)
+	data_count := dataexport.GetDataExportSearchCountByScdId(util.MQFW, util.Mgo_bidding, config.Config.Mongobidding.DbName, config.Config.Elasticsearch, id)
 	if data_count > config.ExConf.MsgMaxCount || data_count == -1 {
 		data_count = config.ExConf.MsgMaxCount
 	}
 
-	if data_count == 0 {
+	if data_count <= 0 {
 		log.Println("未查询到检索信息", userId, id)
 		p.ServeJson(map[string]interface{}{
 			"status": "n",

+ 6 - 3
src/jfw/modules/subscribepay/src/service/dataexportPack.go

@@ -238,10 +238,13 @@ func (this *DataExportPack) Statistics() {
 		if filterId == "" {
 			return nil, fmt.Errorf("请求参数异常")
 		}
-		selectCount := dataexport.GetDataExportSearchCountByScdId(util.MQFW, config.Config.Elasticsearch, filterId)
+		selectCount := dataexport.GetDataExportSearchCountByScdId(util.MQFW, util.Mgo_bidding, config.Config.Mongobidding.DbName, config.Config.Elasticsearch, filterId)
 		if selectCount > config.ExConf.MsgMaxCount || selectCount == -1 {
 			selectCount = config.ExConf.MsgMaxCount
 		}
+		if selectCount <= 0 {
+			return nil, fmt.Errorf("导出数据异常")
+		}
 		if entId := this.GetString("entId"); entId != "" {
 			deduct, err := entity.JyDataExportPack.DoEntPackRepeatCheck(this.Session(), userId, entId, filterId, selectCount)
 			if err != nil {
@@ -291,8 +294,8 @@ func (this *DataExportPack) PackPay() {
 		if filterId == "" {
 			return nil, fmt.Errorf("请求参数异常")
 		}
-		selectCount := dataexport.GetDataExportSearchCountByScdId(util.MQFW, config.Config.Elasticsearch, filterId)
-		if selectCount > config.ExConf.MsgMaxCount {
+		selectCount := dataexport.GetDataExportSearchCountByScdId(util.MQFW, util.Mgo_bidding, config.Config.Mongobidding.DbName, config.Config.Elasticsearch, filterId)
+		if selectCount > config.ExConf.MsgMaxCount || selectCount == -1 {
 			selectCount = config.ExConf.MsgMaxCount
 		}
 		if total_req != selectCount {

BIN=BIN
src/web/staticres/big-member/image/buyer-open.png


BIN=BIN
src/web/staticres/big-member/image/winner-open.png


+ 25 - 0
src/web/staticres/big-member/js/meauContact.js

@@ -425,6 +425,31 @@ var SCFX = [
             five: 'icon-tick'
           }
         ]
+      },
+      {
+        two:"定制化市场分析报告",
+        three:[
+          {
+            threein:"可自定义分析条件,包含:分析内容、时间、地区、行业和采购单位类型。",
+            four:"icon-close",
+            five: 'icon-tick'
+          },
+          {
+            threein:'市场规模分析,包含市场概况、项目规模分布、时间分布、地区分布、客户分布、细分市场分布。',
+            four:"icon-close",
+            five: 'icon-tick'
+          },
+          {
+            threein:'采购单位分析,包含采购规模分布、项目数量/金额TOP10采购单位及其重点合作中标单位。',
+            four:"icon-close",
+            five: 'icon-tick'
+          },
+          {
+            threein:'中标单位分析,包含中标规模分布、项目数量/中标金额TOP10中标单位及其重点合作采购单位。',
+            four:"icon-close",
+            five: 'icon-tick'
+          }
+        ]
       }
     ]
   },

+ 26 - 2
src/web/staticres/big-member/js/unit_portrayal.js

@@ -132,7 +132,8 @@ var vNode = {
               visited: false,
               surplus: 0
             }, // 超级订阅用户画像浏览
-            freeTrial: false // 免费用户是否访问过当前画像
+            freeTrial: false, // 免费用户是否访问过当前画像
+            canRun: true
         }
     },
     computed: {
@@ -187,7 +188,7 @@ var vNode = {
         // 展示超级订阅浏览次数
         superVipPort: function () {
           console.log(this.userInfo.vipStatus, this.userInfo.viper)
-          return this.userInfo.vipStatus > 0 && this.userInfo.viper && this.bigStatus <= 0
+          return this.userInfo.vipStatus > 0 && this.userInfo.viper && this.power.indexOf(5) ==  -1
         },
         // 超级订阅用户对应的按钮
         superVipBtnText: function () {
@@ -198,6 +199,10 @@ var vNode = {
             text = '前往升级'
           }
           return text 
+        },
+        // 留完资的用户(保含已体验和未体验的)
+        getfreeBuyerOpen: function () {
+          return this.userInfo.isFree && this.userInfo.freeBuyerPort != 0;
         }
     },
     watch: {
@@ -220,6 +225,11 @@ var vNode = {
         if (!params && storageClick) {
           this.$nextTick(function(){
             document.querySelector('.win-analyse').scrollIntoView()
+            if (this.getfreeBuyerOpen) {
+              $('.win-analyse').css({
+                "margin-top": '1.8rem'
+              })
+            }
             sessionStorage.removeItem('is-click-set')
           })
         }
@@ -241,6 +251,20 @@ var vNode = {
       window.removeEventListener("resize", this.init,20);
     },
     methods: {
+        onUnitScroll: utils.debounce(function() {
+          if (!this.getfreeBuyerOpen) return
+          var scrollTop = this.$refs.container.scrollTop
+          var setRefTop = this.$refs.setRefs.offsetTop
+          console.log(scrollTop, setRefTop);
+          if (scrollTop >= setRefTop && this.getfreeBuyerOpen) {
+            $('.win-analyse').css({
+              "margin-top": '.24rem'
+            })
+          }
+        }, 300),
+        goOpenVip: function () {
+          location.href = "/front/vipsubscribe/vipsubscribe_new"
+        },
         // 查询超级订阅采购单位画像浏览次数
         getUsage: function () {
           var _this = this

+ 18 - 2
src/web/staticres/common-module/collection/css/index.css

@@ -648,7 +648,7 @@
 .unitType .van-tabs__wrap .van-tabs__nav.van-tabs__nav--card .van-tab.van-tab--active {
     background: #ffffff;
 }
-.unitType .van-tabs__wrap .van-tabs__nav.van-tabs__nav--card .van-tab.van-tab--active .van-tab__text{
+.unitType:not(.use-key-card) .van-tabs__wrap .van-tabs__nav.van-tabs__nav--card .van-tab.van-tab--active .van-tab__text{
     color: #2ABED1;
 }
 
@@ -1110,4 +1110,20 @@
   color: #9B9BA3!important;
   line-height: .4rem;
   padding-bottom: .24rem;
-}
+}
+
+.j-tag {
+  padding: .04rem .08rem;
+  font-size: .2rem;
+  line-height: .28rem;
+  border-radius: .08rem;
+  border: 1px solid transparent;
+}
+.j-tag.tag-green {
+  color: #6CCF49;
+  border-color: #6CCF49;
+}
+.j-tag.tag-orange {
+  color: #FF9F3F;
+  border-color: #FF9F3F;
+}

+ 35 - 23
src/web/staticres/common-module/collection/js/area-city-mobile.js

@@ -11,7 +11,7 @@ var areaCityMobileComponentTemplate = `
                 </template>
                 <van-cell
                     clickable
-                    title="全选"
+                    :title="item.name === '全国' ? '全国' : '全选'"
                     :class="{checkActive: item.type}"
                     @click="checkAll(item)"
                 >
@@ -58,7 +58,6 @@ var areaCityMobileComponent = {
   },
   data:function () {
     return {
-      active: 1,
       tablist: [],
       // 原始数组
       provinceListMapExp: {
@@ -144,21 +143,17 @@ var areaCityMobileComponent = {
 
       var provinceList = []
       for (var key in provinceListMap) {
-        if (key === '#') {
-          continue
-        } else {
-          provinceList = provinceList.concat(provinceListMap[key])
-        }
+        provinceList = provinceList.concat(provinceListMap[key])
       }
 
       this.tablist = provinceList.map(function (item) {
         var obj = {
           name: item.name,
-          type: false,
+          type: item.name === '全国',
           children: item.children
         }
         // 如果市直辖市自治区等没有子项的,给他push一个子项
-        if (item.children.length === 0) {
+        if (item.children.length === 0 && item.name !== '全国') {
           obj.children.push({
             name: item.name,
             type: false
@@ -170,19 +165,25 @@ var areaCityMobileComponent = {
     getCitiesFromJSONMap (provinceName) {
       return chinaMapJSON.find(item => item.name.indexOf(provinceName) !== -1)
     },
+    setCountryState (f) {
+      this.tablist[0].type = f
+    },
     setState: function(data) {
       // 设置全国(此处为全部未选中)
       if (!data || Object.keys(data).length === 0) {
         this.allStateChange(false)
-        this.confirmDisabled = true
+        this.setCountryState(true)
       } else {
         for (var key in data) {
           if (data[key].length === 0) {
             // 当前全省
             for (var i = 0; i < this.tablist.length; i++) {
-              this.tablist[i].children.forEach(function (item) {
-                item.type = true
-              })
+              if (this.tablist[i].name === key) {
+                this.tablist[i].children.forEach(function (item) {
+                  item.type = true
+                })
+                break
+              }
             }
           }  else {
             this.tablist.some(function (item) {
@@ -199,7 +200,7 @@ var areaCityMobileComponent = {
           }
           
         }
-        this.confirmDisabled = false
+        this.setCountryState(false)
       }
     },
     // 获取当前选中状态
@@ -207,6 +208,7 @@ var areaCityMobileComponent = {
       var state = {}
       var count = 0
       this.tablist.forEach(function (item) {
+        if (item.name === '全国') return
         if (item.type) {
           // 全省被选中
           state[item.name] = []
@@ -237,22 +239,32 @@ var areaCityMobileComponent = {
     // 全选或者全不选
     allStateChange: function (type) {
       this.tablist.forEach(function (item) {
-        item.type = type
-        item.children.forEach(function (iitem) {
-          iitem.type = type
-        })
+        if (item.name === '全国') {
+
+        } else {
+          item.type = type
+          item.children.forEach(function (iitem) {
+            iitem.type = type
+          })
+        }
       })
     },
     // 模块全选
     checkAll: function (item) {
-      // 子项跟随全选状态
-      item.type = !item.type
-      item.children.forEach(function (city) {
-        city.type = item.type
-      })
+      if (item.name === '全国') {
+        this.setState()
+      } else {
+        this.setCountryState(false)
+        // 子项跟随全选状态
+        item.type = !item.type
+        item.children.forEach(function (city) {
+          city.type = item.type
+        })
+      }
     },
     // 模块单选
     toggleCheck: function (item, parent) {
+      this.setCountryState(false)
       item.type = !item.type
 
       var state = []

+ 0 - 1
src/web/staticres/common-module/collection/js/cate-mobile.js

@@ -96,7 +96,6 @@ var cateComponent = {
   },
   methods: {
     setState: function() {
-      console.log(this.selectcatelist)
       let arr = this.selectcatelist
       if (this.selectcatelist.length != 0) {
         this.tablist.forEach(function(item) {

+ 74 - 37
src/web/staticres/common-module/collection/js/date-mobile.js

@@ -19,7 +19,7 @@ var dateComponentTemplate = `
       </div>
   </div>
   <div v-if="type === 'more-picker'">
-    <van-popup v-model="datePicker.startshow" :safe-area-inset-bottom="true" get-container="#date-picker-other-box" round position="bottom" :style="{ height: '46%' }">
+    <van-popup v-model="datePicker.startshow" :safe-area-inset-bottom="true" :get-container="popupContainer" round position="bottom" :style="{ height: '46%' }">
       <div class="j-container">
         <div class="j-header">
           <div class="headertitle">
@@ -53,7 +53,7 @@ var dateComponentTemplate = `
         </div>
       </div>
     </van-popup>
-    <van-popup v-model="datePicker.endshow" :safe-area-inset-bottom="true" get-container="#date-picker-other-box" round position="bottom" :style="{ height: '46%' }">
+    <van-popup v-model="datePicker.endshow" :safe-area-inset-bottom="true" :get-container="popupContainer" round position="bottom" :style="{ height: '46%' }">
       <div class="j-container">
         <div class="j-header">
           <div class="headertitle">
@@ -115,6 +115,10 @@ var dateComponentTemplate = `
 var dateComponent = {
   name: 'date-mobile',
   props: {
+    popupContainer: {
+      type: String,
+      default: '#date-picker-other-box'
+    },
     'selectdate': {
       type: Object,
       default: function () {
@@ -127,7 +131,9 @@ var dateComponent = {
     },
     "datatype": {
       type: Array,
-      default: []
+      default: function () {
+        return []
+      }
     },
     "rootopen": {
       type: Boolean,
@@ -201,49 +207,58 @@ var dateComponent = {
     }
   },
   methods: {
-    setState () {
+    setState (data) {
       // {
       //   start: 1620230400000, // 2021-5-6
       //   end: 1620489600000, // 2021-5-9
       //   exact: 'all'
       // }
-      let data = this.selectdate
+      if (!data) {
+        data = this.selectdate
+      }
       if (!data || Object.keys(data).length === 0) {
         this.setTimeSelectListState('all')
       } else {
         switch (data.exact) {
-          case 'all': {
-            this.setTimeSelectListState('all')
-            this.clearDateTimePicker()
-            break
-          }
-          case 'lately7': {
-            this.setTimeSelectListState('lately7')
-            this.clearDateTimePicker()
-            break
-          }
-          case 'lately30': {
-            this.setTimeSelectListState('lately30')
-            this.clearDateTimePicker()
-            break
-          }
-          case 'lastYear': {
-            this.setTimeSelectListState('lastYear')
+          case 'all':
+          case 'lately7':
+          case 'lately30':
+          case 'lately90':
+          case 'lately180':
+          case 'thisYear':
+          case 'sinceLastYear':
+          case 'sinceYearBeforeLast': {
+            this.setTimeSelectListState(data.exact)
             this.clearDateTimePicker()
             break
           }
           case 'exact': {
             this.setTimeSelectListState('exact')
             this.dateStyle = true
-            if (data.startDate) {
-              this.dateTimePickerState.start = new Date(data.startDate)
-              this.dateTimePickerState.startPlaceHolder = new Date(data.startDate).pattern('yyyy年MM月dd日')
-              this.datePicker.startcurrentDate = new Date(new Date(data.startDate).pattern('yyyy'), new Date(data.startDate).pattern('MM') - 1 , new Date(data.startDate).pattern('dd'))
-            }
-            if (data.end) {
-              this.dateTimePickerState.end = new Date(data.endDate)
-              this.dateTimePickerState.endPlaceHolder = new Date(data.endDate).pattern('yyyy年MM月dd日')
-              this.datePicker.endcurrentDate = new Date(new Date(data.endDate).pattern('yyyy'), new Date(data.endDate).pattern('MM') - 1, new Date(data.endDate).pattern('dd'))
+
+            // 有startDate&endDate就用。没有就用start/end 恢复数据
+            if (data.startDate || data.endDate) {
+              if (data.startDate) {
+                this.dateTimePickerState.start = new Date(data.startDate)
+                this.dateTimePickerState.startPlaceHolder = new Date(data.startDate).pattern('yyyy年MM月dd日')
+                this.datePicker.startcurrentDate = new Date(new Date(data.startDate).pattern('yyyy'), new Date(data.startDate).pattern('MM') - 1 , new Date(data.startDate).pattern('dd'))
+              }
+              if (data.endDate) {
+                this.dateTimePickerState.end = new Date(data.endDate)
+                this.dateTimePickerState.endPlaceHolder = new Date(data.endDate).pattern('yyyy年MM月dd日')
+                this.datePicker.endcurrentDate = new Date(new Date(data.endDate).pattern('yyyy'), new Date(data.endDate).pattern('MM') - 1, new Date(data.endDate).pattern('dd'))
+              }
+            } else {
+              if (data.start) {
+                this.dateTimePickerState.start = new Date(data.start)
+                this.dateTimePickerState.startPlaceHolder = new Date(data.start).pattern('yyyy年MM月dd日')
+                this.datePicker.startcurrentDate = new Date(new Date(data.start).pattern('yyyy'), new Date(data.start).pattern('MM') - 1 , new Date(data.start).pattern('dd'))
+              }
+              if (data.end) {
+                this.dateTimePickerState.end = new Date(data.end)
+                this.dateTimePickerState.endPlaceHolder = new Date(data.end).pattern('yyyy年MM月dd日')
+                this.datePicker.endcurrentDate = new Date(new Date(data.end).pattern('yyyy'), new Date(data.end).pattern('MM') - 1, new Date(data.end).pattern('dd'))
+              }
             }
             break
           }
@@ -296,15 +311,13 @@ var dateComponent = {
             this.dateTimePickerState.end = new Date(this.dateTimePickerState.end)
           }
           timeState.end = this.dateTimePickerState.end.getTime()
+          // 结束时间为当天23:59:59
+          timeState.end += ((60 * 60 * 1000 * 24) - 1000)
         } else {
           timeState.end = ''
         }
-
-        // 如果开始时间===结束时间(并且都不为0, 不为空),则表示为同一天,取开始时间和结束时间相差23小时
-        if (timeState.start === timeState.end && timeState.start != 0 && timeState.end != 0 && timeState.start && timeState.end) {
-          timeState.end = timeState.end + (60 * 60 * 1000 * 24) - 1000
-        }
       }
+      console.log(timeState)
       return timeState
     },
     // 计算lately7/lately30/lastYear的开始和结束时间
@@ -335,6 +348,31 @@ var dateComponent = {
           t.start = t.end - durations.day30
           break
         }
+        case 'lately90': { // 近3个月
+          t.start = t.end - (durations.day30 * 3)
+          break
+        }
+        case 'lately180': { // 近6个月(近半年)
+          t.start = t.end - (durations.day30 * 6)
+          break
+        }
+        case 'thisYear': { // 今年全年
+          const year = new Date(t.end).getFullYear()
+          t.start = +new Date(`${year}`)
+          t.end = +new Date(`${year + 1}`) - durations.hour1 * 8 - 1
+          break
+        }
+        case 'sinceLastYear': { // 去年至今
+          const year = new Date(t.end).getFullYear()
+          const lastYear = year - 1
+          t.start = +new Date(`${lastYear}`)
+          break
+        }
+        case 'sinceYearBeforeLast': { // 前年至今
+          const year = new Date(t.end).getFullYear()
+          t.start = +new Date(`${year - 2}`)
+          break
+        }
         // 最近一年/去年
         case 'lastYear': {
           if(this.datatype.length !== 0) {
@@ -357,7 +395,6 @@ var dateComponent = {
           break
         }
       }
-      console.log(t)
       return t
     },
     selectFixedDate: function(item) {

+ 77 - 31
src/web/staticres/common-module/collection/js/ent_portrait.js

@@ -132,7 +132,8 @@ var vNode = {
         top10: true,
         topShow: true,
         dt: true
-      }
+      },
+      freeWinnerOpen: false
     }
   },
   created: function () {
@@ -237,7 +238,7 @@ var vNode = {
       return (!this.conf._4 && !this.isVip) || (this.entvisit.total <= this.entvisit.usage && this.powerInfo.memberStatus <= 0 && !this.entvisit.visited) || (this.entvisit.total <= this.entvisit.usage && !this.showContacts && !this.entvisit.visited)
     },
     isMember () {
-      return this.powerInfo.memberStatus <= 0 || !this.conf._4
+      return !this.conf._4 || this.powerInfo.memberStatus <= 0
     },
     isShowUpTip () {
       return this.entvisit.provin == -1 ? false : true && !this.surplus && this.isVip && this.powerInfo.memberStatus <= 0 && !this.entvisit.visited
@@ -273,11 +274,45 @@ var vNode = {
     }
   },
   methods: {
+    // 监听画像页面滚动
+    onEntScroll: utils.debounce(function(){
+      if (!this.freeWinnerOpen) return // 没有开通超级订阅广告位banner return
+      var scrollTop = this.$refs.container.scrollTop // 画像页面父dom滚动距离
+      var offSetTop = this.$refs.setRef.offsetTop // 中标分析-高级分析设置距顶部距离
+      var bannerHeight = this.$refs.bannerRef.offsetHeight // 广告位banner高度
+      if (scrollTop >= offSetTop - bannerHeight) {
+        $('.banner-sticky').css({
+          "position": "fixed",
+          'top': '46px',
+          "z-index": '9999'
+        })
+      } else {
+        $('.banner-sticky').css({
+          "position": "static"
+        })
+        $('.win-analyse').css({
+          "margin-top": '.24rem'
+        })
+      }
+    }, 50),
     scrollHeight: function () {
       var storageClick = JSON.parse(sessionStorage.getItem('is-click-set'))
       if ($('.win-analyse').length && $('.win-analyse').length > 0 && storageClick) {
         this.$nextTick(function(){
-          document.querySelector('.win-analyse').scrollIntoView()
+          // 有开通超级订阅banner时
+          if (this.freeWinnerOpen) {
+            document.querySelector('.banner-sticky').scrollIntoView()
+            $('.banner-sticky').css({
+              "position": "fixed",
+              'top': '46px',
+              "z-index": '9999'
+            })
+            $('.win-analyse').css({
+              "margin-top": '2rem'
+            })
+          } else {
+            document.querySelector('.win-analyse').scrollIntoView()
+          }
           sessionStorage.removeItem('is-click-set')
         })
       }
@@ -367,20 +402,22 @@ var vNode = {
       }
       let urls = ''
       // 如果专家版、智慧版 调大会员接口,如果是专家版、自定义版,同时是超级订阅 根据可查看次数判断 调大会员还是超级订阅接口
-      if (_this.powerInfo.memberStatus > 0 && _this.powerInfo.memberStatus <= 2) {
+      if (_this.powerInfo.memberStatus > 0 && _this.powerInfo.power.indexOf(4) > -1) {
         urls = '/bigmember/portrait/winner/getData'
-      } else if (_this.powerInfo.memberStatus > 2) {
-        if (_this.isVip) { // 超级订阅
-          if (_this.entvisit.total <= _this.entvisit.usage && !_this.entvisit.visited) {
-            urls = '/bigmember/portrait/winner/getData'
-          } else {
-            urls = '/bigmember/portrait/subVipPortrait/winner'
-          }
-        } else {
-          urls = '/bigmember/portrait/winner/getData'
-          // 商机版、自定义版
-        }
-      } else {
+      } 
+      // else if (_this.powerInfo.memberStatus > 2) {
+      //   if (_this.isVip) { // 超级订阅
+      //     if (_this.entvisit.total <= _this.entvisit.usage && !_this.entvisit.visited) {
+      //       urls = '/bigmember/portrait/winner/getData'
+      //     } else {
+      //       urls = '/bigmember/portrait/subVipPortrait/winner'
+      //     }
+      //   } else {
+      //     urls = '/bigmember/portrait/winner/getData'
+      //     // 商机版、自定义版
+      //   }
+      // } 
+      else {
         urls = '/bigmember/portrait/subVipPortrait/winner'
       }
       _this.getEntPortraitInfoTimes++
@@ -456,19 +493,21 @@ var vNode = {
       var _this = this
       var urls = ''
       // 判断专家版、智慧版; 商机版和自定义版时判断是不是超级订阅
-      if (_this.powerInfo.memberStatus > 0 && _this.powerInfo.memberStatus <= 2) {
+      if (_this.powerInfo.memberStatus > 0 && _this.powerInfo.power.indexOf(13) > -1) {
         urls = '/bigmember/portrait/winner/getNewMsg'
-      } else if (_this.powerInfo.memberStatus > 2) {
-        if (_this.isVip) {
-          if (_this.entvisit.total <= _this.entvisit.usage && !_this.entvisit.visited) {
-            urls = '/bigmember/portrait/winner/getNewMsg'
-          } else {
-            urls = '/bigmember/portrait/subVipPortrait/winnerNewMsg'
-          }
-        } else {
-          urls = '/bigmember/portrait/winner/getNewMsg'
-        }
-      } else {
+      } 
+      // else if (_this.powerInfo.memberStatus > 2) {
+      //   if (_this.isVip) {
+      //     if (_this.entvisit.total <= _this.entvisit.usage && !_this.entvisit.visited) {
+      //       urls = '/bigmember/portrait/winner/getNewMsg'
+      //     } else {
+      //       urls = '/bigmember/portrait/subVipPortrait/winnerNewMsg'
+      //     }
+      //   } else {
+      //     urls = '/bigmember/portrait/winner/getNewMsg'
+      //   }
+      // } 
+      else {
         urls = '/bigmember/portrait/subVipPortrait/winnerNewMsg'
       }
       return urls
@@ -651,12 +690,16 @@ var vNode = {
                 _this.portrait = 'winnerVip'
               }
               // 新版超级订阅用户获取访问量
-              if (res.data.viper && _this.conf.isMember <= 0) {
+              if (res.data.viper && (_this.conf.isMember <= 0 || res.data.power.indexOf(4) == -1)) {
                 _this.getEntVisits()
               }
 	            //免费用户体验权限
-	            if(res.data.isFree&&res.data.freeEntPort==0){
-	            	_this.canFreeExp=true
+	            if(res.data.isFree){
+                if (res.data.freeEntPort==0) {
+                  _this.canFreeExp=true
+                } else {
+                  _this.freeWinnerOpen = true
+                }
 	            }
               // 免费用户看过当前企业画像数据
               if (res.data.isFree) {
@@ -1222,6 +1265,9 @@ var vNode = {
       //     confirmButtonText: '我知道了'
       //   }).then(function () { })
       // }
+    },
+    goOpenVip: function() {
+      location.href = "/front/vipsubscribe/vipsubscribe_new"
     }
   }
 }

+ 35 - 0
src/web/staticres/common-module/collection/js/industry-mobile.js

@@ -167,6 +167,24 @@ var industryComponent = {
         })
         this.canClick = bool
       }
+      // this.checkSelectedAll()
+    },
+    // 检查是否全选
+    checkSelectedAll: function () {
+      this.tablist.forEach(function(item){
+        var children = item[Object.keys(item)[0]]
+        var childrenState = []
+        children.forEach(function(child) {
+          childrenState.push(child)
+        })
+
+        if (childrenState.indexOf(false) === -1) {
+          // 已全选
+          item.type = true
+        } else {
+          item.type = false
+        }
+      })
     },
     // 总全选
     checkBoxAll:function() {
@@ -274,6 +292,22 @@ var industryComponent = {
       this.$emit('cancel', params)
       return params
     },
+    getSelected: function () {
+      var industryObj = {}
+      this.tablist.forEach(function(item, index){
+        var key = Object.keys(item)[0]
+        item[key].forEach(function(data, i) {
+          if(data.type){
+            if (industryObj[key]) {
+              industryObj[key] = industryObj[key].concat([data.name])
+            } else {
+              industryObj[key] = [data.name]
+            }
+          }
+        })
+      })
+      return industryObj
+    },
     // 确定按钮
     onConfirm:function() {
       let industryArr = []
@@ -290,6 +324,7 @@ var industryComponent = {
       let params = {
         name: 'industryItem',
         data: industryArr,
+        detail: this.getSelected(),
         t: t
       }
       this.$emit('confirm', params)

+ 85 - 17
src/web/staticres/common-module/collection/js/keyword-mobile.js

@@ -1,14 +1,14 @@
 var keywordComponentTemplate = `<div class="j-container">
 <div class="j-main">
   <div class="unitTab">
-    <van-tabs type="card" class="unitType" v-model="active">
+    <van-tabs type="card" class="unitType" :class="{ 'use-key-card': useKeyCard }" v-model="active">
       <van-tab title="全部">
         <van-cell-group>
           <van-cell
           clickable
           type="primary"
           title="全选"
-          :class="{checkActive:checkedAll==true}"
+          :class="{ checkActive: checkedAll==true && !useKeyCard }"
           @click="checkBoxAll"
           >
           <template #right-icon>
@@ -27,7 +27,7 @@ var keywordComponentTemplate = `<div class="j-container">
         <van-cell
             clickable
             title="全选"
-            :class="{checkActive:item[Object.keys(item)[1]]==true}"
+            :class="{ checkActive: item[Object.keys(item)[1]]==true && !useKeyCard }"
             @click="checkAll(item)"
             >
             <template #right-icon>
@@ -40,11 +40,18 @@ var keywordComponentTemplate = `<div class="j-container">
             clickable
             label-disabled="false"
             :key="i"
-            :class="{checkActive:iitem.type==true}"
-            title-class="van-multi-ellipsis--l2"
+            :class="{ checkActive: iitem.type==true && !useKeyCard }"
+            :title-class="useKeyCard ? '' : 'van-multi-ellipsis--l2'"
             :title="iitem.text || iitem.name"
             @click="toggleCheck(iitem, item)"
           >
+            <template #title v-if="useKeyCard">
+              <span class="j-tag" :class="iitem.matchway == 1 ? 'tag-orange' : 'tag-green'">{{ iitem.matchway == 1 ? '模糊' : '精准' }}</span>
+              <span class="custom-title">{{ iitem.text || iitem.name }}</span>
+            </template>
+            <template #label v-if="useKeyCard && iitem.notkey">
+              <span class="custom-title">排除词:{{ iitem.notkey }}</span>
+            </template>
             <template #right-icon>
               <van-checkbox checked-color="#2ABED1" :bind-group="false" v-model="iitem.type" :name="iitem.name" ref="checkboxes" />
             </template>
@@ -66,6 +73,10 @@ var keywordComponentTemplate = `<div class="j-container">
 var keywordComponent = {
   name: 'keyword-mobile',
   props: {
+    useKeyCard: {
+      type: Boolean,
+      default: false
+    }, 
     "selectkeywordlist": {
       type: Array,
       default: function () {
@@ -86,7 +97,8 @@ var keywordComponent = {
       tablist: [],
       checkedAll: false,
       canClick: true,
-      isvip: false
+      isvip: false,
+      keywordGroupList: []
     }
   },
   computed: {
@@ -138,6 +150,7 @@ var keywordComponent = {
               let maxarr = []
               if(res.data) {
                 let data = res.data.member_jy.a_items
+                _this.keywordGroupList = data
                 data.forEach(function(item,index) {
                   let minarr = []
                   let keyname = item.s_item
@@ -150,6 +163,10 @@ var keywordComponent = {
                     data = {
                       name: data.key[0],
                       text: textArr.join(' '), // 展示在页面上的文字
+                      notkey: data.notkey ? data.notkey.join(' ') : '',
+                      // matchWayText: item.matchway == 1 ? '模糊' : '精准',
+                      // matchWayClass: item.matchway == 1 ? 'tag-orange' : 'tag-green'
+                      matchway: data.matchway,
                       type: false
                     }
                     minarr.push(data)
@@ -161,12 +178,12 @@ var keywordComponent = {
                   maxarr.push(obj)
                 })
                 _this.tablist = maxarr
-                console.log('maxarr', maxarr)
                 if(maxarr.length == 0) {
                   _this.active = 0
                 }else {
                   _this.active = 1
                 }
+                _this.setState()
               }
             }
           } else {
@@ -175,6 +192,7 @@ var keywordComponent = {
               if(_this.isvip) {
                 if(res.userData && res.userData.o_vipjy) {
                   let data = res.userData.o_vipjy.a_items
+                  _this.keywordGroupList = data
                   data.forEach(function(item,index) {
                     let minarr = []
                     let keyname = item.s_item
@@ -187,6 +205,8 @@ var keywordComponent = {
                       data = {
                         name: data.key[0],
                         text: textArr.join(' '), // 展示在页面上的文字
+                        notkey: data.notkey ? data.notkey.join(' ') : '',
+                        matchway: data.matchway,
                         type: false
                       }
                       minarr.push(data)
@@ -198,7 +218,6 @@ var keywordComponent = {
                     maxarr.push(obj)
                   })
                   _this.tablist = maxarr
-                  console.log('maxarr', maxarr)
                   if(maxarr.length == 0) {
                     _this.active = 0
                   }else {
@@ -242,7 +261,7 @@ var keywordComponent = {
               _this.setState()
             }
           }
-          
+          _this.checkNoKey()
         },
         error: function(err){
           console.log(err)
@@ -250,21 +269,39 @@ var keywordComponent = {
       })
     },
     setState: function() {
+      var _this = this
       let bool = true
       let keyArr = this.selectkeywordlist
       this.tablist.forEach(function(item) {
-        console.log(item, 'item')
         item[Object.keys(item)[0]].forEach(function(data) {
-          keyArr.forEach(function(sum) {
-            if(data.name == sum) {
-              data.type = true
-              bool = false
-            }
-          })
+          if (keyArr.indexOf(data.text) !== -1) {
+            data.type = true
+            bool = false
+          } else {
+            data.type = false
+          }
         })
+        item.type = _this.checkIsAllChildrenSelected(item[Object.keys(item)[0]])
       })
       this.canClick = bool
     },
+    // 传入某个分类下children数组, 是否全部被选中
+    checkIsAllChildrenSelected: function (children) {
+      if (!Array.isArray(children)) return false
+      var stateArr = []
+      children.forEach(function (item) {
+        stateArr.push(item.type)
+      })
+      return stateArr.indexOf(false) === -1
+    },
+    resetAllNoSelect: function () {
+      this.canClick = true
+      this.tablist.forEach(function(item) {
+        item[Object.keys(item)[0]].forEach(function(data) {
+          data.type = false
+        })
+      })
+    },
     // 总全选
     checkBoxAll:function() {
       if(this.checkedAll){
@@ -367,23 +404,54 @@ var keywordComponent = {
       this.$emit('cancel', params)
     },
     // 确定按钮
-    onConfirm:function() {
+    onConfirm:function () {
       let keywordArr = []
+      var detailArr = []
       let t = ''
       this.tablist.forEach(function(item, index){
+        var classify = {
+          s_item: Object.keys(item)[0],
+          a_key: []
+        }
         item[Object.keys(item)[0]].forEach(function(data, i) {
           if(data.type){
             keywordArr.push(data.text || data.name)
+            classify.a_key.push({
+              key: data.text.split(' '),
+              notkey: data.notkey.split(' '),
+              matchway: data.matchway,
+              updatetime: data.updatetime
+            })
           }
         })
+        if (classify.a_key.length) {
+          detailArr.push(classify)
+        }
       })
       t = '关键词' + keywordArr.length
       let params = {
         name: 'keywordItem',
         data: keywordArr,
+        detail: detailArr,
         t: t
       }
       this.$emit('confirm', params)
+    },
+    checkNoKey () {
+      var count = this.checkHasOneKey()
+      if (count <= 0) {
+        this.$emit('nokeys')
+      }
+    },
+    checkHasOneKey () {
+      var count = 0
+      this.tablist.forEach(function (classify) {
+        var cName = Object.keys(classify)[0]
+        if (Array.isArray(classify[cName])) {
+          count += classify[cName].length
+        }
+      })
+      return count
     }
   }
 }

+ 1 - 1
src/web/staticres/common-module/collection/js/vip-dialog.js

@@ -89,7 +89,7 @@ var vipComponent = {
         },
         source: ''
       }
-      console.log(this.power, this.power.isMember, this.power._4, this.power._13, this.newvip,this.entvisit, this.power.vipStatus)
+      // console.log(this.power, this.power.isMember, this.power._4, this.power._13, this.newvip,this.entvisit, this.power.vipStatus)
       if (this.power.isMember > 0 ) {
         if (this.entvisit.total <= this.entvisit.usage && this.newvip) {
           textMap.btnText = '联系客服'

+ 87 - 0
src/web/staticres/common-module/diy-report/css/report-list.css

@@ -0,0 +1,87 @@
+.info-card-group {
+    padding: .4rem;
+    box-sizing: border-box;
+    background: #F4F5F7;
+    font-family: -apple-system,BlinkMacSystemFont,Helvetica Neue,PingFang SC,Microsoft YaHei,Source Han Sans SC,Noto Sans CJK SC,WenQuanYi Micro Hei,sans-serif;
+
+}
+.info-card-group .info-card-item + .info-card-item {
+    margin-top: .32rem;
+}
+.info-card-group .info-card-item {
+    background: #FFFFFF;
+    box-shadow: 0px 2px 8px 1px rgba(54, 147, 179, 0.05);
+    border-radius: 8px;
+    padding: .32rem .24rem;
+    box-sizing: border-box;
+    font-size: .26rem;
+    font-weight: 500;
+    color: #5E5E64;
+    line-height: .4rem;
+}
+.info-card-item .text-title {
+    font-size: .3rem;
+    font-weight: 700;
+    color: #161826;
+    line-height: .44rem;
+}
+.info-flex-r-box {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
+    word-break: break-all;
+}
+.info-card-item .info-content-group {
+    margin-top: .16rem;
+}
+.info-card-item .info-content-group .info-content-label {
+    flex-shrink: 0;
+}
+.info-card-item .info-content-group .info-flex-r-box {
+    margin-top: .08rem;
+    line-height: .4rem;
+    align-items: flex-start;
+    justify-content: flex-start;
+}
+.info-card-item button {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin: 0 auto;
+    margin-top: .24rem;
+    width: 80%;
+    height: .72rem;
+    background: #2CB7CA;
+    border-radius: 6px;
+    font-size: .32rem;
+    font-weight: 400;
+    color: #FFFFFF;
+    border: none;
+}
+.info-card-item .toggle-row-box i {
+    font-size: .32rem;
+    margin-left: .04rem;
+}
+.info-card-item .toggle-row-box {
+    color: #2ABDD1;
+}
+[v-cloak] {
+    opacity: 0;
+}
+
+
+.card-opened .filters {
+    flex-direction: column;
+}
+.card-opened .info-content-group .info-flex-r-box {
+    line-height: .6rem;
+}
+.card-opened .info-content-group .info-flex-r-box:not(:last-of-type) {
+    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+}
+.card-opened .info-content-label {
+    font-weight: 700;
+    font-size: .26rem;
+    color: #161826;
+}

+ 219 - 0
src/web/staticres/common-module/diy-report/js/report-list.js

@@ -0,0 +1,219 @@
+var reportListTemplate = `
+<div id="reportList" class="info-card-group" v-cloak>
+    <van-list
+        v-model="listState.loading"
+        :finished="listState.finished"
+        :finished-text="reportList.length !== 0 ? '没有更多了' : ''"
+        @load="getList">
+        <div class="empty-container" v-show="reportList.length === 0 && listState.loaded">
+            <div class="empty-content-position">
+                <div class="image">
+                    <img src="/common-module/public/image/jy-back.png">
+                </div>
+                <div class="empty-main tip-text">暂无数据</div>
+            </div>
+        </div>
+        <div class="info-card-item" v-for="(item, i) in reportList" :key="item.id" :class="{ 'card-opened': item.open }">
+            <div class="info-flex-r-box">
+                <div class="text-title">报告&nbsp;@@(item.createTime * 1000)|formatTime('yyyy.MM.dd HH:mm:ss')@@</div>
+                    <div class="info-flex-r-box toggle-row-box" @click="item.open = !item.open">
+                        <span>@@item.open ? '收起' : '展开'@@条件</span>
+                        <transition name="van-fade">
+                            <i class="van-icon" :class="{'van-icon-arrow-down': !item.open, 'van-icon-arrow-up': item.open}"></i>
+                        </transition>
+                    </div>
+                </div>
+                <div class="info-content-group">
+                    <div class="info-flex-r-box filters">
+                        <span class="info-content-label">分析内容:</span>
+                        <div class="info-content-box"
+                            :class="{'van-ellipsis': !item.open}"
+                            v-html="formatKeys(item.keysItems, item.open)">
+                        </div>
+                    </div>
+                    <div class="info-flex-r-box filters">
+                        <span class="info-content-label">时间:</span>
+                        <div class="info-content-box" :class="{'van-ellipsis': !item.open}">
+                            @@item.rangeTimeStart|formatTime('yyyy.MM.dd')@@-@@item.rangeTimeEnd|formatTime('yyyy.MM.dd')@@
+                        </div>
+                    </div>
+                    <div class="info-flex-r-box filters">
+                        <span class="info-content-label">地区:</span>
+                        <div class="info-content-box" :class="{'van-ellipsis': !item.open}">
+                            @@item.area|formatArea@@
+                        </div>
+                    </div>
+                    <div class="info-flex-r-box filters">
+                        <span class="info-content-label">行业:</span>
+                        <div class="info-content-box" :class="{'van-ellipsis': !item.open}">
+                            @@item.industry|formatIndustry@@
+                        </div>
+                    </div>
+                    <div class="info-flex-r-box filters">
+                        <span class="info-content-label">采购单位类型:</span>
+                        <div class="info-content-box" :class="{'van-ellipsis': !item.open}">
+                            @@item.buyerclass|formatBuyerclass@@
+                        </div>
+                    </div>
+                </div>
+                <button @click="goReport(item.id)">查看报告</button>
+            </div>
+        </div>
+    </van-list>
+</div>
+`
+var reportListMobileComponent = {
+    name: 'report-list',
+    template: reportListTemplate,
+    delimiters: ['@@', '@@'],
+    data: function () {
+        return {
+            listState: {
+                loaded: false,
+                loading: true,
+                finished: false,
+                total: 0,
+                pageNum: 1,
+                pageSize: 20
+            },
+            reportList: []
+        }
+    },
+    filters: {
+        formatTime: function (value, fmt) {
+            if (!value) return ''
+            return new Date(value).pattern(fmt)
+        },
+        formatBuyerclass: function (value) {
+            if (!value) return '全部'
+            return String(value).replace(/,/g, ',')
+        },
+        formatArea: function (value) {
+            if (!value) return '-'
+            value = JSON.parse(value)
+
+            if (Object.keys(value).length === 0) {
+                return '全国'
+            }
+
+            var area = []
+            var citys = []
+            for (var key in value) {
+                if (!value[key].length) {
+                    area.push(key)
+                } else {
+                    citys.push(...value[key])
+                }
+            }
+
+            var concatList = area.concat(citys)
+
+            if (concatList.length) {
+                return concatList.join(',')
+            } else {
+                return '全国'
+            }
+        },
+        formatIndustry: function (value) {
+            if (!value) return '全行业'
+            value = JSON.parse(value)
+
+            if (Object.keys(value).length === 0) {
+                return '全行业'
+            }
+
+            var keyArr = []
+            var valueArr = []
+            for (var key in value) {
+                if (!value[key].length) {
+                    keyArr.push(key)
+                } else {
+                    valueArr.push(...value[key])
+                }
+            }
+
+            return valueArr.join(',')
+        }
+    },
+    mounted: function () {
+        this.getList()
+    },
+    methods: {
+        goReport: function (id) {
+            this.$emit('go-report', id)
+        },
+        getList: function () {
+            $.ajax({
+                url: '/bigmember/marketAnalysis/analysisHistory',
+                type: 'POST',
+                data: {
+                    pageNum: this.listState.pageNum,
+                    pageSize: this.listState.pageSize
+                },
+                success: function (res) {
+                    if (res && res.data && !res.error_msg) {
+                        if (res.data.total !== -1) {
+                            this.listState.total = res.data.total
+                        }
+                        if (res.data.list) {
+                            var tempList = res.data.list.map(function (v) {
+                                v.open = false
+                                if (v.rangeTime) {
+                                    const rangeTimeArr = v.rangeTime.split('-')
+                                    v.rangeTimeStart = new Date(rangeTimeArr[0] * 1000).getTime()
+                                    v.rangeTimeEnd = new Date(rangeTimeArr[1] * 1000).getTime()
+                                }
+                                return v
+                            })
+                            this.listState.pageNum++
+                            this.reportList = this.reportList.concat(tempList)
+                            if (tempList.length < this.listState.pageSize) {
+                                this.listState.finished = true
+                            }
+                        } else {
+                            this.listState.finished = true
+                        }
+                    } else {
+                        this.listState.finished = true
+                    }
+                }.bind(this),
+                error: function (err) {
+                    this.listState.finished = true
+                    this.listState.loading = false
+                }.bind(this),
+                complete: function () {
+                    this.listState.loading = false
+                    this.listState.loaded = true
+                }.bind(this)
+            })
+        },
+        formatKeys: function (keys, open) {
+            var tempStr = '-'
+            if (!keys) return tempStr
+            try {
+                var tempResult = []
+                var tempList = JSON.parse(keys)
+                tempList.forEach(function (v) {
+                    v.a_key.forEach(function (k) {
+                        tempResult.push({
+                            key: [].concat(k.key, k.appendkey),
+                            type: k.matchway === 1 ? '精准' : '模糊'
+                        })
+                    })
+                })
+
+                if (open) {
+                    tempStr += '<br />'
+                    tempStr = tempResult.map(function (v) {
+                        return `<div>[${v.key.join(' ')}]-${v.type}</div>`
+                    }).join('')
+                } else {
+                    tempStr = tempResult.map(function (v) {
+                        return `[${v.key.join(' ')}-${v.type}]`
+                    }).join('、')
+                }
+            } catch (e) {}
+            return tempStr
+        }
+    }
+}

BIN=BIN
src/web/staticres/commonFunctions/analysis_report.png


+ 12 - 0
src/web/staticres/css/dev2/newBidSearch.css

@@ -549,4 +549,16 @@
 }
 .custom-alert .el-message-box__btns button:nth-child(2){
   margin-left: 32px;
+}
+.free-go-open{
+  margin-left: 32px;
+  color: #686868;
+  font-size: 14px;
+}
+.free-go-open .go-open-btn{
+  text-decoration: none;
+}
+.free-go-open .go-open-btn:hover{
+  text-decoration: none;
+  color: #fff;
 }

+ 2 - 2
src/web/staticres/js/ent-search-index-pc.js

@@ -756,10 +756,10 @@ var vm = new Vue({
             var svipLink = '/swordfish/page_big_pc/svip/ent_ser_portrait/' + id
             // 大会员画像
             var memberLink = '/swordfish/page_big_pc/ent_portrait/' + id
-            console.log(window.memberStatus, this.powerInfo.vip)
+            console.log(window.memberStatus, this.powerInfo.vip, window.memberPower)
             if (this.powerInfo.member) {
                 // 如果是专家版、智慧版 跳大会员页面
-                if (window.memberStatus <= 2) {
+                if (window.memberPower && window.memberPower.indexOf(4) !== -1) {
                   window.open(memberLink)
                 } else {
                   // 如果是商机版、自定义版

+ 10 - 4
src/web/staticres/js/login.js

@@ -306,6 +306,12 @@ function checkBigStatus () {
         }
         if (res.data.viper) {
           $(".myorderDiv.ent-search").show()
+        }
+        if (res.data.power.indexOf(4) == -1 && res.data.vipStatus>0&&res.data.viper) {
+          $(".myorderDiv.entPortraitRecord").show()
+        }
+        if (res.data.power.indexOf(5) == -1 && res.data.vipStatus>0&&res.data.viper) {
+          $(".myorderDiv.buyerPortraitRecord").show()
         }
 		if (res.data.memberStatus<=0&&res.data.vipStatus>0&&res.data.viper){
 			$(".myorderDiv.portraitRecord").show()
@@ -434,10 +440,10 @@ var logic = function(data,num){
           +"<div class=\"myorderDiv bx-collection\" onclick=\"window.location.href='/swordfish/frontPage/collection/sess/index'\">"
           +"<span>标讯收藏</span>"
           +"</div>"
-		  +"<div class=\"myorderDiv portraitRecord\" style='display: none' onclick=\"window.location.href='/swordfish/frontPage/seeHistory/sess/index'\">"
+		  +"<div class=\"myorderDiv portraitRecord entPortraitRecord\" style='display: none' onclick=\"window.location.href='/swordfish/frontPage/seeHistory/sess/index'\">"
 		  +"<span>企业画像记录</span>"
 		  +"</div>"
-		  +"<div class=\"myorderDiv portraitRecord\" style='display: none' onclick=\"window.location.href='/swordfish/frontPage/seeBuyerHistory/sess/index'\">"
+		  +"<div class=\"myorderDiv portraitRecord buyerPortraitRecord\" style='display: none' onclick=\"window.location.href='/swordfish/frontPage/seeBuyerHistory/sess/index'\">"
 		  +"<span>采购单位画像记录</span>"
 		  +"</div>"
 					hhtml+= "<div class='exitDiv' onclick='signout()'>"
@@ -727,10 +733,10 @@ var haslogin = function(num,kyorpn,url){
             +"<div class=\"myorderDiv bx-collection\" onclick=\"window.location.href='/swordfish/frontPage/collection/sess/index'\">"
             +"<span>标讯收藏</span>"
             +"</div>"
-			+"<div class=\"myorderDiv portraitRecord\" style='display: none' onclick=\"window.location.href='/swordfish/frontPage/seeHistory/sess/index'\">"
+			+"<div class=\"myorderDiv portraitRecord entPortraitRecord\" style='display: none' onclick=\"window.location.href='/swordfish/frontPage/seeHistory/sess/index'\">"
 			+"<span>企业画像记录</span>"
 			+"</div>"
-			+"<div class=\"myorderDiv portraitRecord\" style='display: none' onclick=\"window.location.href='/swordfish/frontPage/seeBuyerHistory/sess/index'\">"
+			+"<div class=\"myorderDiv portraitRecord buyerPortraitRecord\" style='display: none' onclick=\"window.location.href='/swordfish/frontPage/seeBuyerHistory/sess/index'\">"
 			+"<span>采购单位画像记录</span>"
 			+"</div>"
             hhtml+= "<div class='exitDiv' onclick='signout()'>"

+ 20 - 2
src/web/staticres/me/js/mine.js

@@ -106,8 +106,26 @@ var mine = {
                         $('#file-pack').hide()
                       }
                   } else {
-                    $('#ent-follow-history').hide()
-                    $('#buyer-follow-history').hide()
+                    // 有采购单位全景分析权限的 不显示画像记录 没有的判断是否是超级订阅新用户
+                    if (res.data.power && res.data.power.indexOf(5) > -1) {
+                      $('#buyer-follow-history').hide()
+                    } else {
+                      if(res.data.vipStatus > 0 && res.data.viper ) {
+                        $('#buyer-follow-history').show()
+                      } else {
+                        $('#buyer-follow-history').hide()
+                      }
+                    }
+                    // 有企业全景分析权限的 不显示画像记录 没有的判断是否是超级订阅新用户
+                    if (res.data.power && res.data.power.indexOf(4) > -1) {
+                      $('#ent-follow-history').hide()
+                    } else {
+                      if (res.data.vipStatus > 0 && res.data.viper) {
+                        $('#ent-follow-history').show()
+                      } else {
+                        $('#ent-follow-history').hide()
+                      }
+                    }
                   }
                   if ($.isArray(res.data.power)) {
                       // 大会员没有附加下载包权限用户且新版超级订阅用户

+ 3 - 1
src/web/staticres/vipsubscribe/js/historypush.js

@@ -418,7 +418,9 @@ var vm = new Vue({
         var count = data.count
         this.selectAreaList = areaCityRes
         if (!areaCityRes || Object.keys(areaCityRes).length === 0) {
-          
+          this.area = ''
+          this.city = ''
+          $('.areaText').html('地区')
         } else {
           var obj = {
             p: [], // 省份全选

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
src/web/templates/big-member/wx/page_index.html


+ 12 - 6
src/web/templates/big-member/wx/page_unit_portrayal.html

@@ -108,12 +108,12 @@
 </head>
 <body>
 <div class="j-container">
-    <div id="unit_portrayal" class="j-main" v-cloak @click="doubleBar.showTooltip = false">
+    <div id="unit_portrayal" ref="container" class="j-main" v-cloak @click="doubleBar.showTooltip = false" @scroll="onUnitScroll">
         <div v-if="chartLoading" class="skeleton">
             <img class="working"  src="/big-member/image/working.gif" alt="">
         </div>
         <div v-else>
-          <div class="u-header">
+          <div class="u-header" style="padding-bottom: 0.24rem;">
               <div class="company">
                   <span class="j-icon icon-company"></span>
                   <span class="ent-title">${buyer.name || '--'}</span>
@@ -121,18 +121,24 @@
               <p class="region">所在地:${statistics.province || '--'} ${statistics.city}</p>
               <p class="buyer-type">采购单位类型:${statistics.buyerClass || '--'}</p>
           </div>
+          <!-- 留完资的免费用户 已体验和未体验的展示去开通 -->
+          <div v-if="getfreeBuyerOpen">
+            <van-sticky>
+              <img @click="goOpenVip" src="/big-member/image/buyer-open.png" alt="">
+            </van-sticky>
+          </div>
           <!-- 免费用户采购单位全景分析提示 -->
-          <div v-if="getfreeBuyerPort" style="margin-top: .24rem; " class="free-give">
+          <div v-if="getfreeBuyerPort" class="free-give">
             <div class="go-text"> 免费赠送1次【采购单位全景分析】权益体验机会!</div>
             <div class="go-btn"  @click="goGiveAnalysis">去解锁</div>
           </div>
           <!-- 超级订阅用户展示  -->
-          <div v-if="superVipPort" style="margin-top: .24rem; " class="free-give">
+          <div v-if="superVipPort" class="free-give">
             <div class="balance-text"> 当月采购单位画像余额:<em class="highlight-text">${usageInfo.surplus}</em></div>
             <div class="go-btn" @click="goUpgradeOrConcat(superVipBtnText)">${superVipBtnText}</div>
           </div>
           <!-- 采购单位通讯录 -->
-          <div style="margin-top: .24rem;">
+          <div>
             <div v-if="getStatus" key="txl">
               <div class="vip_component" style="height:10.8rem;background:url('/common-module/collection/image/buyer/01-bg.png') no-repeat;background-size:100% 100%">
                 <p class="example-title win-bid-title">采购单位通讯录</p>
@@ -143,7 +149,7 @@
           </div>
           <!-- 高级分析设置 -->
             <!-- 高级分析 -->
-            <div class="win-analyse">
+            <div class="win-analyse" ref="setRefs">
               <span class="win-bid-title">采购单位分析</span>
               <div class="high-link" @click="goHighSet">
                 <span>高级分析设置</span>

+ 9 - 3
src/web/templates/frontRouter/wx/collection/sess/ent_portrait.html

@@ -72,7 +72,7 @@
 </style>
 <body>
 <div class="j-container">
-    <div id="ent-portrait" class="j-main" v-cloak>
+    <div id="ent-portrait" class="j-main" v-cloak ref="container"  @scroll="onEntScroll">
         <!-- <van-dialog
         v-model="setShow"
         show-cancel-button
@@ -222,7 +222,7 @@
                 <template #title>
                     <span :class="{bidinfo:!hasOnePower}">中标分析</span>
                     <span v-if="isShowUpTip" class="bid_upgrade">升级</span>
-                    <span v-if="isMember && (hasOnePower && surplus && isVip)" class="bid_surplus">剩余:${entvisit.total - entvisit.usage}</span>
+                    <span v-if="(hasOnePower && surplus && isVip)" class="bid_surplus">剩余:${entvisit.total - entvisit.usage}</span>
                 </template>
                 <div v-if="!showContacts">
                   <div style="background: #fff;padding: .24rem .32rem 0;">
@@ -235,8 +235,14 @@
                 <div class="bg-white tab-card cell-list history-list" v-else>
                   <hispro-component type="winner" :id="entInfo.id"></hispro-component>
                 </div>
+                <!-- 留完资的免费用户 已体验和未体验的展示去开通 -->
+                <div v-if="freeWinnerOpen" class="banner-sticky" ref="bannerRef">
+                  <!-- <van-sticky offset-top="33.67vw"> -->
+                    <img @click="goOpenVip" src="/big-member/image/winner-open.png" alt="">
+                  <!-- </van-sticky> -->
+                </div>
                 <!-- 高级分析 -->
-                <div class="win-analyse">
+                <div class="win-analyse" ref="setRef">
                   <span class="win-bid-title">中标分析</span>
                   <div class="high-link" @click="goHighSet">
                     <span>高级分析设置</span>

+ 15 - 4
src/web/templates/pc/biddetail_rec.html

@@ -929,6 +929,10 @@
             <img class="file-icon-help" src="/images/help-b.png" alt="">
             <span class="concat-kf recharge-new">立即充值</span>
           </span>
+          <span class="free-go-open" style="display:none;">
+            <span>如需下载更多附件,请开通超级订阅</span>
+            <a class="concat-kf go-open-btn" href="/swordfish/page_big_pc/free/svip/buy">去开通>> </a>
+          </span>
         </div>
 				<div class="download-list" style="margin-top: 20px">
 				</div>
@@ -2653,7 +2657,7 @@ var ucbs_source="pc_rec",ucbsId="{{.T.obj.ucbsId}}";
 				}
 				if (isMember) {
 					// 如果是专家版、智慧版 跳大会员页面
-					if(window.memberStatus <=2) {
+					if(window.memberStatus > 0 && window.memberPower && window.memberPower.indexOf(4) !== -1) {
 						window.open(memberLink)
 					} else {
 						// 如果是商机版、自定义版
@@ -3456,7 +3460,8 @@ function fromwhere(text){
         return
       }
       //  是大会员自定义版本没有下载权限 或 非超级订阅的商机管理用户 (弹框提醒联系客服)
-      if ((window.memberStatus > 0 &&  window.memberPower.indexOf(3) == -1) || (window.vipStatus <=0 && window.entniche)) {
+      var memberNoVip = (window.memberStatus > 0 &&  window.memberPower.indexOf(3) == -1) && !(window.vipStatus > 0 && window.viper)
+      if (memberNoVip || (window.vipStatus <=0 && window.entniche)) {
         bidVue.$alert('对不起,暂无权限,请联系客服', {
           showClose:false,
           center: true,
@@ -3645,8 +3650,14 @@ function fromwhere(text){
   // 根据isAdd接口 展示附件部分dom
   function showFileSomeDom () {
     // 免费用户展示可下载一次提示(免费用户且没有体验过附件下载权益的展示)
-    if (window.isFree && window.freeFile == 0) {
-      $('.free-download').css('display', 'inline-block')
+    if (window.isFree) {
+      if (window.freeFile == 0) {
+        $('.free-download').css('display', 'inline-block')
+        $('.free-go-open').hide()
+      } else {
+        $('.free-go-open').css('display', 'inline-block')
+        $('.free-download').hide()
+      }
     }
     // 新超级订阅用户
     if (window.vipStatus > 0 && window.viper) {

+ 3 - 3
src/web/templates/pc/subscribe_new.html

@@ -224,8 +224,8 @@
                 <div class="content">打通企业库、项目库、招标库多源数据,构建企业多维度分析,获取企业历史项目、数量、规模,深入挖掘合作客户及关系等;</div>
                 <div class="title"><div class="font">采购单位全景分析</div></div>
                 <div class="content">提供采购单位的历史采购周期、规模等深入分析甲方采购需求、供应商关系,帮助企业拓展客户;</div>
-                <div class="title"><div class="font">周报/月报</div></div>
-                <div class="content">订阅招标项目信息提供周报/月报多维分析,帮助销售管理者快速做出预判与决策。</div>
+                <div class="title"><div class="font">周报/月报/定制化市场分析报告</div></div>
+                <div class="content">订阅招标项目信息提供周报/月报/定制化市场分析报告多维分析,帮助销售管理者快速做出预判与决策。</div>
             </div>
             <div class="content-right">
                 <img src="{{Msg "seo" "cdn"}}/images/subscribe/scenario_3.png?v={{Msg "seo" "version"}}" alt="" style="width: 630px;height: 432px">
@@ -287,7 +287,7 @@
                     <li class="double"><div>推送设置</div><div>固定时间/实时推送</div></li>
                     <li class="gray double"><div>标讯高级搜索</div><div>按联系方式、附件、项目名称/标的物、发布时间搜索</div></li>
                     <li class="double"><div>企业搜索</div><div>按中标项目/标的物、联系方式等搜索企业信息</div></li>
-                    <li class="gray">月报/周报</li>
+                    <li class="gray">周报/月报/定制化市场分析报告</li>
                     <li class=" double"><div>标讯收藏</div><div>关注项目一键收藏,重要信息不遗漏</div></li>
                     <li class="gray">专属资源社群对接</li>
                 </ul>

+ 57 - 10
src/web/templates/weixin/wxinfocontent_rec.html

@@ -719,10 +719,33 @@ em {
           overflow: hidden;
           margin: 0 auto;
       }
+      .free-open-tip{
+        display: flex;
+        align-items: center;
+        height: .4rem;
+        margin-left: .24rem;
+        background: rgba(42, 189, 209, 0.1);
+        border-radius: 10px;
+      }
+      .free-open-tip .down-more-text{
+        color: #2ABDD1;
+        font-size: .22rem;
+        padding: 0 .08rem 0 .16rem;
+      }
+      .free-open-tip .open-vip-btn{
+        height: 100%;
+        background-color: #2ABDD1;
+        border-radius: 10px;
+        color: #fff;
+        padding: 0 .22rem;
+        font-size: .22rem;
+        line-height: .4rem;
+      }
       #h_content table{
         /* border: 1px solid #EBEBEB; */
         border-collapse: collapse!important;
         border-spacing: 0px !important;
+        text-align: center;
       }
       #h_content table tr td,.h_content table th{
         border: 1px solid #EBEBEB;
@@ -1094,7 +1117,11 @@ em {
                             <span class="file-count-tip">本月剩余:<em class="file-count"></em>个</span>
                             <span class="icon-help"></span>
                             <span class="concat-kf">联系客服</span>
-                            <span class="go-buy-file-pack" style="display: none">立即充值</span>
+							<span class="go-buy-file-pack" style="display: none">立即充值</span>
+                            <span class="free-open-tip" style="display: none;">
+                              <span class="down-more-text">下载更多附件</span>
+                              <span class="open-vip-btn">开通超级订阅</span>
+                            </span>
                         </div>
                     </a>
                 </div>
@@ -1635,7 +1662,7 @@ isOpening()
 function isOpening() {
 	$.ajax({
 			type:'GET',
-			url:'/bigmember/use/isAdd',
+			url:'/bigmember/use/isAdd?t=' + Date.now(),
 			success: function(res) {
 					//console.log(res)
           bigstatus = res.data.memberStatus
@@ -1675,8 +1702,17 @@ function isOpening() {
             $('#analysis-in').hide()
           }
           // 免费用户展示可下载一次提示(免费用户且没有体验过附件下载权益的展示)
-          if (res.data && res.data.isFree && res.data.freeFile == 0) {
-            $('.free-down-text').css('display', 'inline-block')
+          if (res.data && res.data.isFree) {
+            if (res.data.freeFile == 0) {
+              $('.free-down-text').css('display', 'inline-block')
+            } else {
+              // 留过资 体验过的 提示开通超级订阅
+              $('.free-down-text').hide()
+              $('.free-open-tip').css('display', 'flex')
+              $('.free-open-tip .open-vip-btn').click(function(){
+                location.href= '/front/vipsubscribe/vipsubscribe_new'
+              })
+            }
           }
           //非大会员或大会员无此功能 且是新超级订阅用户
           if (res.data && res.data.vipStatus > 0 && res.data.viper&&!window.isMemberAndPower) {
@@ -1883,7 +1919,8 @@ function andownload() {
                       }
                     }
                     // 是大会员自定义版本没有下载权限 或 非超级订阅的商机管理用户 (弹框提醒联系客服)
-                    if (window.isNoMember == true || (window.vipStatus <=0 && window.entniche)) {
+                    var memberNoVip = window.isNoMember == true && !(window.vipStatus >0 && window.viper)
+                    if (memberNoVip || (window.vipStatus <=0 && window.entniche)) {
                       vant.Dialog.alert({
                         message: '您未购买此服务,如需使用请联系您的客户经理或客服升级套餐,谢谢!',
                         className: 'custom-dialog',
@@ -1946,17 +1983,17 @@ function gotoFilePage(name){
 // 大会员文案点击
 $('.bigvip_drain').on('click', function() {
 	let powerInt = []
-	if(!drainPower.entniche && !drainPower.member && drainPower.vip <= 0) {
+	if(window.isFree) {
 			// 免费用户
 			powerInt.push(0)
 	}
-	if(drainPower.member) {
+	if(window.isNoMember||window.isMemberAndPower) {
 			powerInt.push(0)
 	}
-	if(drainPower.vip > 0) {
+	if(window.vipStatus > 0) {
 			powerInt.push(1)
 	}
-	if(drainPower.entniche) {
+	if(window.entniche) {
 			powerInt.push(3)
 	}
 	console.log(powerInt)
@@ -2070,7 +2107,17 @@ function subData(){
 }
 //
 $(function(){
-
+  var u = navigator.userAgent;
+  var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
+  var isPageHide = false;
+  window.addEventListener('pageshow', function () {
+      if (isPageHide && isiOS) {
+      window.location.reload();
+      }
+  });
+  window.addEventListener('pagehide', function () {
+      isPageHide = true;
+  });
 	$(document).on("click",function(e) {
         if($(e.target).parents(".easyalert-mask").length == 0){
             $("#easyalert-mask").remove();

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio