WH01243 2 年之前
父节点
当前提交
b4e91ed555
共有 100 个文件被更改,包括 11137 次插入1709 次删除
  1. 185 182
      src/config.json
  2. 1 0
      src/config.yaml
  3. 63 70
      src/db.json
  4. 4 5
      src/go.mod
  5. 8 10
      src/go.sum
  6. 96 16
      src/jfw/front/datasmt.go
  7. 136 11
      src/jfw/front/shorturl.go
  8. 4 4
      src/jfw/front/tags.go
  9. 119 1
      src/jfw/modules/app/src/app/front/shorturl.go
  10. 2 1
      src/jfw/modules/app/src/config.yaml
  11. 60 56
      src/jfw/modules/app/src/db.json
  12. 44 51
      src/jfw/modules/app/src/go.mod
  13. 497 86
      src/jfw/modules/app/src/go.sum
  14. 207 33
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/css/analysis_result.css
  15. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/bid_bg.png
  16. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/itemA_05.jpg
  17. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB1.png
  18. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB2.png
  19. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB3.png
  20. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB4.png
  21. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB5.png
  22. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB6.png
  23. 258 0
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/analysis_pro_list.js
  24. 609 240
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/analysis_result.js
  25. 6 6
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/chart_options.js
  26. 13 13
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/contrast_trial.js
  27. 1 1
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/main_root_data.js
  28. 1 1
      src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/mock.js
  29. 239 0
      src/jfw/modules/app/src/web/staticres/jyapp/dataSmt/css/index.css
  30. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/dataSmt/images/data-market-text.png
  31. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/dataSmt/images/header-banner.png
  32. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/dataSmt/images/icon-1.png
  33. 102 0
      src/jfw/modules/app/src/web/staticres/jyapp/dataSmt/js/index.js
  34. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/wxswordfish/images/share-icon.png
  35. 二进制
      src/jfw/modules/app/src/web/staticres/jyapp/wxswordfish/images/share-page.png
  36. 35 2
      src/jfw/modules/app/src/web/templates/big-member/page_ai_add.html
  37. 1 1
      src/jfw/modules/app/src/web/templates/big-member/page_analysis_filter.html
  38. 299 223
      src/jfw/modules/app/src/web/templates/big-member/page_analysis_result.html
  39. 103 0
      src/jfw/modules/app/src/web/templates/big-member/page_bid_analysis_pro_list.html
  40. 0 0
      src/jfw/modules/app/src/web/templates/big-member/page_contrast.html
  41. 1 1
      src/jfw/modules/app/src/web/templates/big-member/page_landingPage.html
  42. 1 1
      src/jfw/modules/app/src/web/templates/big-member/page_landingPage_old.html
  43. 6 6
      src/jfw/modules/app/src/web/templates/big-member/page_landingPage_old_1.html
  44. 1 1
      src/jfw/modules/app/src/web/templates/big-member/page_ontrial_landingPage.html
  45. 2 2
      src/jfw/modules/app/src/web/templates/big-member/page_pro_follow_detail.html
  46. 178 1
      src/jfw/modules/app/src/web/templates/dataSmt/index.html
  47. 22 2
      src/jfw/modules/app/src/web/templates/dataSmt/list.html
  48. 4 4
      src/jfw/modules/app/src/web/templates/weixin/wxinfocontent.html
  49. 1 0
      src/jfw/modules/bigmember/src/config.json
  50. 264 77
      src/jfw/modules/bigmember/src/entity/analysis.go
  51. 112 55
      src/jfw/modules/bigmember/src/entity/analysisEntName.go
  52. 1 1
      src/jfw/modules/bigmember/src/go.mod
  53. 77 41
      src/jfw/modules/bigmember/src/service/analysis/analysis.go
  54. 387 213
      src/jfw/modules/bigmember/src/service/analysis/decision.go
  55. 691 179
      src/jfw/modules/bigmember/src/service/analysis/esquery.go
  56. 2 0
      src/jfw/modules/bigmember/src/service/analysis/power.go
  57. 9 11
      src/jfw/modules/bigmember/src/service/analysis/util.go
  58. 91 0
      src/jfw/modules/bigmember/src/util/util.go
  59. 15 0
      src/jfw/modules/distribution/.idea/git_toolbox_prj.xml
  60. 26 10
      src/jfw/modules/publicapply/src/db.json
  61. 2 2
      src/jfw/modules/subscribepay/src/config.yaml
  62. 5 5
      src/jfw/modules/subscribepay/src/service/orderListDetails.go
  63. 二进制
      src/jfw/modules/subscribepay/src/web/staticres/res/dataexport/20201130152650_250672091720_bjINh.xlsx
  64. 二进制
      src/jfw/modules/subscribepay/src/web/staticres/res/dataexport/20201130153115_250672151862_QBYIm.xlsx
  65. 3 3
      src/jfw/modules/wxtoken/src/config.json
  66. 4 4
      src/jfw/modules/wxtoken/src/main.go
  67. 二进制
      src/web/staticres/big-member/image/landpage_new/itemA_05.jpg
  68. 二进制
      src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB1.png
  69. 二进制
      src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB2.png
  70. 二进制
      src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB3.png
  71. 二进制
      src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB4.png
  72. 二进制
      src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB5.png
  73. 二进制
      src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB6.png
  74. 5 5
      src/web/staticres/big-member/js/chart_options.js
  75. 13 13
      src/web/staticres/big-member/js/contrast_trial.js
  76. 13 13
      src/web/staticres/big-member/js/meauContact.js
  77. 26 26
      src/web/staticres/big-member/js/previewTable.js
  78. 209 0
      src/web/staticres/common-module/analysis-filter/css/analysis-filter.css
  79. 二进制
      src/web/staticres/common-module/analysis-filter/image/icon_close.png
  80. 二进制
      src/web/staticres/common-module/analysis-filter/image/right.png
  81. 482 0
      src/web/staticres/common-module/analysis-filter/js/analysis-filter.js
  82. 5 5
      src/web/staticres/common-module/collection/js/chart_options.js
  83. 二进制
      src/web/staticres/common-module/pc-dialog/image/data-supermarket-buy.png
  84. 二进制
      src/web/staticres/common-module/pc-dialog/image/data-supermarket-contact.png
  85. 72 12
      src/web/staticres/common-module/pc-dialog/js/leave-info-dialog.js
  86. 3 3
      src/web/staticres/common-module/perfect-info/js/perfect-info.js
  87. 109 0
      src/web/staticres/common-module/public/js/china-province-data.js
  88. 456 0
      src/web/staticres/common-module/viewer/viewer.css
  89. 3597 0
      src/web/staticres/common-module/viewer/viewer.js
  90. 458 0
      src/web/staticres/css/dataSmt/dataMart.css
  91. 242 0
      src/web/staticres/css/dataSmt/dataMart_detail.css
  92. 449 0
      src/web/staticres/dataSmt/css/index.css
  93. 二进制
      src/web/staticres/dataSmt/images/case-ccscc.png
  94. 二进制
      src/web/staticres/dataSmt/images/case-cec.png
  95. 二进制
      src/web/staticres/dataSmt/images/case-langchao.png
  96. 二进制
      src/web/staticres/dataSmt/images/case-liantong.png
  97. 二进制
      src/web/staticres/dataSmt/images/case-minsheng.png
  98. 二进制
      src/web/staticres/dataSmt/images/case-ruijie.png
  99. 二进制
      src/web/staticres/dataSmt/images/case-siemens.png
  100. 二进制
      src/web/staticres/dataSmt/images/case-soft.png

文件差异内容过多而无法显示
+ 185 - 182
src/config.json


+ 1 - 0
src/config.yaml

@@ -6,3 +6,4 @@ powerCheckCenterKey: "powercheck.rpc" #权益校验中台
 resourceCenterKey: "resource.rpc" #资源中台
 entManageApplication: "entmanageapplication.rpc" #企业管理中台
 activityKey: "activity.rpc" #营销中台rpc
+publicserviceKey: "publicservice.rpc"

+ 63 - 70
src/db.json

@@ -1,75 +1,68 @@
 {
-	"mongodb": {
-		"main": {
-			"address": "192.168.3.206:27080",
-	 		"size": 5,
-	 		"dbName": "qfw",
-			"replSet": ""
-		},
-		"log": {
-			"address": "192.168.3.206:27090",
-	 		"size": 5,
-	 		"dbName": "qfw",
-			"replSet": "",
-			"userName": "admin",
-			"password": "123456"
-		},
-		"ent": {
-			"address": "192.168.3.206:27002",
-	 		"size": 5,
-	 		"dbName": "mixdata",
-			"userName": "jyDevGroup",
-			"password": "jy@DevGroup"
-		},
-		"qyfw": {
-			"address": "192.168.3.206:27080",
-	 		"size": 5,
-	 		"dbName": "jyqyfw"
-		},
-		"bidding": {
-			"address": "192.168.3.206:27002",
-	 		"size": 5,
-	 		"dbName": "qfw_data",
-			"replSet": "",
-			"collection": "bidding",
-			"collection_back": "bidding_back",
-			"userName": "jyDevGroup",
-			"password": "jy@DevGroup"
-		}
-	},
-	"elasticsearch": {
-		"main": {
-			"address": "http://192.168.3.241:9205,http://192.168.3.149:9200",
-	    	"size": 5,
-			"version": "v7",
-			"userName": "",
-			"password": ""
-		}
+  "mongodb": {
+    "main": {
+      "address": "192.168.3.206:27080",
+      "size": 10,
+      "dbName": "qfw"
     },
-    "redis": {
-    	"main":{
-			"address": "other=192.168.3.149:1712,push=192.168.3.149:1712,sso=192.168.3.149:1712,session=192.168.3.11:1713,recovery=192.168.3.149:1712,merge=192.168.3.149:1712,newother=192.168.3.149:1712,poly=192.168.3.149:1713"
-		},
-		"login": {
-			"address": "login=192.168.3.149:1713"
-		}
+    "log": {
+      "address": "192.168.3.206:27090",
+      "size": 5,
+      "dbName": "qfw",
+      "userName": "admin",
+      "password": "123456"
     },
-    "mysql": {
-	    "main": {
-	        "dbName": "jianyu",
-	        "address": "192.168.3.11:3366",
-	        "userName": "root",
-	        "passWord": "Topnet123",
-			"maxOpenConns": 5,
-			"maxIdleConns": 5
-	    },
-		"base": {
-	        "dbName": "base_service",
-	        "address": "192.168.3.217:4000",
-	        "userName": "root",
-	        "passWord": "=PDT49#80Z!RVv52_z",
-			"maxOpenConns": 5,
-			"maxIdleConns": 5
-	    }
+    "ent": {
+      "address": "192.168.3.206:27002",
+      "size": 5,
+      "dbName": "mixdata",
+      "userName": "jyDevGroup",
+      "password": "jy@DevGroup"
+    },
+    "bidding": {
+      "address": "192.168.3.206:27002",
+      "size": 5,
+      "dbName": "qfw_data",
+      "replSet": "",
+      "collection": "bidding",
+      "collection_back": "bidding_back",
+      "userName": "jyDevGroup",
+      "password": "jy@DevGroup"
+    }
+  },
+  "elasticsearch": {
+    "main": {
+      "address": "http://192.168.3.241:9205,http://192.168.3.149:9200",
+      "size": 30,
+      "version": "v7",
+      "userName":"",
+      "password":""
+    }
+  },
+  "redis": {
+    "main":{
+      "address": "other=192.168.3.149:1712,sso=192.168.3.149:1713,push=192.168.3.149:1711,session=192.168.3.149:1713,recovery=192.168.3.149:1715,merge=192.168.3.206:2711,newother=192.168.3.149:1712,poly=192.168.3.149:1713"
+    },
+    "login": {
+      "address": "login=192.168.3.149:1712"
+    }
+  },
+  "mysql": {
+    "main": {
+      "dbName": "jianyu",
+      "address": "192.168.3.149:3306",
+      "userName": "root",
+      "passWord": "Topnet123",
+      "maxOpenConns": 10,
+      "maxIdleConns": 5
+    },
+    "base": {
+      "dBName": "base_service",
+      "address" : "192.168.3.14:4000",
+      "userName": "root",
+      "passWord": "=PDT49#80Z!RVv52_z",
+      "maxOpenConns": 5,
+      "maxIdleConns": 5
     }
+  }
 }

+ 4 - 5
src/go.mod

@@ -6,7 +6,7 @@ require (
 	app.yhyue.com/moapp/jyMarketing v0.0.2-0.20230308011651-df591d32df88
 	app.yhyue.com/moapp/jybase v0.0.0-20230614085041-f8f20842d5cb
 	app.yhyue.com/moapp/jylog v0.0.0-20230522075550-05d7230ca545
-	app.yhyue.com/moapp/jypkg v0.0.0-20230627072535-2f1a67f51167
+	app.yhyue.com/moapp/jypkg v0.0.0-20230621114846-e9533ffc8ba0
 	bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.13
 	github.com/SKatiyar/qr v0.0.0-20151201054752-25b6bdf44e67
 	github.com/fsnotify/fsnotify v1.6.0
@@ -117,15 +117,15 @@ require (
 	go.uber.org/zap v1.24.0 // indirect
 	golang.org/x/crypto v0.6.0 // indirect
 	golang.org/x/net v0.10.0 // indirect
-	golang.org/x/oauth2 v0.7.0 // indirect
+	golang.org/x/oauth2 v0.6.0 // indirect
 	golang.org/x/sync v0.1.0 // indirect
 	golang.org/x/sys v0.8.0 // indirect
 	golang.org/x/term v0.8.0 // indirect
 	golang.org/x/text v0.9.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
-	google.golang.org/grpc v1.56.1 // indirect
+	google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
+	google.golang.org/grpc v1.55.0 // indirect
 	google.golang.org/protobuf v1.30.0 // indirect
 	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
@@ -135,7 +135,6 @@ require (
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	gorm.io/driver/mysql v1.0.5 // indirect
 	gorm.io/gorm v1.21.3 // indirect
-	jygit.jydev.jianyu360.cn/ApplicationCenter/publicService v0.0.0-20230626055559-2b719f6c6602 // indirect
 	k8s.io/api v0.26.3 // indirect
 	k8s.io/apimachinery v0.27.0-alpha.3 // indirect
 	k8s.io/client-go v0.26.3 // indirect

+ 8 - 10
src/go.sum

@@ -9,8 +9,8 @@ app.yhyue.com/moapp/jybase v0.0.0-20230614085041-f8f20842d5cb h1:fT7FIKElKjkRHTm
 app.yhyue.com/moapp/jybase v0.0.0-20230614085041-f8f20842d5cb/go.mod h1:D40Ae0rQilH8Hc5o2Vtt04Tjh/DNEFpcS3/WkJMPJb8=
 app.yhyue.com/moapp/jylog v0.0.0-20230522075550-05d7230ca545 h1:+Lak4m1zgsigQloOsvp8AJ+0XeX/+PGp9QP550xlbBQ=
 app.yhyue.com/moapp/jylog v0.0.0-20230522075550-05d7230ca545/go.mod h1:uFrsdUBFbETiJlEmr4PtJWPsZlUpPj2bHQRhryu6ggk=
-app.yhyue.com/moapp/jypkg v0.0.0-20230627072535-2f1a67f51167 h1:WO3F0w/jqPj5fS30rmzCvmN3F/aLmtx51Pfcps6y7+E=
-app.yhyue.com/moapp/jypkg v0.0.0-20230627072535-2f1a67f51167/go.mod h1:JBkMSnaOQbfV80laTPwjzjfP6nLXOQpJBaNUdvKV2tw=
+app.yhyue.com/moapp/jypkg v0.0.0-20230621114846-e9533ffc8ba0 h1:sKWgJriRTdxEuNkzAooMAjs+2bPu1mq9Q493aMA98oI=
+app.yhyue.com/moapp/jypkg v0.0.0-20230621114846-e9533ffc8ba0/go.mod h1:Ize93SJEPkBR0Tz8PM2KTJK3bpzlD/qp1JwJ4kdmlss=
 app.yhyue.com/moapp/message v0.0.0-20221223100203-6402e389d9ae h1:6rDDaz6yxvE8viTSzEBwKYOFWq14TMfuBivSazUZMz4=
 app.yhyue.com/moapp/message v0.0.0-20221223100203-6402e389d9ae/go.mod h1:b0zZHev3gmJao1Fo+2Z2KPVjsuLOJVvVxf+kCnu9WkA=
 bp.jydev.jianyu360.cn/BaseService/entManageApplication v0.0.0-20230214091519-89a98c01ab0e h1:h+VEI3o1qC0jeCzkFGTrLI4f27cfa/W/y+0sXokWMgE=
@@ -1043,8 +1043,8 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ
 golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
-golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
+golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
+golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1312,8 +1312,8 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH
 google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20220228195345-15d65a4533f7/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
 google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
-google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
-google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
+google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
+google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@@ -1342,8 +1342,8 @@ google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5
 google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
 google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
 google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ=
-google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
+google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
+google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1420,8 +1420,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-jygit.jydev.jianyu360.cn/ApplicationCenter/publicService v0.0.0-20230626055559-2b719f6c6602 h1:lZ0XCzRDSOBaoJczQudZ3KZhRs4zm5sjboDpwuYZUVM=
-jygit.jydev.jianyu360.cn/ApplicationCenter/publicService v0.0.0-20230626055559-2b719f6c6602/go.mod h1:Jjhym3U0MFdSgeafHPm758NefCPZpekg2sWPh6Gy6Jk=
 k8s.io/api v0.22.9/go.mod h1:rcjO/FPOuvc3x7nQWx29UcDrFJMx82RxDob71ntNH4A=
 k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU=
 k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE=

+ 96 - 16
src/jfw/front/datasmt.go

@@ -1,11 +1,58 @@
 package front
 
 import (
+	"app.yhyue.com/moapp/jybase/common"
 	"app.yhyue.com/moapp/jybase/go-xweb/xweb"
 	"app.yhyue.com/moapp/jypkg/public"
+	"fmt"
 	"jy/src/jfw/config"
+	"jy/src/jfw/paging"
+	"strings"
 )
 
+var TDKMap = map[string]map[string]string{
+	"采购意向": map[string]string{
+		"title":       "采购意向_数据超市-剑鱼标讯",
+		"keyWord":     "数据超市,采购意向数据,政府采购意向,剑鱼标讯",
+		"description": "剑鱼标讯数据超市提供不同行业领域的政府采购意向数据批量下载服务,成品数据安全合规,助力企业高效挖掘商机。",
+	},
+	"拟建项目": map[string]string{
+		"title":       "拟建项目_数据超市-剑鱼标讯",
+		"keyWord":     "数据超市,拟建项目数据,拟在建项目数据,剑鱼标讯",
+		"description": "剑鱼标讯数据超市提供不同行业领域的拟建项目数据批量下载服务,成品数据安全合规,助力企业高效挖掘商机。",
+	},
+	"招标数据": map[string]string{
+		"title":       "招标采购数据超市-剑鱼标讯",
+		"keyWord":     "数据超市,招标数据,招标采购数据,剑鱼标讯",
+		"description": "剑鱼标讯数据超市提供全国不同行业领域的招标、采购数据批量下载服务,成品数据安全合规,海量招投标大数据助力企业进行统计、分析和决策服务。",
+	},
+	"中标数据": map[string]string{
+		"title":       "招标中标数据超市-剑鱼标讯",
+		"keyWord":     "数据超市,中标数据,中标成交数据,剑鱼标讯",
+		"description": "剑鱼标讯数据超市提供全国不同行业领域的中标、成交数据批量下载服务,成品数据安全合规,对企业做好市场行情监测、销售策略制定、中标单位或竞争对手等相关数据的分析,提供有力支持。",
+	},
+	"中标单位数据": map[string]string{
+		"title":       "中标单位数据超市-剑鱼标讯",
+		"keyWord":     "中标单位信息,中标单位数据,中标企业数据,剑鱼标讯",
+		"description": "剑鱼标讯数据超市提供全国中标单位、中标企业数据批量下载服务,数据类型覆盖中标单位企业工商信息、招标信息通讯录、中标项目规模及数量、业务覆盖区域、客户群体等多个字段,助力您全面了解中标单位详情。",
+	},
+	"采购单位数据": map[string]string{
+		"title":       "采购单位数据超市-剑鱼标讯",
+		"keyWord":     "采购单位信息,采购单位数据,采购商数据,业主采购数据,剑鱼标讯",
+		"description": "剑鱼标讯数据超市提供全国企业采购单位、业主数据批量下载服务,数据类型覆盖采购单位机构工商信息、招标信息通讯录、招标采购项目规模及数量、TOP5中标单位信息等多个字段,助力您全面了解采购单位详情。",
+	},
+	"企业工商数据": map[string]string{
+		"title":       "企业工商数据超市-剑鱼标讯",
+		"keyWord":     "工商数据,企业工商数据包,工商数据库,剑鱼标讯",
+		"description": "剑鱼标讯数据超市提供全国企业工商数据批量下载服务,基于精准的全国企业信息公司名录库,辅助您进行销售线索挖掘、商机触达、客户管理等全链路销售服务。",
+	},
+}
+var searchTDKMap = map[string]string{
+	"title":       "%s相关搜索结果_%s数据超市 - 剑鱼标讯",
+	"keyWord":     "%s,%s%s,%s招投标数据,%s招标采购数据,剑鱼标讯",
+	"description": "剑鱼标讯数据超市提供%s相关搜索结果,在这里您可以查询%s相关的%s信息,并支持数据批量下载服务,了解更多%s相关招投标数据服务就上剑鱼标讯官网!",
+}
+
 type Datasmt struct {
 	*xweb.Action
 	index  xweb.Mapper `xweb:"/datasmt"`            //落地页
@@ -18,30 +65,53 @@ func init() {
 }
 
 func (this *Datasmt) Index() error {
-	data := config.Middleground.Publicservice.List("", "", 0, 8)
-	if data == nil {
-		return this.Render("/_err.html")
-	}
-	this.T["list"] = data.List
+	data := config.Middleground.Publicservice.List("", "", 1, 8)
+	this.T["list"] = data["list"]
 	if mobileReg.MatchString(this.UserAgent()) || public.CheckWxBrowser(this.Request) {
-		return this.Render("/weixin/dataSmt/index.html")
+		return this.Render("")
 	} else {
 		return this.Render("/pc/dataSmt/index.html")
 	}
 }
 
-func (this *Datasmt) List(dataType string) error {
-
+func (this *Datasmt) List(query string) error {
+	queryArr := strings.Split(query, "_")
+	dataType := queryArr[0]
+	pageNum := common.Int64All(queryArr[1])
+	pageSize := int64(40)
+	searchValue := this.GetString("searchValue")
 	this.T["dataType"] = dataType
 	data := config.Middleground.Publicservice.List(searchValue, dataType, pageNum, pageSize)
-	if data == nil {
-		return this.Render("/_err.html")
+	if common.IntAll(data["PageCount"]) > 0 {
+		this.T["pagingMap"] = paging.GetLetterPaging(common.IntAll(pageNum), common.IntAll(pageSize), common.IntAll(data["PageCount"]), fmt.Sprintf("/datasmt/%s?searchValue=%s", fmt.Sprintf("%s_%v", dataType, "%v"), searchValue))
+	}
+	//数据清洗
+	this.T["list"] = data["list"]
+	this.T["hotKeys"] = data["hotKeys"]
+	this.T["fieldIllustrate"] = data["fieldIllustrate"]
+	this.T["searchValue"] = data["searchValue"]
+	this.T["dataTypeStr"] = data["dataTypeStr"]
+	title := ""
+	keywords := ""
+	description := ""
+	if dataType == "" && searchValue == "" {
+		title = TDKMap["其他"]["title"]
+		keywords = TDKMap["其他"]["keyWord"]
+		description = TDKMap["其他"]["description"]
+	} else if searchValue == "" {
+		title = TDKMap[common.InterfaceToStr(data["dataTypeStr"])]["title"]
+		keywords = TDKMap[common.InterfaceToStr(data["dataTypeStr"])]["keyWord"]
+		description = TDKMap[common.InterfaceToStr(data["dataTypeStr"])]["description"]
+	} else {
+		title = fmt.Sprintf(searchTDKMap["title"], searchValue, common.InterfaceToStr(data["dataTypeStr"]))
+		keywords = fmt.Sprintf(searchTDKMap["keyWord"], searchValue, searchValue, common.InterfaceToStr(data["dataTypeStr"]), searchValue, searchValue)
+		description = fmt.Sprintf(searchTDKMap["description"], searchValue, searchValue, common.InterfaceToStr(data["dataTypeStr"]), searchValue)
 	}
-	this.T["list"] = data.List
-	this.T["hotKeys"] = data.HotKeys
-	this.T["fieldIllustrate"] = data.FieldIllustrate
+	this.T["title"] = title
+	this.T["keywords"] = keywords
+	this.T["description"] = description
 	if mobileReg.MatchString(this.UserAgent()) || public.CheckWxBrowser(this.Request) {
-		return this.Render("/weixin/dataSmt/list.html")
+		return this.Render("")
 	} else {
 		return this.Render("/pc/dataSmt/list.html")
 	}
@@ -49,9 +119,19 @@ func (this *Datasmt) List(dataType string) error {
 
 func (this *Datasmt) Detail(dataType, id string) error {
 	this.T["dataType"] = dataType
-	this.T["id"] = id
+	data := config.Middleground.Publicservice.Detail(id)
+	this.T["data"] = data
+	//标题处理
+	title := fmt.Sprintf("%s- 剑鱼标讯", data["name"])
+	//关键词处理
+	keywords := fmt.Sprintf("%s%s,%s招投标数据,%s招标采购数据,%s,剑鱼标讯", data["keyword"], data["dataType"], data["keyword"], data["keyword"], data["dataType"])
+	//描述处理
+	description := fmt.Sprintf("%s%s", data["name"], data["describe"])
+	this.T["title"] = title
+	this.T["keywords"] = keywords
+	this.T["description"] = description
 	if mobileReg.MatchString(this.UserAgent()) || public.CheckWxBrowser(this.Request) {
-		return this.Render("/weixin/dataSmt/detail.html")
+		return this.Render("")
 	} else {
 		return this.Render("/pc/dataSmt/detail.html")
 	}

+ 136 - 11
src/jfw/front/shorturl.go

@@ -4,6 +4,7 @@ import (
 	"database/sql"
 	"errors"
 	"fmt"
+	"github.com/gogf/gf/v2/util/gconv"
 	"jy/src/jfw/config"
 	"jy/src/jfw/wx"
 	"log"
@@ -55,6 +56,30 @@ var Map_stype = map[string]bool{
 	"advancedProject": true,
 }
 
+var TypeCodeMap = map[string]string{
+	"拟建":   "拟建项目",
+	"采购意向": "采购意向",
+	"预告":   "招标预告",
+	"预审":   "资格预审",
+	"预审结果": "资格预审结果",
+	"论证意见": "论证意见",
+	"需求公示": "需求公示",
+	"招标":   "公开招标",
+	"邀标":   "邀请招标",
+	"询价":   "询价采购",
+	"竞谈":   "竞争性谈判",
+	"单一":   "单一来源采购",
+	"竞价":   "竞价公告",
+	"变更":   "变更公告",
+	"中标":   "中标公示",
+	"成交":   "成交公告",
+	"废标":   "废标公告",
+	"流标":   "流标公告",
+	"合同":   "合同公告信息",
+	"验收":   "验收公告信息",
+	"违规":   "违规信息",
+}
+
 var seoAgentReg = regexp.MustCompile("Baiduspider|360Spider|bingbot|Googlebot")
 
 func (s *Short) Article(stype, id string) error {
@@ -150,6 +175,8 @@ func (s *Short) LoginCommon(userId, stype, id string) error {
 						retMap["subtype"], _ = obj["subtype"].(string)
 						retMap["subscopeclass"], _ = obj["s_subscopeclass"].(string)
 						retMap["publishtime"] = util.IntAll(obj["publishtime"])
+						retMap["keywords"] = KeyWordHandle(obj)
+						retMap["description"] = DescriptionHandle(stype, obj)
 					}
 					s.T["shareid"] = config.Seoconfig["baiduSEM-p"].(string)
 					s.T["logid"] = config.Seoconfig["baiduSEM-p"].(string)
@@ -184,7 +211,6 @@ func (s *Short) LoginCommon(userId, stype, id string) error {
 			ssOpenid := s.Session().Get("s_m_openid")
 			po, bo, wo, obj := pcVRT(sid, industry, stype, true)
 			if obj != nil && len(obj) > 0 {
-
 				if len(po) > 0 {
 					s.T["projectOther"] = po
 				}
@@ -231,11 +257,11 @@ func (s *Short) LoginCommon(userId, stype, id string) error {
 					obj["publishtimeShorDate"] = time.Unix(util.Int64All(obj["publishtime"]), 0).Format(date.Date_Short_Layout)
 				}
 				s.T["url"] = s.Uri()
+				obj["keywords"] = KeyWordHandle(obj)
+				obj["description"] = DescriptionHandle(stype, obj)
 				s.T["obj"] = obj
-
 				content, _ := s.Render4Cache("/pc/biddetail_rec.html", &s.T)
-				timeout := 60 * 20
-				redis.Put("newother", catchKey, string(content), timeout)
+				redis.Put("newother", catchKey, string(content), 60*20)
 				return s.SetBody(content)
 			}
 		} else {
@@ -334,7 +360,7 @@ func (s *Short) LoginCommon(userId, stype, id string) error {
 		canRead := false
 		if ((isVip && isOldVip) || isMember || isEntniche) || //老版本vip、大会员、商机管理
 			((isVip && !isOldVip) && (!(util.ObjToString(obj["subtype"]) == "拟建" || util.ObjToString(obj["subtype"]) == "采购意向"))) || //新超级订阅非采购意向”和“拟建项目”
-			stype == "mailprivate" || stype == "indexcontent" { //邮箱推送
+			stype == "mailprivate" || stype == "indexcontent" || stype == "bdprivate" { //邮箱推送
 			canRead = true
 		} else {
 			canRead = SeeDetailLimit(obj, userId, sid)
@@ -418,6 +444,8 @@ func (s *Short) LoginCommon(userId, stype, id string) error {
 			s.T["advertUrl"] = config.Sysconfig["advertUrl"]
 			s.T["canRead"] = canRead
 			obj["industry"] = industry
+			obj["keywords"] = KeyWordHandle(obj)
+			obj["description"] = DescriptionHandle(stype, obj)
 			s.T["obj"] = obj
 			//获取打赏文案
 			s.T["rewardText"], s.T["advertText"] = getRewardText()
@@ -453,7 +481,7 @@ func (s *Short) LoginCommon(userId, stype, id string) error {
 			var node bool
 			if ((isVip && isOldVip) || isMember || isEntniche) || //老版本vip、大会员、商机管理
 				((isVip && !isOldVip) && (!(util.ObjToString(obj["subtype"]) == "拟建" || util.ObjToString(obj["subtype"]) == "采购意向"))) || //新超级订阅非采购意向”和“拟建项目”
-				stype == "mailprivate" || stype == "indexcontent" { //邮箱推送
+				stype == "mailprivate" || stype == "indexcontent" || stype == "bdprivate" { //邮箱推送
 				node = true
 			} else {
 				_, _, _, objc := pcVRT(sid, indust, stype, isVip || isMember || isEntniche)
@@ -560,7 +588,8 @@ func (s *Short) LoginCommon(userId, stype, id string) error {
 			if ssOpenid != nil {
 				obj["ucbsId"] = encrypt.EncodeArticleId2ByCheck("ucbs#" + ssOpenid.(string) + "#" + id)
 			}
-
+			obj["keywords"] = KeyWordHandle(obj)
+			obj["description"] = DescriptionHandle(stype, obj)
 			s.T["obj"] = obj
 			s.T["url"] = s.Uri()
 			return s.Render("/pc/biddetail_rec.html", &s.T)
@@ -1008,7 +1037,8 @@ func (s *Short) NologinCommon(userId, stype, id, sid string) error {
 		}
 		s.T["logid"] = config.Seoconfig["jysskzy"].(string)
 		s.T["shareid"] = se.EncodeString(shareid)
-		s.T["keywords"] = s.GetString("kds")
+		//s.T["keywords"] = s.GetString("kds")
+
 		s.DisableHttpCache()
 		po, bo, wo, obj := pcVRT(sid, industry, stype, false || false || false)
 		if obj != nil && len(obj) > 0 {
@@ -1024,6 +1054,7 @@ func (s *Short) NologinCommon(userId, stype, id, sid string) error {
 			FieldProcessing(obj, "", industry, id, "", userId, stype, false)
 			obj["urlpath"] = s.Uri()
 			obj["industry"] = industry
+
 			if userId == "" {
 				obj["winnerTitle"] = obj["winner"]
 				obj["buyerTitle"] = obj["buyer"]
@@ -1031,19 +1062,20 @@ func (s *Short) NologinCommon(userId, stype, id, sid string) error {
 				obj["projectcodeTitle"] = obj["projectcode"]
 				log.Println(time.Now().UnixNano())
 				obj = Filter(obj)
-				obj["description"] = fmt.Sprintf("%s,%s。", obj["title"], baseInfo(obj))
+				//obj["description"] = fmt.Sprintf("%s,%s。", obj["title"], baseInfo(obj))
 			}
 			if obj["publishtime"] != nil {
 				obj["publishtimeShorDate"] = time.Unix(util.Int64All(obj["publishtime"]), 0).Format(date.Date_Short_Layout)
 			}
+			obj["keywords"] = KeyWordHandle(obj)
+			obj["description"] = DescriptionHandle("nologin", obj)
 			s.T["obj"] = obj
 			s.T["url"] = s.Uri()
 			s.T["newBidInfoList"] = tg.GetNewBidInfo()
 			s.T["industryInfoList"] = tg.GetConsult()
 			s.T["hotLabelList"] = tg.GetHotLabel(30)
 			content, _ := s.Render4Cache("/pc/tags/detail.html", &s.T)
-			timeout := 60 * 60 * 24
-			redis.Put("newother", catchKey, string(content), timeout)
+			redis.Put("newother", catchKey, string(content), 60*2)
 			return s.SetBody(content)
 		}
 	} else {
@@ -1121,3 +1153,96 @@ func RegDetail(html string) string {
 	}
 	return ""
 }
+
+func KeyWordHandle(obj map[string]interface{}) string {
+	keywordArr := []string{}
+	owner := util.InterfaceToStr(obj["owner"])
+	buyer := util.InterfaceToStr(obj["buyer"])
+	if buyer == "" {
+		buyer = owner
+	}
+	if buyer != "" && buyer != config.Sysconfig["detailMosaicTxt"] {
+		keywordArr = append(keywordArr, buyer)
+	}
+	if util.InterfaceToStr(obj["s_winner"]) != "" && util.InterfaceToStr(obj["s_winner"]) != config.Sysconfig["detailMosaicTxt"] {
+		keywordArr = append(keywordArr, util.InterfaceToStr(obj["s_winner"]))
+	}
+	if obj["purchasinglist"] != nil && obj["purchasinglist"] != "" {
+		i := 0
+		for _, v := range gconv.SliceMap(obj["purchasinglist"]) {
+			if i == 5 {
+				break
+			}
+			if util.InterfaceToStr(v["itemname"]) != "" && util.InterfaceToStr(obj["s_winner"]) != config.Sysconfig["detailMosaicTxt"] {
+				keywordArr = append(keywordArr, util.InterfaceToStr(v["itemname"]))
+				i++
+			}
+		}
+	}
+	if util.InterfaceToStr(obj["subtype"]) != "" && util.InterfaceToStr(obj["subtype"]) != "其它" {
+		keywordArr = append(keywordArr, TypeCodeMap[util.InterfaceToStr(obj["subtype"])])
+	}
+	if util.InterfaceToStr(obj["area"]) != "" {
+		keywordArr = append(keywordArr, util.InterfaceToStr(obj["area"])+"招标")
+	}
+	if util.InterfaceToStr(obj["city"]) != "" {
+		keywordArr = append(keywordArr, util.InterfaceToStr(obj["city"])+"招标")
+	}
+	keywordArr = append(keywordArr, "剑鱼标讯")
+	keyword := strings.Join(keywordArr, ",")
+	return keyword
+}
+func DescriptionHandle(stype string, obj map[string]interface{}) string {
+	description := ""
+	publishtime := util.Int64All(obj["l_publishtime"])
+	if publishtime == 0 {
+		publishtime = util.Int64All(obj["publishtime"])
+	}
+	pushTime := time.Unix(publishtime, 0)
+	title := util.InterfaceToStr(obj["title"])
+	owner := util.InterfaceToStr(obj["owner"])
+	buyer := util.InterfaceToStr(obj["buyer"])
+	if buyer == "" {
+		buyer = owner
+	}
+	s_winner := util.InterfaceToStr(obj["s_winner"])
+	area := util.InterfaceToStr(obj["area"])
+	city := util.InterfaceToStr(obj["city"])
+	if stype == "bdprivate" {
+		//bdprivate
+		//{项目标题},采购单位:{采购单位名称},成交供应商:{中标企业名称},公告日期:{公告日期}。
+		descriptionArr := []string{}
+		if title != "" {
+			descriptionArr = append(descriptionArr, title)
+		}
+		if buyer != "" {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("采购单位:%s", buyer))
+		}
+		if s_winner != "" {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("成交供应商:%s", s_winner))
+		}
+		if publishtime != 0 {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("公告日期:%s", pushTime.Format("2006年01月02日")))
+		}
+		descriptionArr = append(descriptionArr, "查看该项目信息详情请访问剑鱼标讯官网。")
+		description = strings.Join(descriptionArr, ",")
+	} else {
+		//descriptionStr = "%s,项目所属地区是%s%s,项目采购单位是%s,项目发布时间是%s"
+		descriptionArr := []string{}
+		if title != "" {
+			descriptionArr = append(descriptionArr, title)
+		}
+		if area != "" || city != "" {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("项目所属地区是%s%s", area, city))
+		}
+		if buyer != "" {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("项目采购单位是%s", buyer))
+		}
+		if publishtime != 0 {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("项目发布时间是%s", pushTime.Format("2006年01月02日")))
+		}
+		descriptionArr = append(descriptionArr, "查看该项目信息详情请访问剑鱼标讯官网。")
+		description = strings.Join(descriptionArr, ",")
+	}
+	return description
+}

+ 4 - 4
src/jfw/front/tags.go

@@ -408,7 +408,7 @@ func (this *Tags) GetIndustry(industryHref string) interface{} {
 				v: industryMap[v],
 			})
 		}
-		redis.Put("other", rediskey, m, 2*60*60)
+		redis.Put("other", rediskey, m, 2*60)
 		return m
 	}
 	return nil
@@ -493,7 +493,7 @@ func (this *Tags) GetStype(href string) (list []map[string]interface{}) {
 			}
 		}
 		list = m
-		redis.Put("other", rediskey, list, 2*60*60)
+		redis.Put("other", rediskey, list, 2*60)
 	}
 	return list
 }
@@ -677,8 +677,8 @@ func (this *Tags) GetBidding(industry, area, city, stype, keyword string, reques
 					industry = strings.Split(industry, "_")[0]
 				}
 				public.BidListConvert(industry, datas)
-				redis.Put("other", rediskey, datas, 2*60*60)
-				redis.Put("other", rediskeyCount, count, 2*60*60)
+				redis.Put("other", rediskey, datas, 2*60)
+				redis.Put("other", rediskeyCount, count, 2*60)
 				return *datas, count, false
 			}
 		}

+ 119 - 1
src/jfw/modules/app/src/app/front/shorturl.go

@@ -11,6 +11,8 @@ import (
 	"strings"
 	"time"
 
+	"github.com/gogf/gf/v2/util/gconv"
+
 	"app.yhyue.com/moapp/jybase/date"
 	"app.yhyue.com/moapp/jybase/encrypt"
 	"app.yhyue.com/moapp/jybase/fsw"
@@ -39,6 +41,29 @@ func init() {
 
 var DateFullLayout = "2006-01-02 15:04:05"
 var suffix_msgt = "_SX"
+var TypeCodeMap = map[string]string{
+	"拟建":   "拟建项目",
+	"采购意向": "采购意向",
+	"预告":   "招标预告",
+	"预审":   "资格预审",
+	"预审结果": "资格预审结果",
+	"论证意见": "论证意见",
+	"需求公示": "需求公示",
+	"招标":   "公开招标",
+	"邀标":   "邀请招标",
+	"询价":   "询价采购",
+	"竞谈":   "竞争性谈判",
+	"单一":   "单一来源采购",
+	"竞价":   "竞价公告",
+	"变更":   "变更公告",
+	"中标":   "中标公示",
+	"成交":   "成交公告",
+	"废标":   "废标公告",
+	"流标":   "流标公告",
+	"合同":   "合同公告信息",
+	"验收":   "验收公告信息",
+	"违规":   "违规信息",
+}
 
 func (s *Short) Article(stype, id string) error {
 	//先判断是否有session
@@ -267,6 +292,8 @@ func (s *Short) Article(stype, id string) error {
 		s.T["advertName"] = config.Sysconfig["advertName"]
 		s.T["advertUrl"] = config.Sysconfig["advertUrl"]
 		obj["industry"] = industry
+		obj["keywords"] = KeyWordHandle(obj)
+		obj["description"] = DescriptionHandle(stype, obj)
 		s.T["obj"] = obj
 		s.T["isIosExam"], s.T["isIosExamPhone"], _, _ = IosExamInfo(s.Action, false, false)
 		content, err := s.Render4Cache("/weixin/wxinfocontent.html", &s.T)
@@ -333,8 +360,10 @@ func NoLoginArticle(stype, sid string) map[string]interface{} {
 		obj["buyerTitle"] = obj["buyer"]
 		obj["projectnameTitle"] = obj["projectname"]
 		obj["projectcodeTitle"] = obj["projectcode"]
+		obj["keywords"] = KeyWordHandle(obj)
+		obj["description"] = DescriptionHandle("nologin", obj)
 		obj = Filter(obj)
-		redis.Put("other", catchKey, obj, 60*60*2)
+		redis.Put("other", catchKey, obj, 60*2)
 	}
 	return obj
 }
@@ -612,3 +641,92 @@ func baseInfo(obj map[string]interface{}) string {
 	}
 	return info
 }
+func KeyWordHandle(obj map[string]interface{}) string {
+	keywordArr := []string{}
+	owner := util.InterfaceToStr(obj["owner"])
+	buyer := util.InterfaceToStr(obj["buyer"])
+	if buyer == "" {
+		buyer = owner
+	}
+	if buyer != "" && buyer != config.Sysconfig["detailMosaicTxt"] {
+		keywordArr = append(keywordArr, util.InterfaceToStr(obj["buyer"]))
+	}
+	if util.InterfaceToStr(obj["s_winner"]) != "" && util.InterfaceToStr(obj["s_winner"]) != config.Sysconfig["detailMosaicTxt"] {
+		keywordArr = append(keywordArr, util.InterfaceToStr(obj["s_winner"]))
+	}
+	if obj["purchasinglist"] != nil && obj["purchasinglist"] != "" {
+		i := 0
+		for _, v := range gconv.SliceMap(obj["purchasinglist"]) {
+			if i == 5 {
+				break
+			}
+			if util.InterfaceToStr(v["itemname"]) != "" && util.InterfaceToStr(obj["s_winner"]) != config.Sysconfig["detailMosaicTxt"] {
+				keywordArr = append(keywordArr, util.InterfaceToStr(v["itemname"]))
+				i++
+			}
+		}
+	}
+	if util.InterfaceToStr(obj["subtype"]) != "" && util.InterfaceToStr(obj["subtype"]) != "其它" {
+		keywordArr = append(keywordArr, TypeCodeMap[util.InterfaceToStr(obj["subtype"])])
+	}
+	if util.InterfaceToStr(obj["area"]) != "" {
+		keywordArr = append(keywordArr, util.InterfaceToStr(obj["area"])+"招标")
+	}
+	if util.InterfaceToStr(obj["city"]) != "" {
+		keywordArr = append(keywordArr, util.InterfaceToStr(obj["city"])+"招标")
+	}
+	keywordArr = append(keywordArr, "剑鱼标讯")
+	keyword := strings.Join(keywordArr, ",")
+	return keyword
+}
+func DescriptionHandle(stype string, obj map[string]interface{}) string {
+	description := ""
+	pushTime := time.Unix(util.Int64All(obj["l_publishtime"]), 0)
+	title := util.InterfaceToStr(obj["title"])
+	owner := util.InterfaceToStr(obj["owner"])
+	buyer := util.InterfaceToStr(obj["buyer"])
+	if buyer == "" {
+		buyer = owner
+	}
+	s_winner := util.InterfaceToStr(obj["s_winner"])
+	publishtime := util.Int64All(obj["l_publishtime"])
+	area := util.InterfaceToStr(obj["area"])
+	city := util.InterfaceToStr(obj["city"])
+	if stype == "bdprivate" {
+		//bdprivate
+		//{项目标题},采购单位:{采购单位名称},成交供应商:{中标企业名称},公告日期:{公告日期}。
+		descriptionArr := []string{}
+		if title != "" {
+			descriptionArr = append(descriptionArr, title)
+		}
+		if buyer != "" {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("采购单位:%s", buyer))
+		}
+		if s_winner != "" {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("成交供应商:%s", s_winner))
+		}
+		if publishtime != 0 {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("公告日期:%s", pushTime.Format("2006年01月02日")))
+		}
+		descriptionArr = append(descriptionArr, "查看该项目信息详情请访问剑鱼标讯官网。")
+		description = strings.Join(descriptionArr, ",")
+	} else {
+		//descriptionStr = "%s,项目所属地区是%s%s,项目采购单位是%s,项目发布时间是%s"
+		descriptionArr := []string{}
+		if title != "" {
+			descriptionArr = append(descriptionArr, title)
+		}
+		if area != "" || city != "" {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("项目所属地区是%s%s", area, city))
+		}
+		if buyer != "" {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("项目采购单位是%s", buyer))
+		}
+		if publishtime != 0 {
+			descriptionArr = append(descriptionArr, fmt.Sprintf("项目发布时间是%s", pushTime.Format("2006年01月02日")))
+		}
+		descriptionArr = append(descriptionArr, "查看该项目信息详情请访问剑鱼标讯官网。")
+		description = strings.Join(descriptionArr, ",")
+	}
+	return description
+}

+ 2 - 1
src/jfw/modules/app/src/config.yaml

@@ -3,4 +3,5 @@ etcd:
   - 127.0.0.1:2379
 userCenterKey: "usercenter.rpc" #用户中台rpc
 powerCheckCenterKey: "powercheck.rpc" #权益校验中台
-entManageApplication: "entmanageapplication.rpc" #企业管理中台
+entManageApplication: "entmanageapplication.rpc" #企业管理中台
+publicserviceKey: "publicservice.rpc"

+ 60 - 56
src/jfw/modules/app/src/db.json

@@ -1,64 +1,68 @@
 {
-	"mongodb": {
-		"main": {
-			"address": "192.168.3.206:27080",
-	 		"size": 5,
-	 		"dbName": "qfw"
-		},
-		"log": {
-			"address": "192.168.3.206:27090",
-	 		"size": 5,
-	 		"dbName": "qfw",
-			"userName": "admin",
-			"password": "123456"
-		},
-		"ent": {
-			"address": "192.168.3.206:27001,192.168.3.206:27002",
-	 		"size": 5,
-	 		"dbName": "mixdata",
-			"userName": "jyDevGroup",
-			"password": "jy@DevGroup"
-		},
-		"bidding": {
-			"address": "192.168.3.206:27001,192.168.3.206:27002",
-	 		"size": 5,
-	 		"dbName": "qfw_data",
-			"collection": "bidding",
-			"collection_back": "bidding_back",
-			"userName": "jyDevGroup",
-			"password": "jy@DevGroup"
-		}
-	},
-	"elasticsearch": {
-		"main": {
-			"address": "http://192.168.3.206:9800",
-	    	"size": 2,
-			"version": "v7",
-			"userName": "",
-			"password": ""
-		}
+  "mongodb": {
+    "main": {
+      "address": "192.168.3.206:27080",
+      "size": 20,
+      "dbName": "qfw"
     },
+    "log": {
+      "address": "192.168.3.206:27090",
+      "size": 5,
+      "dbName": "qfw",
+      "userName": "admin",
+      "password": "123456"
+    },
+    "ent": {
+      "address": "192.168.3.206:27002",
+      "size": 5,
+      "dbName": "mixdata",
+      "userName": "jyDevGroup",
+      "password": "jy@DevGroup"
+    },
+    "bidding": {
+      "address": "192.168.3.206:27002",
+      "size": 5,
+      "dbName": "qfw_data",
+      "replSet": "",
+      "collection": "bidding",
+      "collection_back": "bidding_back",
+      "userName": "jyDevGroup",
+      "password": "jy@DevGroup"
+    }
+  },
+  "elasticsearch": {
+    "main": {
+      "address": "http://192.168.3.241:9205,http://192.168.3.149:9200",
+      "size": 30,
+      "version": "v7",
+      "userName": "",
+      "password": ""
+    }
+  },
   "redis": {
     "main":{
-      "address": "other=192.168.3.11:1712,push=192.168.3.206:1712,sso=192.168.3.206:1712,session=192.168.3.11:1713,recovery=192.168.3.206:1712,merge=192.168.3.206:1712,newother=192.168.3.206:1712"
+      "address": "other=192.168.3.149:1712,sso=192.168.3.149:1713,push=192.168.3.149:1711,session=192.168.3.149:1713,recovery=192.168.3.149:1715,merge=192.168.3.149:1712,newother=192.168.3.149:1712,poly=192.168.3.149:1713"
+    },
+    "login": {
+      "address": "login=192.168.3.149:1712"
     }
+  },
+  "mysql": {
+    "main": {
+      "dbName": "jianyu",
+      "address": "192.168.3.149:3306",
+      "userName": "root",
+      "passWord": "Topnet123",
+      "maxOpenConns": 500,
+      "maxIdleConns": 200
     },
-    "mysql": {
-	    "main": {
-	        "dbName": "jianyu",
-	        "address": "192.168.3.11:3366",
-	        "userName": "root",
-	        "passWord": "Topnet123",
-			"maxOpenConns": 2,
-			"maxIdleConns": 2
-	    },
-      	"base": {
-	        "dBName": "base_service",
-	        "address": "192.168.3.217:4000",
-	        "userName": "root",
-	        "passWord": "=PDT49#80Z!RVv52_z",
-	        "maxOpenConns": 5,
-	        "maxIdleConns": 5
-      	}
+    "base": {
+      "dBName": "base_service",
+      "address" : "192.168.3.217:4000",
+      "userName": "root",
+      "passWord": "=PDT49#80Z!RVv52_z",
+      "maxOpenConns": 5,
+      "maxIdleConns": 5
     }
+  }
 }

+ 44 - 51
src/jfw/modules/app/src/go.mod

@@ -5,12 +5,12 @@ go 1.18
 require (
 	app.yhyue.com/moapp/jybase v0.0.0-20230614085041-f8f20842d5cb
 	app.yhyue.com/moapp/jylog v0.0.0-20230522075550-05d7230ca545
-	app.yhyue.com/moapp/jypkg v0.0.0-20230627072535-2f1a67f51167
+	app.yhyue.com/moapp/jypkg v0.0.0-20230531014856-12e9a04b5c44
 	bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.13
 	github.com/SKatiyar/qr v0.0.0-20151201054752-25b6bdf44e67
 	github.com/gogf/gf/v2 v2.3.1
 	github.com/pkg/errors v0.9.1
-	go.mongodb.org/mongo-driver v1.11.6
+	go.mongodb.org/mongo-driver v1.11.1
 )
 
 require (
@@ -25,61 +25,58 @@ require (
 	github.com/cenkalti/backoff/v4 v4.2.1 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/clbanning/mxj/v2 v2.5.5 // indirect
-	github.com/coreos/go-semver v0.3.1 // indirect
-	github.com/coreos/go-systemd/v22 v22.5.0 // indirect
+	github.com/coreos/go-semver v0.3.0 // indirect
+	github.com/coreos/go-systemd/v22 v22.3.2 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
-	github.com/emicklei/go-restful/v3 v3.9.0 // indirect
-	github.com/fatih/color v1.15.0 // indirect
+	github.com/fatih/color v1.13.0 // indirect
+	github.com/felixge/fgprof v0.9.3 // indirect
 	github.com/fsnotify/fsnotify v1.6.0 // indirect
 	github.com/garyburd/redigo v1.6.2 // indirect
 	github.com/go-logr/logr v1.2.4 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
-	github.com/go-openapi/jsonpointer v0.19.6 // indirect
-	github.com/go-openapi/jsonreference v0.20.1 // indirect
-	github.com/go-openapi/swag v0.22.3 // indirect
 	github.com/go-redis/redis/v8 v8.11.5 // indirect
-	github.com/go-sql-driver/mysql v1.7.1 // indirect
+	github.com/go-sql-driver/mysql v1.7.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
-	github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
+	github.com/golang-jwt/jwt/v4 v4.4.3 // indirect
 	github.com/golang/mock v1.6.0 // indirect
-	github.com/golang/protobuf v1.5.3 // indirect
+	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
 	github.com/gomodule/redigo v2.0.0+incompatible // indirect
-	github.com/google/gnostic v0.5.7-v3refs // indirect
 	github.com/google/go-cmp v0.5.9 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
+	github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect
+	github.com/googleapis/gnostic v0.5.5 // indirect
 	github.com/gorilla/websocket v1.5.0 // indirect
 	github.com/grokify/html-strip-tags-go v0.0.1 // indirect
-	github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 // indirect
+	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/howeyc/fsnotify v0.9.0 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.1 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/klauspost/compress v1.15.15 // indirect
+	github.com/klauspost/compress v1.15.11 // indirect
 	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
-	github.com/mattn/go-colorable v0.1.13 // indirect
-	github.com/mattn/go-isatty v0.0.17 // indirect
+	github.com/mattn/go-colorable v0.1.12 // indirect
+	github.com/mattn/go-isatty v0.0.14 // indirect
 	github.com/mattn/go-runewidth v0.0.13 // indirect
-	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
+	github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
-	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
 	github.com/nsqio/go-nsq v1.1.0 // indirect
 	github.com/olekukonko/tablewriter v0.0.5 // indirect
 	github.com/olivere/elastic v6.2.37+incompatible // indirect
 	github.com/olivere/elastic/v7 v7.0.22 // indirect
 	github.com/openzipkin/zipkin-go v0.4.1 // indirect
-	github.com/pelletier/go-toml/v2 v2.0.8 // indirect
-	github.com/prometheus/client_golang v1.15.1 // indirect
-	github.com/prometheus/client_model v0.3.0 // indirect
-	github.com/prometheus/common v0.42.0 // indirect
-	github.com/prometheus/procfs v0.9.0 // indirect
+	github.com/pelletier/go-toml/v2 v2.0.6 // indirect
+	github.com/prometheus/client_golang v1.13.0 // indirect
+	github.com/prometheus/client_model v0.2.0 // indirect
+	github.com/prometheus/common v0.37.0 // indirect
+	github.com/prometheus/procfs v0.8.0 // indirect
 	github.com/rivo/uniseg v0.2.0 // indirect
 	github.com/sirupsen/logrus v1.8.3 // indirect
 	github.com/spaolacci/murmur3 v1.1.0 // indirect
@@ -95,37 +92,36 @@ require (
 	github.com/xdg-go/scram v1.1.1 // indirect
 	github.com/xdg-go/stringprep v1.0.3 // indirect
 	github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
-	github.com/zeromicro/go-zero v1.5.3 // indirect
+	github.com/zeromicro/go-zero v1.4.4 // indirect
 	github.com/ziutek/blas v0.0.0-20190227122918-da4ca23e90bb // indirect
-	go.etcd.io/etcd/api/v3 v3.5.9 // indirect
-	go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
-	go.etcd.io/etcd/client/v3 v3.5.9 // indirect
+	go.etcd.io/etcd/api/v3 v3.5.6 // indirect
+	go.etcd.io/etcd/client/pkg/v3 v3.5.6 // indirect
+	go.etcd.io/etcd/client/v3 v3.5.6 // indirect
 	go.opentelemetry.io/otel v1.15.1 // indirect
 	go.opentelemetry.io/otel/exporters/jaeger v1.15.1 // indirect
 	go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.15.1 // indirect
 	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.15.1 // indirect
 	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.15.1 // indirect
 	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.15.1 // indirect
-	go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 // indirect
 	go.opentelemetry.io/otel/exporters/zipkin v1.15.1 // indirect
 	go.opentelemetry.io/otel/sdk v1.15.1 // indirect
 	go.opentelemetry.io/otel/trace v1.15.1 // indirect
 	go.opentelemetry.io/proto/otlp v0.19.0 // indirect
-	go.uber.org/atomic v1.10.0 // indirect
-	go.uber.org/automaxprocs v1.5.2 // indirect
-	go.uber.org/multierr v1.9.0 // indirect
-	go.uber.org/zap v1.24.0 // indirect
-	golang.org/x/crypto v0.6.0 // indirect
-	golang.org/x/net v0.10.0 // indirect
-	golang.org/x/oauth2 v0.7.0 // indirect
+	go.uber.org/atomic v1.9.0 // indirect
+	go.uber.org/automaxprocs v1.5.1 // indirect
+	go.uber.org/multierr v1.8.0 // indirect
+	go.uber.org/zap v1.21.0 // indirect
+	golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 // indirect
+	golang.org/x/net v0.8.0 // indirect
+	golang.org/x/oauth2 v0.4.0 // indirect
 	golang.org/x/sync v0.1.0 // indirect
-	golang.org/x/sys v0.8.0 // indirect
-	golang.org/x/term v0.8.0 // indirect
-	golang.org/x/text v0.9.0 // indirect
+	golang.org/x/sys v0.7.0 // indirect
+	golang.org/x/term v0.6.0 // indirect
+	golang.org/x/text v0.8.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
-	google.golang.org/grpc v1.56.1 // indirect
+	google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
+	google.golang.org/grpc v1.54.0 // indirect
 	google.golang.org/protobuf v1.30.0 // indirect
 	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
@@ -135,14 +131,11 @@ require (
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	gorm.io/driver/mysql v1.0.5 // indirect
 	gorm.io/gorm v1.21.3 // indirect
-	jygit.jydev.jianyu360.cn/ApplicationCenter/publicService v0.0.0-20230626055559-2b719f6c6602 // indirect
-	k8s.io/api v0.26.3 // indirect
-	k8s.io/apimachinery v0.27.0-alpha.3 // indirect
-	k8s.io/client-go v0.26.3 // indirect
-	k8s.io/klog/v2 v2.90.1 // indirect
-	k8s.io/kube-openapi v0.0.0-20230307230338-69ee2d25a840 // indirect
-	k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
-	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
-	sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
-	sigs.k8s.io/yaml v1.3.0 // indirect
+	k8s.io/api v0.22.9 // indirect
+	k8s.io/apimachinery v0.22.9 // indirect
+	k8s.io/client-go v0.22.9 // indirect
+	k8s.io/klog/v2 v2.80.1 // indirect
+	k8s.io/utils v0.0.0-20221108210102-8e77b1f39fe2 // indirect
+	sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
+	sigs.k8s.io/yaml v1.2.0 // indirect
 )

文件差异内容过多而无法显示
+ 497 - 86
src/jfw/modules/app/src/go.sum


+ 207 - 33
src/jfw/modules/app/src/web/staticres/jyapp/big-member/css/analysis_result.css

@@ -1,3 +1,24 @@
+#analysis-result .head-tip{
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: .88rem;
+  background: #EAF8FA;
+  color: #2ABED1;
+  font-size: .26rem;
+}
+#analysis-result .bid_forcast_com{
+  padding-top: .24rem;
+  width: 100%;
+  height: 1.3rem;
+  line-height: .4rem;
+  background: url('../image/bid_bg.png') no-repeat;
+  background-size: 100% 100%;
+  color: #171826;
+  font-size: .26rem;
+  text-align: center;
+}
 #analysis-result .skeleton{
     height: 100%;
     display: flex;
@@ -98,10 +119,6 @@
     margin-top: -0.02rem;
 }
 
-#analysis-result .filter {
-    margin-top: .16rem;
-}
-
 #analysis-result .filter-title {
     padding: .32rem .32rem .12rem;
     background: #fff;
@@ -114,7 +131,6 @@
     font-size: .36rem;
     line-height: .52rem;
     color: #171826;
-    font-weight: bold;
 }
 
 #analysis-result .filter-title>span::after {
@@ -156,7 +172,7 @@
 #analysis-result .cur-value {
     color: #2ABED1;
 }
-#analysis-result .van-tabs__wrap {
+#analysis-result .van-tabs__wrap, .setTop .van-tabs__wrap{
     height: .96rem;
 }
 #analysis-result .van-tabs__wrap::after{
@@ -173,7 +189,7 @@
     background: transparent;
 }
 
-#analysis-result .van-tabs__line {
+#analysis-result .van-tabs__line, .setTop .van-tabs__line {
     width: 24px;
     background: linear-gradient(#25BEEE, #2ABED1);
     border-radius: 1px;
@@ -185,7 +201,10 @@
 }
 #analysis-result .summary{
     background-color: #fff;
-    margin-bottom: .16rem;
+    margin-top: .16rem;
+}
+#analysis-result .projects {
+  margin-top: .16rem;
 }
 #analysis-result .summary-container{
     display: flex;
@@ -223,7 +242,7 @@
 }
 
 #analysis-result .a-item {
-    margin-bottom: .2rem;
+    margin: .16rem 0 .2rem;
     background-color: #fff;
     overflow: hidden;
 }
@@ -331,36 +350,102 @@
     font-size: .32rem;
     line-height: .48rem;
     color: #171826;
-    font-weight: bold;
 }
 #analysis-result .win-capital{
-  padding: 8px 24px;
-  font-size: .22rem;
-  color: #171826;
+  padding: .16rem 0 .16rem .48rem;
+  font-size: .24rem;
+  color: #5F5E64;
   line-height: .36rem;
 }
+#analysis-result .win-capital>span:last-child{
+  margin-left: .64rem;
+}
 #analysis-result .win-info{
+  padding: .22rem .16rem;
   background: linear-gradient(180deg, rgba(108, 218, 237, 0.2) 0%, rgba(255, 255, 255, 0) 100%);
   border-radius: 6px;
 }
 #analysis-result .w-title{
   display: flex;
-  align-items: center;
+  flex-direction: column;
   justify-content: space-between;
-  padding: 9px 8px 0;
+}
+#analysis-result .w-title .w-title-head {
+  font-size: .24rem;
+  color: #5F5E64;
+}
+#analysis-result .switchTab{
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  width: 100%;
+  height: .64rem;
+}
+.switchTab .switch-tab{
+  position: relative;
+  height: .44rem;
+  margin-left: .32rem;
+  font-size: .28rem;
+  color: #171826;
+}
+.switchTab .switch-tab.textColor{
+  color: #2ABED1;
+}
+.switchTab .switch-tab .line {
+  position: absolute;
+  bottom: 0;
+  left: .3rem;
+  width: .48rem;
+  height: .04rem;
+  background: #2ABED1;
+  border-radius: .02rem;
+}
+
+.switchTab .switch-tab {
+  margin-top: .18rem;
+}
+#analysis-result .switchTab .switch_label{
+  color: #9B9CA3;
+  font-size: .24rem;
+}
+#analysis-result .switchTab .switch_tab_list{
+  /* width: 2.56rem; */
+  height: 100%;
+}
+/* #analysis-result .switch_tab_list.winner_0 .van-tabs__line{
+  transform: translateX(.79rem) translateX(-50%);
+}
+#analysis-result .switch_tab_list.history_0 .van-tabs__line{
+  transform: translateX(.79rem) translateX(-50%);
+}
+#analysis-result .switch_tab_list.history_1 .van-tabs__line{
+  transform: translateX(2.15rem) translateX(-50%);
+} */
+/* #analysis-result .switch_tab_list.winner_1 .van-tabs__line{
+  transform: translateX(.79rem) translateX(-50%);
+} */
+#analysis-result .switch_tab_list .van-tabs__wrap {
+  height: 100%;
+}
+#analysis-result .switch_tab_list .van-tabs__wrap .van-tab{
+  padding: 0 .16rem;
+}
+#analysis-result .switch_tab_list .van-tab--active{
+  color: #2ABED1;
 }
 .w-title-label{
-  font-size: .26rem;
-  color: #1d1d1d;
-  line-height: .36rem;
+  margin-top: .08rem;
+  font-size: .28rem;
+  color: #171826;
+  line-height: .48rem;
 }
 #analysis-result .company-info{
     display: flex;
-    align-items: center;
+    flex-direction: column;
     justify-content: space-between;
-    padding: 5px 8px 8px;
+    margin-top: .08rem;
     color: #5F5E64;
-    font-size: .2rem;
+    font-size: .24rem;
     line-height: .36rem;
 }
 #analysis-result .company-info span{
@@ -434,7 +519,14 @@
     background-color: #fff;
     padding: 0 .32rem .32rem;
 }
-
+.ranking .filter-title {
+  display: flex;
+  align-items: center;
+}
+.ranking .filter-title .switchTab{
+  width: auto;
+  flex: 1;
+}
 .ranking .progress-bar-item {
     display: flex;
     flex-direction: column;
@@ -449,10 +541,17 @@
 }
 
 .ranking .progress-bar-item .item-label .item-name {
+    width: 1.04rem;
     font-size: .26rem;
     line-height:.4rem;
     color: #5F5E64;
-    flex: 1;
+}
+
+.ranking .progress-bar-item .item-label .item-time {
+  /* width: 1.6rem; */
+  font-size: .26rem;
+  line-height:.4rem;
+  color: #5F5E64;
 }
 
 .ranking .progress-bar-item .item-label .item-count {
@@ -483,6 +582,27 @@
 .ranking .blue-progress{
     background: linear-gradient(to right,#8DE0EB, #2ABED1);
 }
+.navBar{
+  display: flex;
+  align-items: center;
+  padding: 0 .32rem;
+  height: 1.08rem;
+  color: #9B9CA3;
+  font-size: .28rem;
+}
+.navBar .link-btn{
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-left: .16rem;
+  border-radius: 4px;
+  padding: .08rem .16rem;
+  background: rgba(42, 190, 209, 0.05);
+  line-height: .4rem;
+  color: #2ABED1;
+  font-size: .26rem;
+  border: 0.5px solid #2ABED1;
+}
 #analysis-result .ve-map{
     width: auto;
     /* padding: .16rem .32rem; */
@@ -494,33 +614,61 @@
     /* width: calc(100% - 0.96rem)!important; */
     /* height: 100%; */
 }
+#analysis-result .more {
+  padding: .28rem 0;
+  text-align: center;
+  color: #2ABED1;
+  font-size: .28rem;
+  line-height: .4rem;
+  background: #fff;
+}
 #analysis-result .project-list{
     padding: .24rem .32rem;
     background: #fff;
     border-radius: 8px;
-    margin: .2rem.32rem;
+    /* margin: .2rem.32rem; */
 }
 #analysis-result .pl-title{
     font-size: .32rem;
     line-height: .48rem;
     color: #171826;
 }
+#analysis-result .pl-tags{
+  margin: .16rem 0 .2rem;
+}
+#analysis-result .pl-tags>span{
+  padding: .02rem .16rem;
+  margin-right: .08rem;
+  color: #5F5E64;
+  font-size: .24rem;
+  background: #F7F9FA;
+/* Line/#000000_5% */
+  border: 0.5px solid rgba(0, 0, 0, 0.05);
+  border-radius: 4px;
+}
 #analysis-result .pl-info{
     display: flex;
-    align-items: center;
-    margin-top: .22rem;
+    /* align-items: center; */
+    margin-top: .04rem;
+    line-height: .4rem;
 }
-#analysis-result .pl-info span:nth-child(1){
+#analysis-result .pl-info>span:nth-child(1){
     display: inline-block;
     color: #9B9CA3;
-    font-size:.22rem;
+    font-size:.26rem;
 }
-#analysis-result .pl-info span:nth-child(2){
+#analysis-result .pl-info>span:nth-child(2){
     display: inline-block;
-    color: #2ABED1;
-    font-size:.22rem;
+    font-size:.26rem;
     flex: 1;
-    line-height: 1.4;
+}
+#analysis-result .pl-info .winner-list{
+  display: flex;
+  flex-wrap: wrap;
+  flex: 1;
+}
+.can-click {
+  color: #2ABED1;
 }
 #analysis-result .pl-price{
     display: flex;
@@ -584,10 +732,18 @@
   width: 5rem;
   text-align: center;
 }
+#analysis-result .jy-main-empty{
+  width: 100%;
+}
+#analysis-result .jy-main-empty .navBar{
+  height: .6rem;
+  background-color: transparent;
+  justify-content: center;
+}
 .jy-empty-img{
   width: 4rem;
   height: 4rem;
-  background: url('/common-module/public/image/jy-chagrin.png') no-repeat center center;
+  background: url('/common-module/public/image/jy-back.png') no-repeat center center;
   background-size: contain;
 }
 .jy-empty-text{
@@ -595,4 +751,22 @@
   color: #9B9BA3!important;
   line-height: .4rem;
   padding-bottom: .24rem;
+}
+
+.bottom-tip{
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: .88rem;
+  background: #FFF4E8;
+  color: #FF9F40;
+  font-size: .26rem;
+}
+
+.setTop {
+  position: fixed;
+  /* top: 1rem; */
+  width: 100%;
+  background: #fff;
+  z-index: 2002;
 }

二进制
src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/bid_bg.png


二进制
src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/itemA_05.jpg


二进制
src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB1.png


二进制
src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB2.png


二进制
src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB3.png


二进制
src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB4.png


二进制
src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB5.png


二进制
src/jfw/modules/app/src/web/staticres/jyapp/big-member/image/landpage_new/toubiaoImg/itemB6.png


+ 258 - 0
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/analysis_pro_list.js

@@ -0,0 +1,258 @@
+var vNode = {
+    delimiters: ['${', '}'],
+    el: '#analysis-result',
+    data () {
+        return {
+            projectListDetail:[],
+            filterData: {},
+            projectData: {},
+            listParams: {
+              page: 1,
+              pageSize: 10,
+              loading: false,
+              finished: false
+            }
+        }
+    },
+    created () {
+      // const entId = utils.getParam('entId')
+      // if(analysis_result_proDetail) {
+      //   analysis_result_proDetail = JSON.parse(analysis_result_proDetail)
+      //   if(entId) {
+      //     this.entId = entId
+      //     let arr = []
+      //     analysis_result_proDetail.forEach(item => {
+      //       if(item.entidlist) {
+      //         item.entidlist.forEach(v => {
+      //           if(v === entId) {
+      //             arr.push(item)
+      //           }
+      //         })
+      //       }
+      //     })
+      //     this.projectListDetail = arr
+      //   } else {
+      //     this.projectListDetail = analysis_result_proDetail
+      //   }
+      // }
+      
+    },
+    mounted() {
+        const recover = this.restoreData()
+        if(!recover) {
+          const searchItem = sessionStorage.getItem('searchItem')
+          if(searchItem) {
+            let $dataAnalysisResult = sessionStorage.getItem('$data-analysis-result_' + searchItem)
+            if($dataAnalysisResult) {
+              $dataAnalysisResult = JSON.parse($dataAnalysisResult)
+              this.filterData = $dataAnalysisResult.filterData
+              this.getProjectDetail($dataAnalysisResult.filterData)
+            }
+          }
+        }
+    },
+    methods: {
+        showLoading: function () {
+          var loading = this.$toast.loading({
+            duration: 0,
+            forbidClick: true,
+            message: 'loading...',
+          })
+          return loading
+        },
+        // 金额转换
+        formatterMoney: function(data) {
+            return utils.moneyUnit(data);
+        },
+        // 时间转换
+        formatterTime: function(data) {
+          return new Date(Number(data + '000')).pattern('yyyy/MM/dd')
+        },
+        // 跳企业画像
+        goEntImg:function(name) {
+            this.savePageData()
+            location.href = './ent_portrait?eId=' + encodeURIComponent(name)
+        },
+        onLoad: function () {
+          this.listParams.page++
+          this.getProjectDetail(this.filterData)
+        },
+        // 跳到项目信息详情
+        goProjectDetail: function (id) {
+            var that = this;
+            that.savePageData()
+            $.ajax({
+                type:'POST',
+                url:'/bigmember/follow/project/check',
+                data:{
+                    sid: id
+                },
+                success:function(res) {
+                    if(res.error_code == 0) {
+                        var obj = {
+                            fid: res.data.fig ? res.data.fig : '',
+                            sid: id
+                        }
+                        sessionStorage.setItem('bigvip-fid', JSON.stringify(obj))
+                        location.href = "./pro_follow_detail"
+                    }else{
+                        console.log(res.error_code)
+                    }
+                },
+                error:function(err) {
+                    console.log(err)
+                }
+            })
+        },
+        // 单独查同类项目明细接口
+        getProjectDetail: function(res) {
+          var that = this;
+          var loading = null
+          if(that.listParams.page === 1) {
+            loading = that.showLoading()
+          }
+          that.listParams.loading = true
+          const { area, buyer, limitTime, searchType, pname, projectScope, winner, keys, pid, sid, expertName, searchItem} = res
+          var data = {
+              area: {
+                [area]: []
+              },
+              buyerContent: keys,
+              mobileModel: that.mobileModel,
+              appVersion: that.appVersion,
+              searchType: searchType,
+              winner: winner,
+              buyer: buyer,
+              searchItem: searchItem,
+              limitTime: limitTime,
+              // 专家名称
+              expertName: expertName || '',
+              projectScope: projectScope,
+              page: this.listParams.page,
+              pageSize: this.listParams.pageSize
+          }
+          $.ajax({
+            type:'POST',
+            url:'/bigmember/decision/projectInfoByBW',
+            contentType: 'application/json;charset=utf-8' ,
+            data:JSON.stringify(data),
+            success:function(res) {
+              if(loading) {
+                loading.clear()
+              }
+              if(res.error_code == 0) {
+                // 同类项目明细数据
+                that.projectData = res.data
+                that.listParams.loading = false
+                if(res.data.res && res.data.res.length > 0){
+                  res.data.res.forEach(function (item,i) {
+                    if (item.budget && item.budget !== '') {
+                        item.budget = (item.budget / 10000).fixed(2)
+                    }
+                    if (item.bidamount && item.bidamount !== '') {
+                        item.bidamount = (item.bidamount / 10000).fixed(2)
+                    }
+                    if(item.review_experts){
+                        item.review_experts = item.review_experts.join(',')
+                    }
+                    if(item.project_rate){
+                        item.project_rate = (item.project_rate*100).fixed(2) + '%'
+                    }
+                    if(item.jgtime){
+                        item.jgtime = new Date(Number(item.jgtime + '000')).pattern('yyyy-MM-dd')
+                    }
+                    let winnerArrList = []
+                    if (Array.isArray(item.s_winner)) {
+                      winnerArrList = item.s_winner
+                    } else if (item.s_winner) {
+                      winnerArrList = item.s_winner.split(',')
+                    }
+                    const winners = winnerArrList.map((w, index) => {
+                      let id = null
+                      if (Array.isArray(item.entidlist)) {
+                        id = item.entidlist[index]
+                      }
+                      return {
+                        name: w,
+                        id
+                      }
+                    })
+                    item.s_winner = winners.filter(w => w.name)
+                  })
+                  if(that.listParams.page === 1) {
+                    that.projectListDetail = res.data.res;
+                  } else {
+                    that.projectListDetail = that.projectListDetail.concat(res.data.res)
+                  }
+                  const pageTotalNum = res.data.count / that.listParams.pageSize
+                  const pageResidue = res.data.count % that.listParams.pageSize
+                  if (pageResidue > 0) {
+                    if (that.listParams.page > pageTotalNum) {
+                      that.listParams.finished = true
+                    } else {
+                      that.listParams.finished = false
+                    }
+                  } else {
+                    if (that.listParams.page >= pageTotalNum) {
+                      that.listParams.finished = true
+                    } else {
+                      that.listParams.finished = false
+                    }
+                  }
+                }
+              } else {
+                that.listParams.loading = false
+              }
+            },
+            error:function(err) {
+              that.listParams.loading = false
+              console.log(err)
+            }
+          })
+        },
+        // 跳转中标预测
+        goForecast: function () {
+            sessionStorage.removeItem('big-ai-add-data')
+            this.savePageData()
+            location.href = "./ai_add?id=" + this.project.pId
+        },
+        // 跳转采购单位画像
+        goUnitImage:function(name){
+            this.savePageData()
+            location.href = "./unit_portrayal?entName=" + encodeURIComponent(name)
+        },
+        // 存储页面数据
+        savePageData: function(){
+            var data = {
+                projectListDetail: this.projectListDetail,
+                filterData: this.filterData,
+                projectData: this.projectData,
+                listParams: this.listParams,
+                scrollTop: this.$refs.wrapper.scrollTop
+            }
+            // console.log(data)
+            sessionStorage.setItem('$data-analysis-result-pro-list',JSON.stringify(data))
+        },
+        // 恢复页面数据
+        restoreData:function(){
+            var $data = sessionStorage.getItem('$data-analysis-result-pro-list')
+            if ($data) {
+                $data = JSON.parse($data)
+                this.projectListDetail = $data.projectListDetail
+                this.scrollTop = $data.scrollTop
+                this.filterData = $data.filterData
+                this.projectData = $data.projectData
+                this.listParams = $data.listParams
+                var _this = this
+                this.$nextTick(function(){
+                  setTimeout(() => {
+                    _this.$refs.wrapper.scrollTop = $data.scrollTop || 0
+                  }, 200)
+                })
+                sessionStorage.removeItem('$data-analysis-result-pro-list')
+            }
+            return !!$data
+        }
+    }
+}
+var result = new Vue(vNode)

+ 609 - 240
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/analysis_result.js

@@ -1,6 +1,17 @@
+window.afterClickBack = function () {
+  sessionStorage.removeItem('$data-analysis-result_1')
+  sessionStorage.removeItem('$data-analysis-result_2')
+  sessionStorage.removeItem('$data-analysis-result_3')
+  sessionStorage.removeItem('searchItem')
+  sessionStorage.removeItem('analysis-filter-data')
+  sessionStorage.removeItem('analysis_result_proDetail')
+}
 var vNode = {
     delimiters: ['${', '}'],
     el: '#analysis-result',
+    components: {
+      analysisCom: analysisComponent
+    },
     data () {
         // 柱状图标记
         this.barChartMarkPoint = {
@@ -24,11 +35,11 @@ var vNode = {
         }
         this.chartSettings = {
             xAxisName: ['标书编制周期'],
-            yAxisName: ['类项目数量(个)']
+            yAxisName: ['类项目数量(个)']
         }
         return {
             year:'',
-            skeletonShow: true,
+            skeletonShow: false,
             scroll: 90,
             stickyTop: 80,
             project:{
@@ -62,7 +73,7 @@ var vNode = {
             // 专家分析排行数据
             expertWinArr:[],
             projectListDetail:[],
-            // 类采购历史
+            // 类采购历史
             historyList:[],
             hotWin:[],
             showAll:false,
@@ -71,22 +82,24 @@ var vNode = {
                 rows: []
             },
             pieChartData: {
-                columns: ['行业', '类项目数量','类项目规模','平均折扣率','当前采购单位类型'],
+                columns: ['行业', '类项目数量','类项目规模','平均折扣率','当前采购单位类型'],
                 rows: []
             },
             mapChartData:{
-                columns: ['省份', '类项目数量','类项目规模'],
+                columns: ['省份', '类项目数量','类项目规模'],
                 rows: []
             },
             screenWidth:document.body.clientWidth,
             isShow:{
-                showHistory: true,
-                showWinner: true,
-                bidCycle: true,
-                showHotMap: true,
-                showMap: true,
-                showPie: true,
-                showExperts:true
+                showProjectList: false,
+                showSummary: false,
+                showHistory: false,
+                showWinner: false,
+                bidCycle: false,
+                showHotMap: false,
+                showMap: false,
+                showPie: false,
+                showExperts: false
             },
             // 热力图减去数据为0的行
             minusRows:0,
@@ -103,10 +116,40 @@ var vNode = {
             scrollTop: 0,
             defaultProjectDetail: [],
             hotChartRef: null,
-            pieChartRef: null
+            pieChartRef: null,
+            showListBtn: false,
+            showWinBtn: false,
+            filterData: {},
+            // 同类项目热点中标企业TOP10
+            hotWinnerEnt: {
+              hotTabActive: 0
+            },
+            // 历史合作评标专家
+            historyExpert: {
+              historyTabActive: 0
+            },
+            listCount: {
+              pCount: 0, // 全国数据条数
+              AreaCount: 0, // 地区数据条数
+              BuyerCount: 0, // 采购单位数据条数
+            },
+            powerInfo: {},
+            id: '',
+            isHaveTop: false, // 是否需要置顶tab
+            setHeight: 0, // 置顶高度
+            setHeightActive: '',
+            loadingEmpty: false
         }
     },
     computed: {
+        isHaveTrue: function () {
+          const hasTrueValue = Object.values(this.isShow).includes(true);
+          if (hasTrueValue) {
+            return true
+          } else {
+            return false
+          }
+        },
         showHistoryList: function () {
             return this.showAll ? this.historyList : this.historyList.slice(0,3)
         },
@@ -115,18 +158,30 @@ var vNode = {
         },
         heatMapHeight: function(){
             return 320 - 22*this.minusRows  + 'px'
+        },
+        setShowListBtn: function () {
+          return this.showListBtn ? this.projectListDetail.slice(0, 3) : this.projectListDetail
+        },
+        isShowWinBtn: function () {
+          return this.showWinBtn ? this.hotWin.slice(0, 3) : this.hotWin
+        },
+        is15: function () {
+          if(this.powerInfo.power) {
+            return this.powerInfo.power.includes(15)
+          } else {
+            return false
+          }
         }
     },
     watch: {
+      setHeight: {
+        handler (newval) {
+          this.setHeightActive = 'top:' + newval +'px'
+        },
+        immediate: true
+      },
       active: function(newVal) {
-        // 监听切换到类似项目明细 页面滚动到筛选条件位置
-        if (newVal == 1) {
-          this.$nextTick(function() {
-            if (this.$refs.detailFilter) {
-              this.$refs.detailFilter.scrollIntoView()
-            }
-          })
-        }
+        this.active = newVal
       },
       // 监听热力图
       hotChartRef: function (newVal) {
@@ -152,6 +207,7 @@ var vNode = {
         } catch (error) {
             console.log(error)
         }
+        this.getPower()
         // 取上个页面的sessionStorage
         var prevState = JSON.parse(sessionStorage.getItem('big-analysis_filter'));
         if(prevState) {
@@ -171,7 +227,7 @@ var vNode = {
             this.currentVal.money = prevState.currentVal.money;
             this.currentVal.buyerClass = prevState.currentVal.buyerClass;
         }
-        this.isFollowProject();
+        // this.isFollowProject();
     },
     beforeDestroy() {
         window.removeEventListener("resize", this.init,20);
@@ -183,18 +239,78 @@ var vNode = {
         // }
     },
     mounted() {
-        var restore = this.restoreData()
-        if (!restore) {
-            this.getChartData();
-            this.getBaseInfo();
-        }
-        this.year = new Date().getFullYear() - 2;
+        this.restoreData()
         // 动态调整sticky距离顶部的高度
         this.getStickyTop()
         window.addEventListener('scroll', this.handleScroll, true);
         this.init();
+        this.setInterSection()
     },
     methods: {
+        setInterSection () {
+          this.isHaveTop = false
+          const observer = new IntersectionObserver(this.handleIntersection, {
+            root: null, // 默认为浏览器视窗
+            threshold: 0, // 交叉比例,0为完全进入视窗
+          });
+          console.log(this.$refs.analysisTab)
+          observer.observe(this.$refs.analysisTab)
+        },
+        handleIntersection(entries) {
+          if(!entries[0].isIntersecting) {
+            this.isHaveTop = true
+            this.calcStickyOffset()
+          } else {
+            this.isHaveTop = false
+          }
+          // entries.forEach((entry) => {
+          //   // 元素不可见
+          //   console.log(entry.isIntersecting)
+          //   if (!entry.isIntersecting) {
+          //     this.isHaveTop = true
+          //     this.calcStickyOffset()
+          //   } else {
+          //     this.isHaveTop = false
+          //   }
+          // })
+        },
+        calcStickyOffset: function () {
+          var headerHeight = $('.jy-app-header')[0].clientHeight
+          this.setHeight = headerHeight - 2
+        },
+        getPower:function () {
+          var _this = this
+          $.ajax({
+            type:'POST',
+            url:'/bigmember/use/isAdd',
+            success:function(res) {
+              _this.powerInfo = res.data
+            }
+          })
+        },
+        onTabWinnerClick (newval) {
+          this.hotWinnerEnt.hotTabActive = newval
+          this.filterData.HotWinnerType = newval
+          this.loading = this.showLoading()
+          this.getProjectWinnerEnt()
+        },
+        onTabHistoryClick (newval) {
+          this.historyExpert.historyTabActive = newval
+          if(newval === 0) {
+            this.filterData.projectScope = 1
+          } else {
+            this.filterData.projectScope = 0
+          }
+          this.loading = this.showLoading()
+          this.getHistoryExpert()
+        },
+        setMoenyColor (str) {
+          let pattern = /^(\d+(\.\d+)?)([^\d]*)$/;
+          let match = str.match(pattern);
+          let value = match[1]; // 匹配到的数字部分
+          let unit = match[3]; // 匹配到的单位部分
+          return `<span style="color: #2ABED1">${value}</span> ${unit}`
+        },
         showLoading: function () {
           var loading = this.$toast.loading({
             duration: 0,
@@ -211,6 +327,9 @@ var vNode = {
         formatterTime: function(data) {
           return new Date(Number(data + '000')).pattern('yyyy/MM/dd')
         },
+        formatterLineTime: function(data) {
+          return new Date(Number(data + '000')).pattern('yyyy-MM-dd')
+        },
         // 返回筛选条件
         setBack:function(){
             history.back()
@@ -240,6 +359,24 @@ var vNode = {
                 this.goProjectDetail(id)
             }
         },
+        // 同类项目明细查看更多
+        setViewMore: function (data) {
+          if(data) {
+            // 历史合作评标专家
+            this.filterData.searchType = 3
+            if(this.historyExpert.historyTabActive === 0) {
+              this.filterData.projectScope = 1
+            } else {
+              this.filterData.projectScope = 0
+            }
+            this.filterData.expertName = data.key
+          } else {
+            this.filterData.searchType = 0
+          }
+          this.savePageData()
+          // sessionStorage.setItem('analysis_result_proDetail', JSON.stringify(this.defaultProjectDetail))
+          location.href = '/jyapp/big/page/bid_analysis_pro_list'
+        },
         // 跳到项目信息详情
         goProjectDetail: function (id) {
             var that = this;
@@ -267,12 +404,6 @@ var vNode = {
                 }
             })
         },
-        // 跳转中标预测
-        goForecast: function () {
-            sessionStorage.removeItem('big-ai-add-data')
-            this.savePageData()
-            location.href = "./ai_add?id=" + this.project.pId
-        },
         // 跳转采购单位画像
         goUnitImage:function(name){
             this.savePageData()
@@ -353,29 +484,9 @@ var vNode = {
             })
         },
         // 获取项目基本信息(同跟筛选条件)
-        getBaseInfo: function(){
-            var that = this;
-            $.ajax({
-                type:'POST',
-                url:'/bigmember/analysis/projectInfo',
-                data:{
-                    ptid: that.project.pId,
-                    sourceinfoid: that.project.infoId,
-                    D: 'detail'
-                },
-                success:function(res) {
-                    if(res.error_code == 0 && res.data) {
-                        if(res.data.s_subscopeclass) {
-                            if(res.data.s_subscopeclass.indexOf('_') > -1) {
-                                res.data.s_subscopeclass = res.data.s_subscopeclass.substring(0,res.data.s_subscopeclass.indexOf('_'))
-                            }
-                        }
-                        that.baseInfo = res.data
-                    } else {
-                        console.log(res.error_code)
-                    }
-                }
-            })
+        getBaseInfo: function(data){
+            // var that = this;
+            this.baseInfo = data
         },
         // 处理行业提交数据
         formatterIndustryData:function(data) {
@@ -403,105 +514,176 @@ var vNode = {
                 }
             }
         },
+        setModuleState () {
+          Object.keys(this.isShow).forEach(key => {
+            if (this.isShow[key] === true) {
+              this.isShow[key] = false;
+            }
+          })
+        },
+        // 开始分析
+        setAjaxFilters (data) {
+          // 清除老数据,初始化页面
+          this.setModuleState()
+          this.filterData = data
+          this.filterData.searchItem = 1
+          this.filterData.projectScope = 1
+          this.active = 0
+          sessionStorage.removeItem('$data-analysis-result_1')
+          sessionStorage.removeItem('$data-analysis-result_2')
+          sessionStorage.removeItem('$data-analysis-result_3')
+          // 请求新数据
+          this.setYearData()
+          this.getChartData()
+          this.getProjectWinnerEnt()
+          this.getProjectDetail()
+          this.getHistoryExpert()
+          if(data.searchItem === 1) {
+            this.historyExpert.historyTabActive = 0
+          } else {
+            this.historyExpert.historyTabActive = 1
+          }
+          setTimeout(() => {
+            var targetEle = document.getElementById('analysis-tabs')
+            targetEle.scrollIntoView()
+            this.isHaveTop = false
+          }, 1000)
+        },
+        setYearData () {
+          let num = 1
+          const limitTime = this.filterData.limitTime
+          if(limitTime === 'oneYear') {
+            num = 1
+          } else if(limitTime === 'threeYear') {
+            num = 3
+          } else {
+            num = 5
+          }
+          let month = new Date().getMonth() + 1; // 获取月份,需要加1,因为月份从0开始计数
+          let day = new Date().getDate(); // 获取日期
+          if(month < 10) {
+            month = '0' + month
+          }
+          if(day < 10) {
+            day = '0' + day
+          }
+          this.year = new Date().getFullYear() - num + '/' + month + '/' + day;
+        },
         // 获取详情页数据
         getChartData:function() {
             var that = this;
+            that.loadingEmpty = false
+            var loading = this.showLoading()
+            const {pname, buyer, area, limitTime, keys, searchItem} = this.filterData
             var data = {
-                area: that.areaData,
-                buyerContent: that.contentData,
-                buyerClass: that.buyerClassData,
-                minPrice: utils.deepCompare(that.moneyData, []) ? '' : Number(that.moneyData[0]),
-                maxPrice: Number(that.moneyData[1]) || '',
-                industry: that.industriesData ? that.formatterIndustryData(that.industriesData).toString() : '',
-                pname: that.project.projectName,
-                pid: that.project.pId,
-                sid: that.project.infoId,
-                buyer: that.project.buyer,
-                mobileModel: that.mobileModel,
-                appVersion: that.appVersion
+              appVersion: that.appVersion,
+              searchItem: searchItem ? searchItem : 1,
+              area: {
+                [area]: []
+              },
+              buyer: buyer,
+              buyerContent: keys,
+              pname: pname,
+              limitTime: limitTime
             }
             $.ajax({
-                type:'POST',
+                type:'post',
                 url:'/bigmember/decision/decInfo',
-                contentType: 'application/json;charset=utf-8' ,
-                data:JSON.stringify(data),
+                // url:'/json/analysis.js',
+                data: JSON.stringify(data),
+                contentType: 'application/json',
                 success:function(res) {
+                  console.log(res)
+                  that.loadingEmpty = true
                     if(res.error_code == 0) {
+                        if(res.data.PCount) {
+                          that.listCount.pCount = res.data.PCount
+                        }
+                        if(res.data.AreaCount) {
+                          that.listCount.AreaCount = res.data.AreaCount
+                        }
+                        if(res.data.BuyerCount) {
+                          that.listCount.BuyerCount = res.data.BuyerCount
+                        }
                         if(res.data.status == -2) {
                             that.isShow.showHistory = false;
-                            that.isShow.showWinner = false;
                             that.isShow.bidCycle = false;
                             that.isShow.showHotMap = false;
                             that.isShow.showMap = false;
                             that.isShow.showPie = false;
-                            that.isShow.showExperts = false;
-                        }
-                        // 类似项目明细数据
-                        if(res.data.PDeatils){
-                            res.data.PDeatils.forEach(function (item,i) {
-                                if (item.budget && item.budget !== '') {
-                                    item.budget = (item.budget / 10000).fixed(2)
-                                } else {
-                                    item.budget = '-'
-                                }
-                                if (item.bidamount && item.bidamount !== '') {
-                                    item.bidamount = (item.bidamount / 10000).fixed(2)
-                                } else {
-                                    item.bidamount = '--'
-                                }
-                                if(item.review_experts){
-                                    item.review_experts = item.review_experts.join(',')
-                                }
-                                if(item.project_rate){
-                                    item.project_rate = (item.project_rate*100).fixed(2) + '%'
-                                }
-                                if(item.firsttime){
-                                    item.firsttime = new Date(Number(item.firsttime + '000')).pattern('yyyy/MM/dd')
-                                }
-                            })
-                            that.defaultProjectDetail = res.data.PDeatils
-                            that.projectListDetail = res.data.PDeatils; // 类似项目明细
                         }
-                        // 类项目分析
+                        // 同类项目分析
                         if (res.data.PAnalysis && Object.keys(res.data.PAnalysis).length > 0) {
                             for (var key in res.data.PAnalysis) {
                                 that.cacheImgData[key] = res.data.PAnalysis[key]
                             }
+                            if(that.filterData.searchItem === 1) {
+                              delete that.cacheImgData.group_buyerclass
+                            } else if(that.filterData.searchItem === 2) {
+                              delete that.cacheImgData.group_area
+                            }
+                            that.setProjectDetail()
                             that.initChartData()
+                        } else {
+                          delete that.cacheImgData.all_counts
+                          delete that.cacheImgData.all_money
+                          delete that.cacheImgData.all_review_experts
+                          delete that.cacheImgData.all_winners
+                          delete that.cacheImgData.group_area
+                          delete that.cacheImgData.bidcycle_ranges
+                          delete that.cacheImgData.budgetAnalysis
+                          delete that.cacheImgData.bidcycle_ranges
                         }
-                        that.skeletonShow = false;
-                    }else{
-                        that.skeletonShow = true;
-                        setTimeout(function(){
-                            history.back()
-                        }, 3000)
                     }
+                    loading.clear();
                 },
-                error:function(err) {
-                    console.log(err)
+                error:function() {
+                  that.loadingEmpty = true
+                    loading.clear()
                 }
             })
         },
-        // 单独查类似项目明细接口
-        getProjectDetail: function(type, winner, buyer) {
+        setProjectDetail () {
+          let {all_counts, all_money, all_review_experts, all_winners} = this.cacheImgData
+          if(all_counts == 0) {
+            all_counts = parseInt(all_counts)
+          }
+          if(all_money == 0) {
+            all_money = parseInt(all_money)
+          }
+          if(all_review_experts == 0) {
+            all_review_experts = parseInt(all_review_experts)
+          }
+          if(all_winners == 0) {
+            all_winners = parseInt(all_winners)
+          }
+          if(!all_counts && !all_money && !all_review_experts && !all_winners) {
+            this.isShow.showSummary = false
+          } else {
+            this.isShow.showSummary = true
+            this.$set(this.isShow, 'showSummary', true)
+          }
+          this.$forceUpdate()
+        },
+        // 单独查同类项目明细接口
+        getProjectDetail: function() {
           var that = this;
-          var loading = that.showLoading()
+          const { area, buyer, limitTime, pname, keys, searchItem} = this.filterData
           var data = {
-              area: that.areaData,
-              buyerContent: that.contentData,
-              buyerClass: that.buyerClassData,
-              minPrice: utils.deepCompare(that.moneyData, []) ? '' : Number(that.moneyData[0]),
-              maxPrice: Number(that.moneyData[1]) || '',
-              industry: that.industriesData ? that.formatterIndustryData(that.industriesData).toString() : '',
-              pname: that.project.projectName,
-              pid: that.project.pId,
-              sid: that.project.infoId,
+              area: {
+                [area]: []
+              },
+              buyerContent: keys,
               mobileModel: that.mobileModel,
               appVersion: that.appVersion,
-              // 以下为新增
-              searchType: type,
-              winner: winner,
+              searchType: 0,
+              pname: pname,
               buyer: buyer,
+              searchItem: searchItem,
+              limitTime: limitTime,
+              // 专家名称
+              page: 1,
+              pageSize: 10
           }
           $.ajax({
             type:'POST',
@@ -510,72 +692,204 @@ var vNode = {
             data:JSON.stringify(data),
             success:function(res) {
               if(res.error_code == 0) {
-                loading.clear()
-                // 类似项目明细数据
-                if(res.data){
-                  res.data.forEach(function (item,i) {
-                    if (item.budget && item.budget !== '') {
-                        item.budget = (item.budget / 10000).fixed(2)
-                    } else {
-                        item.budget = '-'
-                    }
-                    if (item.bidamount && item.bidamount !== '') {
-                        item.bidamount = (item.bidamount / 10000).fixed(2)
-                    } else {
-                        item.bidamount = '--'
-                    }
-                    if(item.review_experts){
-                        item.review_experts = item.review_experts.join(',')
-                    }
-                    if(item.project_rate){
-                        item.project_rate = (item.project_rate*100).fixed(2) + '%'
-                    }
-                    if(item.firsttime){
-                        item.firsttime = new Date(Number(item.firsttime + '000')).pattern('yyyy/MM/dd')
-                    }
+                // 同类项目明细数据
+                if(res.data && res.data.res && res.data.res.length > 0){
+                  res.data.res.forEach(function (item,i) {
+                      if (item.budget && item.budget !== '') {
+                          item.budget = (item.budget / 10000).fixed(2)
+                      }
+                      if (item.bidamount && item.bidamount !== '') {
+                          item.bidamount = (item.bidamount / 10000).fixed(2)
+                      }
+                      if(item.review_experts){
+                          item.review_experts = item.review_experts.join('、')
+                      }
+                      if(item.project_rate){
+                          item.project_rate = (item.project_rate*100).fixed(2) + '%'
+                      }
+                      if(item.jgtime){
+                          item.jgtime = new Date(Number(item.jgtime + '000')).pattern('yyyy-MM-dd')
+                      }
+                      let winnerArrList = []
+                      if (Array.isArray(item.s_winner)) {
+                        winnerArrList = item.s_winner
+                      } else if (item.s_winner) {
+                        winnerArrList = item.s_winner.split(',')
+                      }
+                      const winners = winnerArrList.map((w, index) => {
+                        let id = null
+                        if (Array.isArray(item.entidlist)) {
+                          id = item.entidlist[index]
+                        }
+                        return {
+                          name: w,
+                          id
+                        }
+                      })
+                      item.s_winner = winners.filter(w => w.name)
                   })
-                  that.projectListDetail = res.data;
+                  that.defaultProjectDetail = res.data.res
+                  that.projectListDetail = res.data.res;
+                  if (res.data.res.length > 3) {
+                    that.showListBtn = true
+                  } else {
+                    that.showListBtn = false
+                  }
+                  that.isShow.showProjectList = true
+                } else {
+                  that.projectListDetail = []
+                  that.defaultProjectDetail = []
+                  that.isShow.showProjectList = false
                 }
-              } else {
-                loading.clear()
               }
             },
             error:function(err) {
-              loading.clear()
               console.log(err)
             }
           })
         },
+        // 单独查同类项目中标企业TOP10
+        getProjectWinnerEnt:function() {
+          var that = this;
+          const {pname, buyer, area, limitTime, keys, HotWinnerType, searchItem} = this.filterData
+          var data = {
+            appVersion: that.appVersion,
+            searchItem: searchItem ? searchItem : 1,
+            area: {
+              [area]: []
+            },
+            buyer: buyer,
+            buyerContent: keys,
+            pname: pname,
+            limitTime: limitTime,
+            // 以下为新增
+            HotWinnerType: HotWinnerType ? HotWinnerType : 0,
+          }
+          $.ajax({
+              type:'post',
+              url:'/bigmember/decision/hotWinnerTop',
+              data: JSON.stringify(data),
+              contentType: 'application/json',
+              success:function(res) {
+                console.log(res)
+                  if(res.error_code == 0) {
+                      if(res.data.status == -2) {
+                          that.isShow.showWinner = false;
+                      }
+                      // 同类项目分析
+                      if (res.data.PAnalysis && Object.keys(res.data.PAnalysis).length > 0) {
+                        for (var key in res.data.PAnalysis) {
+                            that.cacheImgData[key] = res.data.PAnalysis[key]
+                        }
+                        that.disWinnerAmount(that.cacheImgData.winnerAmount);
+                      } else {
+                        delete that.cacheImgData.winnerAmount
+                      }
+                  }
+                  if(that.loading) {
+                    that.loading.clear()
+                  }
+              },
+              error:function(err) {
+                if(that.loading) {
+                  that.loading.clear()
+                }
+              }
+          })
+        },
+        // 单独查历史合作评标专家
+        getHistoryExpert: function() {
+          var that = this;
+          const {pname, buyer, area, limitTime, keys, searchItem, projectScope, pid, sid} = that.filterData
+          var data = {
+            appVersion: that.appVersion,
+            searchItem: searchItem ? searchItem : 1,
+            area: {
+              [area]: []
+            },
+            buyer: buyer,
+            buyerContent: keys,
+            pname: pname,
+            limitTime: limitTime,
+            pid: pid,
+            sid: sid,
+            projectScope: projectScope ? projectScope : 0
+          }
+          $.ajax({
+              type:'post',
+              url:'/bigmember/decision/decReviewExperts',
+              data: JSON.stringify(data),
+              contentType: 'application/json',
+              success:function(res) {
+                console.log(res)
+                  if(res.error_code == 0) {
+                      if(res.data.status == -2) {
+                          that.isShow.showExperts = false;
+                      }
+                      if (res.data.PAnalysis && Object.keys(res.data.PAnalysis).length > 0) {
+                          that.isShow.showExperts = true
+                          for (var key in res.data.PAnalysis) {
+                              that.cacheImgData[key] = res.data.PAnalysis[key]
+                          }
+                          that.disReviewExperts(that.cacheImgData.reviewExperts);
+                      } else {
+                        delete that.cacheImgData.reviewExperts
+                        that.isShow.showExperts = false
+                      }
+                  }
+                  if(that.loading) {
+                    that.loading.clear()
+                  }
+              },
+              error:function() {
+                  if(that.loading) {
+                    that.loading.clear()
+                  }
+              }
+          })
+        },
+        // 跳转到中标企业预测
+        goBidForcast () {
+          const { pid, sid } = this.filterData
+          this.savePageData()
+          if(pid && sid) {
+            location.href = '/jyapp/big/page/ai_add?fromType=analysis&id=' + pid + '&sId=' + sid
+          } else {
+            location.href = '/jyapp/big/page/ai_add?fromType=analysis'
+          }
+        },
         // 初始化画像数据
         initChartData:function(){
             var item = this.cacheImgData;
             this.disBuyerHistory(item.buyerHistroyList);
-            this.disWinnerAmount(item.winnerAmount);
             this.disBidCycle(item.bidcycle_ranges);
             this.disBudgetFound(item.budgetAnalysis);
             this.disGroupArea(item.group_area);
             this.disBuyerClass(item.group_buyerclass);
-            this.disReviewExperts(item.reviewExperts);
         },
-        // 1.类似项目采购历史数据
+        // 1.类项目采购历史数据
         disBuyerHistory:function(data) {
             if(data && data.length > 0) {
+                this.isShow.showHistory = true
                 this.historyList = data
             } else {
                 this.isShow.showHistory = false;
             }
         },
-        // 2.类似项目热点中标企业数据
+        // 2.类项目热点中标企业数据
         disWinnerAmount:function(data) {
             if(data && data.length > 0) {
+                this.isShow.showWinner = true
+                this.showWinBtn = data.length > 3
                 this.hotWin = data;
             } else {
                 this.isShow.showWinner = false
             }
         },
-        // 3.类似项目标书编制周期发布
+        // 3.类项目标书编制周期发布
         disBidCycle: function (data) {
             if(data && data.length > 0) {
+                this.isShow.bidCycle = true
                 var arr = [];
                 data.forEach(function(item) {
                     arr.push({
@@ -596,10 +910,11 @@ var vNode = {
                 this.isShow.bidCycle = false
             }
         },
-        // 4.类项目预算分布
+        // 4.类项目预算分布
         disBudgetFound:function(data) {
             if(data && data.length > 0) {
                 // 数据都为0 隐藏
+                this.isShow.showHotMap = true
                 var countArr = data.map(function(v){
                     return v.doc_count;
                 })
@@ -615,15 +930,16 @@ var vNode = {
                 this.isShow.showHotMap = false;
             }
         },
-        // 5.类项目区域分布
+        // 5.类项目区域分布
         disGroupArea:function(data){
             if (data && data.length > 0) {
+                this.isShow.showMap = true
                 var rows = [];
                 data.forEach(function(item){
                     rows.push({
                         '省份': item.key,
-                        '类项目数量': item.doc_count,
-                        '类项目规模': utils.moneyUnit(item.bidamount_sum)
+                        '类项目数量': item.doc_count,
+                        '类项目规模': utils.moneyUnit(item.bidamount_sum)
                     })
                 })
                 this.mapChartData.rows = rows.map(function (v) {
@@ -636,9 +952,10 @@ var vNode = {
                 this.isShow.showMap = false
             }
         },
-        // 6.类项目采购单位类型分布
+        // 6.类项目采购单位类型分布
         disBuyerClass:function(data) {
             if (data && data.length > 0) {
+                this.isShow.showPie = true
                 this.$nextTick(function(){
                     this.getPieCharData(data)
                 })
@@ -653,9 +970,11 @@ var vNode = {
                     v.parent = v.doc_count / data[0].doc_count*100 + "%";
                 })
                 this.expertWinArr = data;
+                this.isShow.showExperts = true
             } else {
                 this.isShow.showExperts = false
             }
+            this.$forceUpdate()
         },
 
         // 热力图+散点图数据获取及自定义配置
@@ -687,7 +1006,6 @@ var vNode = {
                 v[1] = v[1] - waitDelCount;
                 return v
             })
-            console.log(waitDelCount,'减掉几行数据为0的')
             that.minusRows = waitDelCount;
             chartOptions.hotChart.series[0].data = data;
             chartOptions.hotChart.series[1].data = curBudget && curBudget != 0 ? [that.getCoordinateInfo(data,curBudget)] : []; // 蓝点
@@ -705,9 +1023,9 @@ var vNode = {
             chartOptions.hotChart.graphic[chartOptions.hotChart.graphic.length - 2].children[0].style.text = maxNum > 10 ? maxNum.toString() : '10';
             chartOptions.hotChart.series[0].tooltip.formatter = function(params){
                 var tip = '';
-                var count = '<span>类项目数量:' + params.value[3] + '个</span></br>';
+                var count = '<span>类项目数量:' + params.value[3] + '个</span></br>';
                 var rate = (typeof params.value[2] == 'number' && !isNaN(params.value[2])) ? '<span>平均折扣率:' + (params.value[2]*100).fixed(2) + '%</span></br>' : '';
-                var budget = '<span>类项目预算:' + params.value[4] + '</span></br>';
+                var budget = '<span>类项目预算:' + params.value[4] + '</span></br>';
                 tip = budget + count + rate;
                 return tip;
             }
@@ -715,9 +1033,9 @@ var vNode = {
                 var arr = chartOptions.hotChart.series[1].data[0]; // 蓝点数据
                 var tip = '';
                 params.marker = '<span style="display:inline-block;margin-right:5px;border-radius:8px;width:8px;height:8px;background-color:' + params.color +'"></span>';
-                var count = '<span style="padding-left:13px;">类项目数量:' + arr[3] + '个</span></br>';
+                var count = '<span style="padding-left:13px;">类项目数量:' + arr[3] + '个</span></br>';
                 var rate = (typeof arr[2] == 'number' && !isNaN(arr[2])) ? '<span style="padding-left:13px;">平均折扣率:' + (arr[2]*100).fixed(2) + '%</span></br>' : '';
-                var budget = '<span style="padding-left:13px;">类项目预算:' + arr[4] + '</span></br>';
+                var budget = '<span style="padding-left:13px;">类项目预算:' + arr[4] + '</span></br>';
                 tip = params.marker +  '当前项目预算:' + (curBudget/10000).fixed(2) + '万元<br/>' + budget + count + rate;
                 return tip;
             }
@@ -816,7 +1134,6 @@ var vNode = {
                 arr.push(data[i]['编制周期'].replace('天','').split('-'))
             }
             var curIndex = this.getArrayIndex(arr,curCycle,'cycle')
-            console.log('当前编制周期所在下标:',curIndex,curCycle)
             params.grid.top = 15;
             params.grid.right = 15;
             params.yAxis[0].name = '';
@@ -842,17 +1159,18 @@ var vNode = {
             data.forEach(function(item){
                 arr.push(item.key,item.doc_money,item.doc_count,item.avg,item.main)
             })
-            var normal =['行业','类项目规模', '类项目数量','平均折扣率','是否当前项目'];
+            var normal =['行业','类项目规模', '类项目数量','平均折扣率','是否当前项目'];
             var newArr = that.arrTrans(5,arr);
             newArr.unshift(normal)
+            chartOptions.deformPieChart.roseType = false;
             chartOptions.deformPieChart.dataset.source = newArr;
             chartOptions.deformPieChart.tooltip.formatter = function(params){
                 var tip = '';
                 var data = params.data;
                 params.marker = '<span style="display:inline-block;margin-right:5px;border-radius:8px;width:8px;height:8px;background-color:' + params.color +'"></span>';
                 var percent = '<span style="padding-left:13px;">采购规模占比:' + params.percent + '%</span></br>';
-                var scale = '<span style="padding-left:13px;">类项目规模:' + (data[1]/10000).fixed(2) + '万元</span></br>';
-                var count = '<span style="padding-left:13px;">类项目数量:' + data[2] + '个</span></br>';
+                var scale = '<span style="padding-left:13px;">类项目规模:' + (data[1]/10000).fixed(2) + '万元</span></br>';
+                var count = '<span style="padding-left:13px;">类项目数量:' + data[2] + '个</span></br>';
                 var rate = (typeof data[3] == 'number' && !isNaN(data[3])) ? '<span style="padding-left:13px;">平均折扣率:' + (data[3]*100).fixed(2) + '%</span></br>' : '';
                 tip = params.marker + params.name +'<br/>' + percent + scale + count + rate
                 return tip;
@@ -891,7 +1209,7 @@ var vNode = {
         // 地图配单独置项
         mapConfig: function(options) {
             var arr = this.mapChartData.rows;
-            var maxNum = Math.max.apply(Math, arr.map(function(o) {return o['类项目数量']}))
+            var maxNum = Math.max.apply(Math, arr.map(function(o) {return o['类项目数量']}))
             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.graphic[0].children[0].style.text = '项目数量(个)'
@@ -903,12 +1221,12 @@ var vNode = {
                 var counts = '';
                 for (var i = 0; i < data.length; i++) {
                     for (var j = 0; j < data[i].data.length; j++) {
-                        if(data[i].name == '类项目数量') {
+                        if(data[i].name == '类项目数量') {
                             if(params.name == data[i].data[j].name) {
                                 counts = data[i].data[j].value
                             }
                         }
-                        if(data[i].name == '类项目规模') {
+                        if(data[i].name == '类项目规模') {
                             if(params.name == data[i].data[j].name) {
                                 scaleVal = data[i].data[j].value
                             }
@@ -917,8 +1235,8 @@ var vNode = {
                 }
                 var tip = '';
                 var area = counts && counts != '' ? params.name + '</br>' : '';
-                var count = counts &&  counts != '' ? '<span>类项目数量:' + counts  + '个</span></br>' : '';
-                var scale = scaleVal && scaleVal != '' ? '<span>类项目规模:' + scaleVal + '</span></br>' : '';
+                var count = counts &&  counts != '' ? '<span>类项目数量:' + counts  + '个</span></br>' : '';
+                var scale = scaleVal && scaleVal != '' ? '<span>类项目规模:' + scaleVal + '</span></br>' : '';
                 tip = area + count + scale;
                 return tip;
             }
@@ -976,7 +1294,13 @@ var vNode = {
         },
         // 存储页面数据
         savePageData: function(){
+            if(this.filterData.searchItem === 1) {
+              delete this.cacheImgData.group_buyerclass
+            } else if(this.filterData.searchItem === 2) {
+              delete this.cacheImgData.group_area
+            }
             var data = {
+                active: this.active,
                 cacheImgData: this.cacheImgData,
                 projectListDetail: this.projectListDetail,
                 defaultProjectDetail: this.defaultProjectDetail,
@@ -986,99 +1310,144 @@ var vNode = {
                 screenWidth: this.screenWidth,
                 year: this.year,
                 baseInfo: this.baseInfo,
-                scrollTop: this.$refs.wrapper.scrollTop
-            }
+                showListBtn: this.showListBtn,
+                scrollTop: this.$refs.wrapper.scrollTop,
+                filterData: this.filterData,
+                showListBtn: this.showListBtn,
+                showWinBtn: this.showWinBtn,
+                hotWinnerEnt: this.hotWinnerEnt,
+                historyExpert: this.historyExpert,
+                listCount: this.listCount,
+                isHaveTop: this.isHaveTop,
+                loadingEmpty: this.loadingEmpty
+                }
             // console.log(data)
-            sessionStorage.setItem('$data-analysis-result',JSON.stringify(data))
+            sessionStorage.setItem('searchItem', this.filterData.searchItem)
+            sessionStorage.setItem('$data-analysis-result_' + this.filterData.searchItem,JSON.stringify(data))
         },
         // 恢复页面数据
         restoreData:function(){
-            var $data = sessionStorage.getItem('$data-analysis-result')
+            const analysisFilterData = sessionStorage.getItem('analysis-filter-data')
+            if(analysisFilterData) {
+              this.id = ''
+            } else {
+              // 如果有id查询/bigmember/analysis/projectInfo
+              const id = utils.getParam('id')
+              if(id) {
+                this.id = id
+              }
+            }
+            const $data_searchItem = sessionStorage.getItem('searchItem')
+            var $data = sessionStorage.getItem('$data-analysis-result_' + $data_searchItem)
             if ($data) {
                 $data = JSON.parse($data)
+                this.isShow = $data.isShow
+                this.filterData = $data.filterData
+                if(this.filterData.searchItem === 1) {
+                  delete $data.cacheImgData.group_buyerclass
+                } else if(this.filterData.searchItem === 2) {
+                  delete $data.cacheImgData.group_area
+                }
                 this.cacheImgData = $data.cacheImgData || {}
                 this.projectListDetail = $data.projectListDetail
                 this.defaultProjectDetail = $data.projectListDetail
+                if($data.projectListDetail.length > 0) {
+                  this.isShow.showProjectList = true
+                } else {
+                  this.isShow.showProjectList = false
+                }
+                this.setProjectDetail()
                 this.skeletonShow = $data.skeletonShow
-                this.isShow = $data.isShow
                 this.minusRows = $data.minusRows
                 this.screenWidth = $data.screenWidth
                 this.year = $data.year
                 this.baseInfo = $data.baseInfo
+                this.showListBtn = $data.showListBtn
                 this.scrollTop = $data.scrollTop
+                this.showListBtn = $data.showListBtn
+                this.showWinBtn = $data.showWinBtn
+                this.hotWinnerEnt = $data.hotWinnerEnt
+                this.historyExpert = $data.historyExpert
+                this.listCount = $data.listCount
+                this.active = $data.active
+                this.isHaveTop = $data.isHaveTop
+                this.loadingEmpty = $data.loadingEmpty
                 var _this = this
                 this.$nextTick(function(){
-                  _this.$refs.wrapper.scrollTop = $data.scrollTop || 0
+                  setTimeout(() => {
+                    _this.$refs.wrapper.scrollTop = $data.scrollTop || 0
+                  }, 500)
                 })
                 this.initChartData()
-                sessionStorage.removeItem('$data-analysis-result')
+                this.disWinnerAmount(this.cacheImgData.winnerAmount);
+                this.disReviewExperts(this.cacheImgData.reviewExperts);
+                this.setInterSection()
+                // sessionStorage.removeItem('$data-analysis-result' + this.filterData.searchItem)
             }
             return !!$data
         },
-        goDetail (winner, buyer) {
-          this.active = 1
-          this.activeNames = ['1']
-          this.winnerVal = winner ? winner : ''
-          this.buyerVal = buyer ? buyer : ''
-          this.scrollTop = this.$refs.wrapper.scrollTop
-          if (buyer) {
-            this.getProjectDetail(0, winner, buyer)
-          } else {
-            this.getProjectDetail(0, winner)
+        goProDetail (data) {
+          if(data) {
+            this.filterData.winner = data.key
+            this.filterData.searchType = 2
           }
+          this.savePageData()
+          // sessionStorage.setItem('analysis_result_proDetail', JSON.stringify(this.defaultProjectDetail))
+          location.href = '/jyapp/big/page/bid_analysis_pro_list'
         },
         onTabClick (page) {
-          if (page == 1) {
-            var loading = this.showLoading()
-            var _this = this
-            setTimeout(function() {
-              _this.projectListDetail = _this.defaultProjectDetail
-              loading.clear()
-            }, 50)
-          } else {
-            var _this = this
-            this.$nextTick(function(){
-              _this.$refs.wrapper.scrollTop = this.scrollTop
-            })
-          }
-          this.activeNames = []
-          this.winnerVal = ''
-          this.buyerVal = ''
-        },
-        // 类似项目明细搜素
-        onSearch () {
-          if (!this.winnerVal && !this.buyerVal) return
-          if (this.winnerVal && this.buyerVal) {
-            this.getProjectDetail(0, this.winnerVal, this.buyerVal)
-          } else {
-            this.getProjectDetail(0, this.winnerVal, this.buyerVal)
-          }
-        },
-        // 跳转其他项目明细页面
-        goOtherDetail (winner, buyer) {
+          this.setModuleState()
+          // this.filterData.projectScope
+          // historyExpert.historyTabActive
           this.savePageData()
-          var data = {
-            area: this.areaData,
-            buyerContent: this.contentData,
-            buyerClass: this.buyerClassData,
-            minPrice: utils.deepCompare(this.moneyData, []) ? '' : Number(this.moneyData[0]),
-            maxPrice: Number(this.moneyData[1]) || '',
-            industry: this.industriesData ? this.formatterIndustryData(this.industriesData).toString() : '',
-            pname: this.project.projectName,
-            pid: this.project.pId,
-            sid: this.project.infoId,
-            buyer: this.project.buyer,
-            mobileModel: this.mobileModel,
-            appVersion: this.appVersion,
-            // 以下为新增
-            winner: winner,
-            searchType: 1
+          switch (page) {
+            case 0:
+              this.filterData.searchItem = 1
+              this.filterData.projectScope = 1
+              this.historyExpert.historyTabActive = 0
+              break;
+            case 1:
+              this.filterData.searchItem = 2
+              this.filterData.projectScope = 1
+              this.historyExpert.historyTabActive = 0
+              break;
+            case 2:
+              this.filterData.searchItem = 3
+              this.filterData.projectScope = 1
+              this.historyExpert.historyTabActive = 0
+              break;
+            default:
+              break;
           }
-          if (winner || buyer) {
-            sessionStorage.setItem('analysis_other_project', JSON.stringify(data))
-            location.href = "./free_other_project?winner=" + winner + '&buyer=' + buyer
+          sessionStorage.setItem('searchItem', this.filterData.searchItem)
+          const $data_searchItem = sessionStorage.getItem('searchItem')
+          if($data_searchItem) {
+            if(this.filterData.searchItem == $data_searchItem) {
+              const recover = this.restoreData()
+              if (!recover) {
+                this.setYearData()
+                this.getChartData()
+                this.getProjectWinnerEnt()
+                this.getProjectDetail()
+                this.getHistoryExpert()
+                setTimeout(() => {
+                  var targetEle = document.getElementById('analysis-tabs')
+                  targetEle.scrollIntoView()
+                  this.isHaveTop = false
+                }, 500)
+              }
+            } else {
+              this.setYearData()
+              this.getChartData()
+              this.getProjectWinnerEnt()
+              this.getProjectDetail()
+              this.getHistoryExpert()
+            }
           }
-        }
+          setTimeout(() => {
+            this.active = page
+          }, 200)
+        },
     }
 }
 var result = new Vue(vNode)

+ 6 - 6
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/chart_options.js

@@ -120,7 +120,7 @@ var chartOptions = {
                     top: 'middle',
                     style: {
                         fill: '#333',
-                        text: '类项目数量(个)',
+                        text: '类项目数量(个)',
                         font: '10px Microsoft YaHei'
                     }
                 }]
@@ -243,7 +243,7 @@ var chartOptions = {
             itemGap: 30,
         },
         series: [{
-            name: '类项目数量',
+            name: '类项目数量',
             type: 'heatmap',
             label: {
                 show: false
@@ -363,7 +363,7 @@ var chartOptions = {
         series: [
             {
                 type:'bar',
-                name:'类项目标书编制周期',
+                name:'类项目标书编制周期',
                 barWidth: 10,
                 barMaxWidth: 10,
                 itemStyle:{
@@ -425,7 +425,7 @@ var chartOptions = {
                         top: 'middle',
                         style: {
                             fill: '#333',
-                            text: '类项目标书编制周期',
+                            text: '类项目标书编制周期',
                             font: '11px Microsoft YaHei',
                             x: 8
                         }
@@ -778,7 +778,7 @@ var chartOptions = {
         series: {
             name: '半径模式',
             type: 'pie',
-            bottom:20,
+            bottom: 60,
             avoidLabelOverlap: true,
             stillShowZeroSum: false,
             radius:[2, '85%'],
@@ -790,7 +790,7 @@ var chartOptions = {
                 x:0,
                 y:1,
                 itemName: '行业',
-                value: "类项目规模", 
+                value: "类项目规模", 
             },
             labelLine: {
                 show:false

+ 13 - 13
src/jfw/modules/app/src/web/staticres/jyapp/big-member/js/contrast_trial.js

@@ -55,7 +55,7 @@ var CustomData = {
             sm: '利用招标大数据,结合项目知识工程,预测潜在新项目',
             merge: true,
             '预测采购项目': ['利用招标大数据,预测潜在项目的采购内容。', '2个'],
-            '类项目联系方式': ['提供类项目的联系人、联系方式等。', '2个'],
+            '类项目联系方式': ['提供类项目的联系人、联系方式等。', '2个'],
         },
         '中标企业预测': {
             sm: '通过大数据和AI技术,预测项目中标企业',
@@ -65,18 +65,18 @@ var CustomData = {
             '企业联系方式': ['提供企业的联系方式,一键可拨打联系人。', '2个'],
         },
         '投标决策分析': {
-            sm: '分析类项目,帮助企业决策是否投标或合作投标、以及投标报价金额等。',
-            '类项目动态': ['提供类项目的招标日期、招标截至日期、采购单位、代理机构、项目行业、金额等', '✅'],
-            '类项目筛选': ['通过项目行业、地区、采购内容、金额区间、采购单位类型筛选符合条件项目信息。', '✅'],
-            '类项目分析': ['通过大数据统计分析,提供近2-3年类项目数量、项目金额、涉及中标企业数量、涉及评标专家数量。', '✅'],
-            '类项目明细': ['提供类项目明细,包含项目的名称、采购方式、中标企业、评标专家、项目时间、预算、中标价、折扣率、中标候选人等。', '✅'],
-            '类项目采购历史': ['提供类项目的历史采购动态,项目名称、采购方式、时间等。', '✅'],
-            '类项目热点中标企业': ['根据类项目的历史中标数量、中标金额等综合评定企业竞争力,提供排名前十的企业。', '✅'],
-            '类项目标书编制周期发布': ['提供类项目的历史招标文件发放至投标截止时间(开标)时间间隔、项目数量,为投标人编制标书提供参考。', '✅'],
-            '类项目采购单位类型分布': ['提供采购规模排名前十的采购单位类型及规模占比、类项目规模、类项目数量、平均折扣率。', '✅'],
-            '类项目评标专家': ['通过大数据分析统计,提供类项目评标专家的频次排名。', '✅'],
-            '类项目区域分布': ['提供类项目的采购区域热度分布。', '✅'],
-            '类项目预算分布': ['提供类似采购项目的预算金额分布。', '✅'],
+            sm: '分析类项目,帮助企业决策是否投标或合作投标、以及投标报价金额等。',
+            '类项目动态': ['提供类项目的招标日期、招标截至日期、采购单位、代理机构、项目行业、金额等', '✅'],
+            '类项目筛选': ['通过项目行业、地区、采购内容、金额区间、采购单位类型筛选符合条件项目信息。', '✅'],
+            '类项目分析': ['通过大数据统计分析,提供近2-3年类项目数量、项目金额、涉及中标企业数量、涉及评标专家数量。', '✅'],
+            '类项目明细': ['提供类项目明细,包含项目的名称、采购方式、中标企业、评标专家、项目时间、预算、中标价、折扣率、中标候选人等。', '✅'],
+            '类项目采购历史': ['提供类项目的历史采购动态,项目名称、采购方式、时间等。', '✅'],
+            '类项目热点中标企业': ['根据类项目的历史中标数量、中标金额等综合评定企业竞争力,提供排名前十的企业。', '✅'],
+            '类项目标书编制周期发布': ['提供类项目的历史招标文件发放至投标截止时间(开标)时间间隔、项目数量,为投标人编制标书提供参考。', '✅'],
+            '类项目采购单位类型分布': ['提供采购规模排名前十的采购单位类型及规模占比、类项目规模、类项目数量、平均折扣率。', '✅'],
+            '类项目评标专家': ['通过大数据分析统计,提供类项目评标专家的频次排名。', '✅'],
+            '类项目区域分布': ['提供类项目的采购区域热度分布。', '✅'],
+            '类项目预算分布': ['提供类似采购项目的预算金额分布。', '✅'],
         }
     },
     '招标大数据服务': {

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

@@ -80,7 +80,7 @@ var staticData = [
                 b_gray_icon:'icon-gray-zhongbiaoxmfx',
                 b_gold_icon:'icon-gold-zhongbiaoxmfx',
                 b_high:'投标决策分析',
-                b_content:'分析类项目,帮助企业决策是否投标或合作投标、以及投标报价金额等。'
+                b_content:'分析类项目,帮助企业决策是否投标或合作投标、以及投标报价金额等。'
             }
         ]
     },

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

@@ -352,7 +352,7 @@ var competeData = [
         ]
     },
 ];
-// 类项目明细
+// 类项目明细
 var projectListDetail = [
     {
         "_id": "ABCY2FCZT0%2FOy87JHxhcHUJJzACHj1mZnB%2FPx4kNi9FaGdzcBlUCjQ%3D",

+ 239 - 0
src/jfw/modules/app/src/web/staticres/jyapp/dataSmt/css/index.css

@@ -0,0 +1,239 @@
+ul,li{
+    list-style: none;
+    padding:0;
+    margin:0;
+}
+.data-sam-main{
+    overflow-y:hidden ;
+}
+.header-banner{
+    position: relative;
+}
+.bottom-handle-box{
+    position: absolute;
+    bottom: 0;
+    z-index:1;
+    background: #fff;
+    height: 1.32rem;
+    width: 100%;
+    padding:  .16rem .32rem .24rem .32rem;
+}
+.bottom-handle-box .confirm-btn{
+    height: .92rem;
+    border-radius: 8px;
+    background: #2ABED1;
+    text-align: center;
+    font-size: .36rem;
+    line-height: .92rem;
+    color: #fff;
+}
+.fixed{
+    position: fixed;
+    bottom: 0;
+}
+/*bannner部分*/
+.header-box{
+    position: absolute;
+    bottom: 0.88rem;
+    padding: 0 0.58rem;
+}
+.header-box .supermarket-img{
+    height: 0.64rem;
+}
+.header-banner-img{
+    width:100%;
+}
+.header-box .sub-description {
+    color: #5F5E64;
+    font-size:0.24rem;
+    line-height:.4rem;
+    margin: .16rem 0;
+    width:4.16rem;
+}
+.header-box .example-list li{
+   float: left;
+    min-width: 2.08rem;
+    display: flex;
+    align-items: center;
+    color: #1D1D1D;
+    font-size: .28rem;
+    margin-bottom: .16rem;
+    text-align: left;
+}
+.header-box .example-list img{
+    width:.32rem;
+    height:.32rem;
+    margin-right: .08rem;
+}
+.header-box .example-list  li:nth-of-type(2n-1) {
+    margin-right: .64rem;
+}
+.content-container{
+    position: relative;
+}
+/*搜索框*/
+.section-search-com{
+    position: absolute;
+    top: -0.48rem;
+    padding: 0 .48rem;
+}
+.search-component{
+    width: 6.54rem;
+    height: .96rem;
+    box-shadow: 0 .04rem .16rem 0 rgba(54, 147, 179, 0.05);
+    border-radius: 8px;
+    background:#fff;
+    display: flex;
+    align-items: center;
+    padding: .24rem;
+}
+.search-component input{
+    height: .52rem;
+    margin-left: .16rem;
+    width: 100%;
+    font-size:.28rem;
+}
+/*条件选择模块*/
+.select-component{
+    margin-top: .96rem;
+    padding: 0 .24rem 0 .48rem;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    font-size: .28rem;
+
+}
+.select-component .cell-left .data-type{
+    color: #2ABED1;
+    margin: .24rem .08rem;
+}
+.select-component .cell-right{
+     color: #2ABED1;
+}
+.select-component .cell-right span:nth-of-type(1) {
+    text-decoration: underline;
+}
+.select-component .cell-right .icon-help1{
+    width: .32rem;
+    height: .32rem;
+    margin-left:.08rem;
+}
+.select-component .cell-left, .select-component .cell-right{
+    display: flex;
+    align-items: center;
+}
+
+.icon-search::before{
+    content: ''
+}
+.icon-duihao {
+    display: flex;
+    width: 0.48rem;
+    height: 0.48rem;
+    color: #2ABED1;
+    font-size: .48rem;
+}
+.icon-youbian{
+    color: #C0C4CC;
+    width: 0.22rem;
+    height: .32rem;
+}
+
+.custom-pop .pop-title{
+    height: 1.28rem;
+    font-size: .4rem;
+    line-height: 1.28rem;
+    padding-left: .36rem;
+    color: #171826;
+}
+.custom-pop .pop-content{
+    height: 7rem;
+    overflow-y: auto;
+}
+.custom-pop .van-cell{
+    padding: 15px 16px 13px 16px;
+    font-size: .32rem;
+}
+.van-popup__close-icon{
+    font-size: .32rem;
+}
+.van-popup__close-icon--top-right{
+    top: .46rem;
+}
+.explain-pop .van-cell{
+    font-weight: bold;
+    padding-top:8px;
+    padding-bottom:8px;
+}
+.explain-pop .van-cell .van-cell__label{
+    color: #5F5E64;
+    font-size:.28rem;
+    font-weight: normal;
+    line-height: .4rem;
+    margin-top: 8px;
+}
+
+/*数据列表*/
+.list-component.j-container{
+    height: calc(100vh - 8.56rem);
+    min-height: 45%;
+}
+.list-component .j-main{
+    /*min-height: 45%;*/
+    padding: 0 .24rem;
+    margin-bottom: .24rem;
+}
+.list-component .list-row{
+    background: #fff;
+    margin-top: .24rem;
+    padding: .48rem .24rem;
+    border-radius: .16rem;
+    position: relative;
+}
+.list-component .label-info{
+    color: #171826;
+    font-size: .3rem;
+    line-height: .48rem;
+}
+.corner-mark{
+    position: absolute;
+    left:0;
+    top:0;
+    display: inline-flex;
+    padding: 1px 12px;
+    flex-direction: column;
+    align-items: center;
+    border-radius: 8px 0;
+    background: linear-gradient(135deg, #FC6 0%, #FF9F40 100%);
+    color: #fff;
+    text-align: center;
+    text-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.15);
+    font-size: .28rem;
+    line-height: .36rem;
+
+}
+.corner-color-1, .corner-color-6{
+    background: linear-gradient(135deg, #FC6 0%, #FF9F40 100%);
+}
+.corner-color-2, .corner-color-5{
+    background: linear-gradient(315deg, #39F 0%, #00D1FF 100%);
+}
+.corner-color-3{
+    background: linear-gradient(135deg, #0BD991 0%, #00B031 100%);
+}
+.corner-color-4{
+    background: linear-gradient(315deg, #1DB5E5 0%, #2ABED1 100%);
+}
+.list-component .row-tags{
+    margin-top: .16rem;
+    color: #5F5E64;
+    font-size: .24rem;
+}
+.list-component .tag-item{
+    padding: 1px 8px;
+    border-radius: 4px;
+    border: 0.5px solid rgba(0, 0, 0, 0.05);
+    background: #F7F9FA;
+}
+
+

二进制
src/jfw/modules/app/src/web/staticres/jyapp/dataSmt/images/data-market-text.png


二进制
src/jfw/modules/app/src/web/staticres/jyapp/dataSmt/images/header-banner.png


二进制
src/jfw/modules/app/src/web/staticres/jyapp/dataSmt/images/icon-1.png


+ 102 - 0
src/jfw/modules/app/src/web/staticres/jyapp/dataSmt/js/index.js

@@ -0,0 +1,102 @@
+
+$(function () {
+})
+function searchFocus () {
+  location.replace('/jyapp/datasmt/list')
+}
+var vNode = {
+  el: '#select-component',
+  delimiters: ['${', '}'],
+  data: {
+    showDataType: false,
+    dataType: 0,
+    selectType: 0,
+    typeList: [
+      {
+        label: '全部',
+        value: 0
+      },
+      {
+        label: '采购意向',
+        value: 1
+      },
+      {
+        label: '拟建项目',
+        value: 2
+      },
+      {
+        label: '招标数据',
+        value: 3
+      },
+      {
+        label: '中标数据',
+        value: 4
+      },
+      {
+        label: '企业工商数据',
+        value: 5
+      },
+      {
+        label: '中标单位数据',
+        value: 6
+      },
+      {
+        label: '采购单位数据',
+        value: 7
+      }
+    ],
+    showExplain: false,
+    explainList: [
+      {
+        title: '采购意向',
+        label: '匹配关键词、省份、城市、公告标题、公告类别、公告内容、发布时间、公告地址、剑鱼标讯地址、项目名称、项目范围、预算金额、采购单位名称'
+      },
+      {
+        title: '拟建项目',
+        label: '匹配关键词、省份、城市、区县、公告标题、公告类别、公告内容、发布时间、公告地址、剑鱼标讯地址、项目名称、总投资、业主单位、建设规模(内容)、建设地点、竣工时间、开工时间、项目类型(申报方式)、审批结果'
+      },
+      {
+        title: '招标数据',
+        label: '匹配关键词、省份、城市、区县、公告标题、公告类别、公告内容、发布时间、公告地址、剑鱼标讯地址、项目名称、项目编号、项目范围、预算金额、报名截止日期、开标日期、投标截止日期、采购单位信息(采购单位名称、采购单位联系人、采购单位联系电话、采购单位地址)、招标代理机构'
+      },
+      {
+        title: '中标数据',
+        label: '匹配关键词、省份、城市、区县、公告标题、公告类别、公告内容、发布时间、公告地址、剑鱼标讯地址、项目名称、项目编号、项目范围、预算金额、中标金额、报名截止日期、开标日期、投标截止日期、采购单位信息(采购单位名称、采购单位联系人、采购单位联系电话、采购单位地址)、招标代理机构、中标单位信息(中标单位名称、中标单位联系人、中标单位联系电话)(来源:招标公告网站)、中标单位信息(中标单位联系人、中标单位联系电话、电子邮箱)(来源:国家企业公示网站)'
+      },
+      {
+        title: '企业工商数据',
+        label: '企业名称、曾用名、登记状态、企业类型、经营范围、法定代表人、注册资本、统一社会信用代码、纳税人识别号、注册号、组织机构代码、成立日期、登记机关、核准日期、所属省份、所属城市、所属区县、企业电话、企业地址、企业邮箱、人员规模'
+      },
+      {
+        title: '中标单位数据',
+        label: '中标单位、统一信用代码、省份、城市、区县、经营范围、招标信息通讯录(联系人、联系方式、地址)、近3年中标项目规模、近3年中标项目数量、业务覆盖区域、客户群体、TOP5客户信息(客户名称、客户所在省份、客户所在城市、客户分类、中标金额)'
+      },
+      {
+        title: '采购单位数据',
+        label: '采购单位、统一信用代码、单位类别、省份、城市、区县、经营范围、招标信息通讯录(联系人、联系方式、地址)、近3年招标项目规模、近3年招标项目数量、TOP5中标单位信息(中标单位名称、中标单位所在省份、中标单位所在城市、合作金额)'
+      }
+    ]
+  },
+  computed: {
+    typeText () {
+       var obj = this.typeList.find(item => {
+        return item.value === this.dataType
+      })
+      return obj ? obj.label : '全部'
+    }
+  },
+  methods: {
+    showTypeHandle () {
+      this.selectType = this.dataType
+      this.showDataType = true
+    },
+    changeDataType (item) {
+      this.selectType = item.value
+    },
+    typeConfirmHandle () {
+      this.dataType = this.selectType
+      this.showDataType = false
+    }
+  }
+}
+var auth = new Vue(vNode)

二进制
src/jfw/modules/app/src/web/staticres/jyapp/wxswordfish/images/share-icon.png


二进制
src/jfw/modules/app/src/web/staticres/jyapp/wxswordfish/images/share-page.png


+ 35 - 2
src/jfw/modules/app/src/web/templates/big-member/page_ai_add.html

@@ -368,6 +368,13 @@
                 this.firstSearch()
             }
             this.initPurchaseList();
+            // 从投标决策分析跳转过来
+            if(utils.getParam('fromType') == 'analysis') {
+              let analysisFilterData = sessionStorage.getItem('analysis-filter-data')
+              if(analysisFilterData) {
+                this.analysisFilterData = JSON.parse(analysisFilterData)
+              }
+            }
             // var searchData = JSON.parse(sessionStorage.getItem('big-ai-search'));
             var addCont = JSON.parse(sessionStorage.getItem('big-ai-add-data'))
             if(addCont) {
@@ -406,6 +413,12 @@
             },
             // 封装预测查询方法(首次查询参数传空、点击查询参数不能为空)
             forecastFn: function(data){
+                const id = utils.getParam('id')
+                const sid = utils.getParam('sId')
+                if(id || sid) {
+                  data.id = id
+                  data.infoid = sid
+                }
                 var that = this;
                 $.ajax({
                     type:'POST',
@@ -589,6 +602,19 @@
             getFilterData: function(){
                 var history = JSON.parse(localStorage.getItem('BIG_AI_LIST'))
                 var that = this;
+                var anaBuyerContent = []
+                var anaBuyer = ''
+                if(that.analysisFilterData.buyerContent) {
+                  anaBuyerContent = that.analysisFilterData.buyerContent.reduce((acc, item) => acc.concat(item.key), []).flat();
+                }
+                if(that.analysisFilterData.filters) {
+                  if(that.analysisFilterData.filters.buyer) {
+                    anaBuyer = that.analysisFilterData.filters.buyer
+                  }
+                  if(that.analysisFilterData.filters.pname) {
+                    that.project.pName = that.analysisFilterData.filters.pname
+                  }
+                }
                 $.ajax({
                     type:'POST',
                     url:'/bigmember/analysis/projectInfo',
@@ -612,11 +638,15 @@
                                         if(that.project.pName == ele.projectname) {
                                             if(ele.purchaseList){
                                                 that.purchaseList = ele.purchaseList
+                                            } else if(anaBuyerContent.length > 0) {
+                                              that.getApiData('content', anaBuyerContent);
                                             } else {
                                                 that.getApiData('content',res.data.purchasing);
                                             }
                                             if(ele.buyer) {
                                                 that.formData.buyer = ele.buyer
+                                            } else if(anaBuyer) {
+                                              that.getApiData('buyer', anaBuyer)
                                             } else {
                                                 that.getApiData('buyer',res.data.buyer)
                                             }
@@ -643,6 +673,11 @@
                                             that.getApiData('area',res.data.area)
                                         }
                                     }
+                                } else if(that.analysisFilterData) {
+                                  that.getApiData('content', anaBuyerContent);
+                                  that.getApiData('buyer', anaBuyer)
+                                  that.getApiData('budget',res.data.budget)
+                                  that.getApiData('area',res.data.area)
                                 } else {
                                     // 2. 读接口中的数据
                                     that.getApiData('content',res.data.purchasing);
@@ -658,8 +693,6 @@
                                     }
                                 });
                             }
-                        }else{
-                            // that.$toast(res.error_msg)
                         }
                     },
                     error:function(err) {

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

@@ -85,7 +85,7 @@
         <div class="a-header">${project.projectName}</div>
         <div class="a-filter">
             <div class="filter-title">
-                <span>类项目筛选条件</span>
+                <span>类项目筛选条件</span>
             </div>
             <div class="filter-content">
                 <van-cell  @click="toSetPage('industry')" :value-class="currentVal.industry == '请选择行业' ? '' : 'cur-value'" title="行业" is-link :value="currentVal.industry" ></van-cell>

+ 299 - 223
src/jfw/modules/app/src/web/templates/big-member/page_analysis_result.html

@@ -16,6 +16,8 @@
     <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=//cdn-common.jianyu360.com/cdn/lib/v-charts/1.19.0/style.min.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}}/common-module/analysis-filter/css/analysis-filter.css?v={{Msg "seo" "version"}}' />
     <link rel="stylesheet" href='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/css/analysis_result.css?v={{Msg "seo" "version"}}' />
     <!--E-当前页面的css资源-->
 </head>
@@ -24,18 +26,18 @@
     {{include "/big-member/header.html"}}
     <div class="j-main" id="analysis-result" v-cloak ref="wrapper">
         <!-- 骨架屏 -->
-        <div class="skeleton" v-if="skeletonShow">
+        <!-- <div class="skeleton" v-if="skeletonShow">
             <img class="working" src="/jyapp/big-member/image/working.gif" alt="">
-        </div>
-        <div v-else>
-            <div class="result-top">
+        </div> -->
+        <div>
+          <div class="head-tip">分析同类项目,优化投标分析流程,提高企业投标决策效率</div>
+            <!-- <div class="result-top">
                 <div class="project-name">${baseInfo.projectname}</div>
                 <div class="project-date">
                     <span>招标日期:${baseInfo.zbtime || '--'}</span>
                     <span>招标截至日期:${baseInfo.bidopentime || '--'}</span>
                 </div>
                 <div>
-                    <!-- <p class="region-item">地区:${project.region}</p> -->
                     <p class="unit-item">
                         <span>采购单位:<a class="buyer" v-if="baseInfo.buyer" @click="goUnitImage(baseInfo.buyer)">${baseInfo.buyer}</a> <em v-else>--</em></span>
                     </p>
@@ -56,242 +58,314 @@
                         <span>中标预测 </span>
                     </div>
                 </div>
-            </div>
+            </div> -->
             <div class="filter">
                 <div class="filter-title">
-                    <span>类似项目筛选条件</span>
+                    <span>分析条件</span>
                 </div>
-                <div class="filter-content">
+                <!-- <div class="filter-content">
                     <van-cell @click="setBack" :value-class="currentVal.industry == '请选择行业' ? '' : 'cur-value'" title="行业" is-link :value="currentVal.industry" ></van-cell>
                     <van-cell @click="setBack" :value-class="currentVal.region == '请选择地区' ? '' : 'cur-value'" title="地区" is-link :value="currentVal.region"></van-cell>
                     <van-cell @click="setBack" :value-class="currentVal.content == '请选择采购内容' ? '' : 'cur-value'" title="采购内容" is-link :value="currentVal.content" ></van-cell>
                     <van-cell @click="setBack" :value-class="currentVal.money == '请选择金额区间' ? '' : 'cur-value'" title="金额区间" is-link :value="currentVal.money" ></van-cell>
                     <van-cell  @click="setBack" :value-class="currentVal.buyerClass == '请选择采购单位类型' ? '' : 'cur-value'" title="采购单位类型" is-link :value="currentVal.buyerClass" ></van-cell>
-                </div>
+                </div> -->
+                <analysis-com @action="getBaseInfo" @click="setAjaxFilters" :id="id"></analysis-com>
             </div>
             <div class="contents">
                 <div class="tabs" ref="backTop">
-                    <van-tabs v-model="active" background="#fff" title-active-color="#2ABED1" line-width="24" sticky offset-top="21.33333vw" @click="onTabClick">
-                        <van-tab title="类似项目分析">
-                            <div class="tab-item">
-                                <div class="summary">
-                                    <div class="summary-container">
-                                        <div class="summary-item">
-                                            <span>项目数量</span>
-                                            <span v-if="cacheImgData.all_counts">${cacheImgData.all_counts}个</span>
-                                            <span v-else>--</span>
-                                        </div>
-                                        <div class="summary-item">
-                                            <span>项目金额</span>
-                                            <span v-if="cacheImgData.all_money">${formatterMoney(cacheImgData.all_money)}</span>
-                                            <span v-else>--</span>
-                                        </div>
-                                        <div class="summary-item">
-                                            <span>涉及中标企业</span>
-                                            <span v-if="cacheImgData.all_winners">${cacheImgData.all_winners}个</span>
-                                            <span v-else>--</span>
-                                        </div>
-                                        <div class="summary-item">
-                                            <span>涉及评标专家</span>
-                                            <span v-if="cacheImgData.all_review_experts">${cacheImgData.all_review_experts}人</span>
-                                            <span v-else>--</span>
-                                        </div>
-                                    </div>
-                                    <div class="summary-tip">
-                                        <p class="van-hairline--top">数据统计范围:${year}/01/01 至今</p>
-                                    </div>
-                                </div>
-                                <div class="a-item purchase-history" v-show="isShow.showHistory">
-                                    <p class="a-title ">${baseInfo.buyer}类似项目采购历史</p>
-                                    <div class="history-content">
-                                        <div class="d_list" v-for="(item,index) in showHistoryList" @click="goBuyerDetail(item.infoid)">
-                                            <p class="i_title">${item.projectname}</p>
-                                            <div class="i_info">
-                                                <p class="area_type">
-                                                    <span v-if="item.area" class="i_area">${item.area}</span>
-                                                    <span v-if="item.bidstatus" class="i_type">${item.bidstatus}</span>
-                                                    <span v-if="item.bidamount" class="i_type">${formatterMoney(item.bidamount)}</span>
-                                                </p>
-                                                <p class="i_time">${item.firsttime}</p>
-                                            </div>
-                                        </div>
-                                        <div v-if="historyList.length > 3 && !showAll">
-                                            <div class="more">
-                                                <span @click="showAll = true">查看更多</span>
-                                            </div>
-                                        </div>
-                                    </div>
-                                </div>
-                                <div class="a-item hot-win" v-show="isShow.showWinner">
-                                    <p class="a-title">类似项目热点中标企业</p>
-                                    <div class="win-content">
-                                        <div class="van-hairline--bottom win-list" v-for="(hs,i) in hotWin" :key="i">
-                                            <div class="win-name">
-                                                <span v-if="i === 0" class="index first-index">${i + 1}</span>
-                                                <span v-else-if="i === 1" class="index second-index">${i + 1}</span>
-                                                <span v-else-if="i === 2" class="index third-index">${i + 1}</span>
-                                                <span v-else class="index">${i + 1}</span>
-                                                <span class="title" @click="goEntImg(hs.entId)">${hs.key}</span>
-                                            </div>
-                                            <div class="win-capital">注册资本:${formatterMoney(hs.capital)}</div>
-                                            <div class="win-info" @click="goDetail(hs.key)">
-                                              <div class="w-title">
-                                                <span class="w-title-label">类似项目明细</span>
-                                                <van-icon class="win-arrow" name="arrow"></van-icon>
-                                              </div>
-                                              <div class="company-info">
-                                                <span>项目数量:${hs.doc_count}个</span>
-                                                <span>项目金额:${formatterMoney(hs.total_project)}</span>
-                                                <!-- <span>注册资本:${formatterMoney(hs.capital)}</span> -->
-                                                <span>最近中标:${formatterTime(hs.max_jytime)}</span>
-                                              </div>
-                                            </div>
-
-                                            <div class="same-history" v-if="hs.buyer_similar_list.doc_count > 0 || hs.buyer_similar_list.total_project > 0" @click="goDetail(hs.key, hs.buyer_similar_list.buyer)">
-                                                <div class="same-title">
-                                                  <span>与${hs.buyer_similar_list.buyer}有<em class="highLight">类似项目</em>合作历史</span>
-                                                  <van-icon class="win-arrow" name="arrow"></van-icon>
-                                                </div>
-                                                <div class="same-info">
-                                                    <span>项目数量:${hs.buyer_similar_list.doc_count}个</span>
-                                                    <span>项目金额:${formatterMoney(hs.buyer_similar_list.total_project)}</span>
-                                                    <span>最近中标:${hs.buyer_similar_list.bid_winner_time || '--'}</span>
-                                                </div>
-                                            </div>
-                                            <div class="other-history" v-if="hs.buyer_other_list.doc_count > 0 || hs.buyer_other_list.total_project > 0" @click="goOtherDetail(hs.key, hs.buyer_similar_list.buyer)">
-                                                <div class="other-title">
-                                                  <span>与${hs.buyer_other_list.buyer}有<em class="highLight">其他项目</em>合作历史</span>
-                                                  <van-icon class="win-arrow" name="arrow"></van-icon>
-                                                </div>
-                                                <div class="other-info">
-                                                    <span>项目数量:${hs.buyer_other_list.doc_count}个</span>
-                                                    <span>项目金额:${formatterMoney(hs.buyer_other_list.total_project)}</span>
-                                                    <span>最近中标:${hs.buyer_other_list.bid_winner_time || '--'}</span>
-                                                </div>
-                                            </div>
-                                        </div>
-                                    </div>
-                                </div>
-                                <!-- 类似项目标书编制周期分布 -->
-                                <div class="a-item" v-show="isShow.bidCycle">
-                                    <p class="a-title">类似项目标书编制周期分布</p>
-                                    <div class="much-bar">
-                                        <div style="padding: 0 12px;font-size: 10px;color: #9B9CA3;line-height: 14px;">类似项目数量(个)</div>
-                                        <ve-histogram ref="histogram" :init-options="initRendererSvg" @ready="onBarReady($event, name)" height="300px" :mark-point="barChartMarkPoint" :after-config="barChartConfig" :data="barChartData" :settings="chartSettings" :extend="chartOptions.barChart"></ve-histogram>
-                                    </div>
-                                    <div class="bar-tip">注:标书编制周期是指招标文件发放之日至投标截止时间(开标)之间的时间间隔,标书编制周期越长,准备时间越充分。</div>
-                                </div>
-                                <!-- 类似项目预算分布 -->
-                                <div class="a-item" v-show="isShow.showHotMap">
-                                    <p class="a-title">类似项目预算分布</p>
-                                    <div class="hot-map">
-                                        <div id="myChart" ref="hotChart" :style="{height: heatMapHeight}"></div>
-                                    </div>
-                                    <div class="bar-tip">注:少数缺失的项目预算,用中标金额补充;平均折扣率=(全部项目预算-全部中标金额)/全部项目预算,仅统计预算和中标金额同时存在的项目。</div>
-                                </div>
-                                <!-- 类似项目区域分布 -->
-                                <div class="a-item" v-show="isShow.showMap">
-                                    <p class="a-title">类似项目区域分布</p>
-                                    <div class="map">
-                                        <ve-map
-                                            ref="mapRef"
-                                            :init-options="initRendererSvg"
-                                            :width="mapWidth"
-                                            height="400px"
-                                            :after-config="mapConfig"
-                                            :data="mapChartData"
-                                            :settings="mapSettings.chartSettings"
-                                            :extend="mapSettings.chartExtend">
-                                        </ve-map>
-                                    </div>
-                                </div>
-                                <!-- 类似项目采购单位类型分布 -->
-                                <div class="a-item" v-show="isShow.showPie">
-                                    <p class="a-title">类似项目采购单位类型分布</p>
-                                    <div class="pieChart">
-                                        <div ref="pieChart" style="height: 360px;"></div>
-                                    </div>
-                                    <div class="bar-tip">注:各采购单位类型占比以采购规模来计算,最多展示占比排名前十的采购单位类型。</div>
-                                </div>
-                                <!-- 类似项目评标专家 -->
-                                <div class="a-item ranking" v-show="isShow.showExperts">
-                                    <p class="a-title">类似项目评标专家</p>
-                                    <p style="padding:0 .32rem;font-size: .18rem;color:#9B9CA3;text-align: right;line-height: .28rem;">参评项目数量(个)</p>
-                                    <div class="progress-bar-container">
-                                        <div class="progress-bar-item" v-for="(item,index) in expertWinArr" :key="index">
-                                            <div class="item-label">
-                                                <span class="item-name">${item.key}</span>
-                                                <span class="item-count">${item.doc_count}个</span>
-                                            </div>
-                                            <div class="item-progress">
-                                                <span class="item-progress-count blue-progress" :style="{width: item.parent}"></span>
-                                            </div>
-                                        </div>
-                                    </div>
+                    <div :style="setHeightActive" :class="{'setTop': isHaveTop}" v-if="isHaveTop">
+                      <van-tabs v-if="listCount.pCount !== 0" v-model="active" background="#fff" title-active-color="#2ABED1" line-width="24" @click="onTabClick">
+                          <van-tab title="采购单位">
+                          </van-tab>
+                          <van-tab :title="filterData.area">
+                          </van-tab>
+                          <van-tab title="全国">
+                          </van-tab>
+                      </van-tabs>
+                    </div>
+                    <div id="analysis-tabs" ref="analysisTab">
+                      <van-tabs v-if="listCount.pCount !== 0" v-model="active" background="#fff" title-active-color="#2ABED1" line-width="24" @click="onTabClick">
+                          <van-tab title="采购单位">
+                          </van-tab>
+                          <van-tab :title="filterData.area">
+                          </van-tab>
+                          <van-tab title="全国">
+                          </van-tab>
+                      </van-tabs>
+                    </div>
+                    <div class="tab-item" v-if="listCount.pCount !== 0">
+                      <div class="summary" v-if="isShow.showSummary">
+                          <div class="filter-title">
+                              <span>同类项目分析</span>
+                          </div>
+                          <div class="summary-container">
+                              <div class="summary-item">
+                                  <span>项目数量</span>
+                                  <span v-if="cacheImgData.all_counts">${cacheImgData.all_counts}个</span>
+                                  <span v-else>--</span>
+                              </div>
+                              <div class="summary-item">
+                                  <span>项目金额</span>
+                                  <span v-if="cacheImgData.all_money">${formatterMoney(cacheImgData.all_money)}</span>
+                                  <span v-else>--</span>
+                              </div>
+                              <div class="summary-item">
+                                  <span>涉及中标企业</span>
+                                  <span v-if="cacheImgData.all_winners">${cacheImgData.all_winners}个</span>
+                                  <span v-else>--</span>
+                              </div>
+                              <div class="summary-item">
+                                  <span>涉及评标专家</span>
+                                  <span v-if="cacheImgData.all_review_experts">${cacheImgData.all_review_experts}人</span>
+                                  <span v-else>--</span>
+                              </div>
+                          </div>
+                          <div class="summary-tip">
+                              <p class="van-hairline--top">数据统计范围:${year}至今</p>
+                          </div>
+                      </div>
+                      <div class="projects" v-if="isShow.showProjectList">
+                        <div class="filter-title">
+                            <span>同类项目明细</span>
+                        </div>
+                        <div v-for="item in setShowListBtn" :key="item._id" class="project-list">
+                            <div class="pl-title" @click="goProjectDetail(item.infoid)">${item.projectname}</div>
+                            <div class="pl-tags">
+                              <span v-if="item.area">${item.area}</span>
+                              <span v-if="item.subtype">${item.subtype}</span>
+                              <span v-if="item.buyerclass">${item.buyerclass}</span>
+                              <span v-if="item.bidamount || item.budget">${item.bidamount || item.budget}万元</span>
+                            </div>
+                            <div class="pl-info can-click" @click="goUnitImage(item.buyer)">
+                                <span>采购单位:</span>
+                                <span>${item.buyer || '--'}</span>
+                            </div>
+                            <div class="pl-info">
+                                <span>预算金额:</span>
+                                <span>${item.budget || '--'}${item.budget ? '万元' : ''}</span>
+                            </div>
+                            <div class="pl-info can-click">
+                                <span>中标单位:</span>
+                                <div class="winner-list">
+                                  <span  @click="goEntImg(winner.id)" v-for="winner in item.s_winner" :key="winner.id">${winner.name}</span> 
                                 </div>
                             </div>
-                        </van-tab>
-                        <van-tab title="类似项目明细">
-                            <div class="detail-filter" ref="detailFilter">
-                              <van-collapse v-model="activeNames">
-                                <van-collapse-item title="筛选条件" name="1">
-                                  <van-field class="filter-input" v-model="winnerVal" label="中标企业" placeholder="输入中标企业名称" maxlength="50"></van-field>
-                                  <van-field class="filter-input" v-model="buyerVal" label="采购单位" placeholder="输入采购单位名称" maxlength="50"></van-field>
-                                  <div class="d-f-search">
-                                    <span @click="onSearch">搜索</span>
+                            <div class="pl-info">
+                                <span>中标金额:</span>
+                                <span>${item.bidamount || '--'}${item.bidamount ? '万元' : ''}</span>
+                            </div>
+                            <div class="pl-info">
+                                <span>评标专家:</span>
+                                <span>${item.review_experts || '--'}</span>
+                            </div>
+                            <div class="pl-info">
+                                <span>成交时间:</span>
+                                <span>${item.jgtime || '--'}</span>
+                            </div>
+                        </div>
+                        <div class="more" v-if="showListBtn" @click="setViewMore()">
+                          <span>查看更多</span>
+                        </div>
+                      </div>
+                      <!-- <div class="a-item purchase-history" v-show="isShow.showHistory">
+                          <div class="filter-title">
+                            <span>${baseInfo.buyer}同类项目采购历史</span>
+                          </div>
+                          <div class="history-content">
+                              <div class="d_list" v-for="(item,index) in showHistoryList" @click="goBuyerDetail(item.infoid)">
+                                  <p class="i_title">${item.projectname}</p>
+                                  <div class="i_info">
+                                      <p class="area_type">
+                                          <span v-if="item.area" class="i_area">${item.area}</span>
+                                          <span v-if="item.bidstatus" class="i_type">${item.bidstatus}</span>
+                                          <span v-if="item.bidamount" class="i_type">${formatterMoney(item.bidamount)}</span>
+                                      </p>
+                                      <p class="i_time">${item.firsttime}</p>
+                                  </div>
+                              </div>
+                              <div v-if="historyList.length > 3 && !showAll">
+                                  <div class="more">
+                                      <span @click="showAll = true">查看更多</span>
                                   </div>
-                                </van-collapse-item>
-                              </van-collapse>
+                              </div>
+                          </div>
+                      </div> -->
+                      <div class="a-item hot-win" v-if="isShow.showWinner">
+                          <div class="filter-title">
+                            <span>同类项目热点中标企业TOP10</span>
+                            <div class="switchTab">
+                              <span class="switch_label">排序:</span>
+                              <div :class="{'textColor': hotWinnerEnt.hotTabActive==0}" class="switch-tab" @click="onTabWinnerClick(0)">
+                                <span>中标金额</span>
+                                <div v-if="hotWinnerEnt.hotTabActive==0" class="line"></div>
+                              </div>
+                              <div :class="{'textColor': hotWinnerEnt.hotTabActive==1}" class="switch-tab" @click="onTabWinnerClick(1)">
+                                <span>中标数量</span>
+                                <div v-if="hotWinnerEnt.hotTabActive==1" class="line"></div>
+                              </div>
+                              <!-- <van-tabs class="switch_tab_list" :class="'winner_' + hotWinnerEnt.hotTabActive" v-model:active="hotWinnerEnt.hotTabActive" @click="onTabWinnerClick">
+                                <van-tab title="中标金额"></van-tab>
+                                <van-tab title="中标数量"></van-tab>
+                              </van-tabs> -->
                             </div>
-                            <div class="tab-item">
-                                <div class="projects" v-if="projectListDetail.length && projectListDetail.length > 0">
-                                    <div v-for="item in projectListDetail" :key="item._id" class="project-list" @click="goProjectDetail(item.infoid)">
-                                        <div class="pl-title">${item.projectname}</div>
-                                        <div class="pl-info">
-                                            <span>采购方式:</span>
-                                            <span>${item.bidtype || '--'}</span>
-                                        </div>
-                                        <div class="pl-info">
-                                            <span>中标企业:</span>
-                                            <span>${item.s_winner || '--'}</span>
-                                        </div>
-                                        <div class="pl-info">
-                                            <span>评审专家:</span>
-                                            <span>${item.review_experts || '--'}</span>
-                                        </div>
-                                        <div class="pl-info">
-                                            <span>项目时间:</span>
-                                            <span>${item.firsttime || '--'}</span>
-                                        </div>
-                                        <div class="pl-price">
-                                            <div class="price-item">
-                                                <span>预算 (万元)</span>
-                                                <span>${item.budget || '--'}</span>
-                                            </div>
-                                            <div class="price-item">
-                                                <span>中标价 (万元)</span>
-                                                <span>${item.bidamount || '--'}</span>
-                                            </div>
-                                            <div class="price-item">
-                                                <span>折扣率</span>
-                                                <span>${item.project_rate || '--'}</span>
-                                            </div>
-                                        </div>
-                                        <div class="bid-company" v-if="item.winnerorder">
-                                            <p>中标候选人:</p>
-                                            <p v-for="sItem in item.winnerorder">
-                                                ${sItem || '--'}
-                                            </p>
-                                        </div>
+                        </div>
+                          <div class="win-content">
+                              <div class="van-hairline--bottom win-list" v-for="(hs,i) in isShowWinBtn" :key="i">
+                                  <div class="win-name" @click="goEntImg(hs.entId)">
+                                      <span v-if="i === 0" class="index first-index">${i + 1}</span>
+                                      <span v-else-if="i === 1" class="index second-index">${i + 1}</span>
+                                      <span v-else-if="i === 2" class="index third-index">${i + 1}</span>
+                                      <span v-else class="index">${i + 1}</span>
+                                      <span class="title">${hs.key}</span>
+                                  </div>
+                                  <div class="win-capital" @click="goProDetail(hs)">
+                                    <span>中标金额:<span v-html="setMoenyColor(formatterMoney(hs.total_project))"></span></span>
+                                    <span>中标数量:<span style="color: #2ABED1;">${hs.doc_count}</span>个</span>
+                                  </div>
+                                  <div class="win-info">
+                                    <div class="w-title">
+                                      <div class="w-title-head">最近合作项目:</div>
+                                      <span @click="goProjectDetail(hs.latest_project._id)" class="w-title-label">${hs.latest_project.projectname}</span>
+                                      <!-- <van-icon class="win-arrow" name="arrow"></van-icon> -->
+                                    </div>
+                                    <div class="company-info">
+                                      <span>中标金额:${hs.latest_project.bidamount ? formatterMoney(hs.latest_project.bidamount) : '--'}</span>
+                                      <!-- <span>注册资本:${formatterMoney(hs.capital)}</span> -->
+                                      <span>成交时间:${formatterTime(hs.latest_project.jgtime)}</span>
                                     </div>
+                                  </div>
+                              </div>
+                              <div v-if="showWinBtn" @click="showWinBtn = false" class="more">
+                                <span>查看更多</span>
+                              </div>
+                          </div>
+                      </div>
+                      <div class="bid_forcast_com" v-if="isHaveTrue && is15">
+                        <span>大数据预测企业中标概率、企业排名,帮助分析潜在投标<br/>企业、辅助投标决策。请点击  </span>
+                        <span @click="goBidForcast" style="color: #2ABED1;">中标企业预测>></span>
+                      </div>
+                      <!-- 同类项目标书编制周期分布 -->
+                      <div class="a-item" v-if="isShow.bidCycle">
+                          <div class="filter-title">
+                            <span>同类项目标书编制周期分布</span>
+                          </div>
+                          <div class="much-bar">
+                              <div style="padding: 0 12px;font-size: 10px;color: #9B9CA3;line-height: 14px;">同类项目数量(个)</div>
+                              <ve-histogram ref="histogram" :init-options="initRendererSvg" @ready="onBarReady($event, name)" height="300px" :mark-point="barChartMarkPoint" :after-config="barChartConfig" :data="barChartData" :settings="chartSettings" :extend="chartOptions.barChart"></ve-histogram>
+                          </div>
+                          <div class="bar-tip">注:标书编制周期是指招标文件发放之日至投标截止时间(开标)之间的时间间隔,标书编制周期越长,准备时间越充分。</div>
+                      </div>
+                      <!-- 同类项目预算分布 -->
+                      <div class="a-item" v-if="isShow.showHotMap">
+                          <div class="filter-title">
+                            <span>同类项目预算分布</span>
+                          </div>
+                          <div class="hot-map">
+                              <div id="myChart" ref="hotChart" :style="{height: heatMapHeight}"></div>
+                          </div>
+                          <div class="bar-tip">注:少数缺失的项目预算,用中标金额补充;平均折扣率=(全部项目预算-全部中标金额)/全部项目预算,仅统计预算和中标金额同时存在的项目。</div>
+                      </div>
+                      <!-- 同类项目区域分布 -->
+                      <div class="a-item" v-if="isShow.showMap">
+                          <div class="filter-title">
+                            <span>同类项目区域分布</span>
+                          </div>
+                          <div class="map">
+                              <ve-map
+                                  ref="mapRef"
+                                  :init-options="initRendererSvg"
+                                  :width="mapWidth"
+                                  height="400px"
+                                  :after-config="mapConfig"
+                                  :data="mapChartData"
+                                  :settings="mapSettings.chartSettings"
+                                  :extend="mapSettings.chartExtend">
+                              </ve-map>
+                          </div>
+                      </div>
+                      <!-- 同类项目采购单位类型分布 -->
+                      <div class="a-item" v-if="isShow.showPie">
+                          <div class="filter-title">
+                            <span>同类项目采购单位类型分布</span>
+                          </div>
+                          <div class="pieChart">
+                              <div ref="pieChart" style="height: 360px;"></div>
+                          </div>
+                          <div class="bar-tip">注:各采购单位类型占比以采购规模来计算,最多展示占比排名前十的采购单位类型。</div>
+                      </div>
+                      <!-- 历史合作评标专家 -->
+                      <div class="a-item ranking" v-if="(historyExpert.historyTabActive == 0 && isShow.showExperts) || historyExpert.historyTabActive == 1">
+                          <div class="filter-title">
+                              <span>历史合作评标专家</span>
+                              <div class="switchTab">
+                                <div :class="{'textColor': historyExpert.historyTabActive==0}" class="switch-tab" @click="onTabHistoryClick(0)">
+                                  <span>全部项目</span>
+                                  <div v-if="historyExpert.historyTabActive==0" class="line"></div>
                                 </div>
-                                <div class="jy-empty" v-else>
-                                    <div class="jy-empty-img"></div>
-                                    <p class="jy-empty-text" style="padding-bottom: 0.32rem;">暂无明细</p>
+                                <div :class="{'textColor': historyExpert.historyTabActive==1}" class="switch-tab" @click="onTabHistoryClick(1)">
+                                  <span>同类项目</span>
+                                  <div v-if="historyExpert.historyTabActive==1" class="line"></div>
                                 </div>
-                            </div>
-                        </van-tab>
-                    </van-tabs>
+                                <!-- <div class="switch-main">
+                                  <van-tabs class="switch_tab_list" :class="'history_'+ historyExpert.historyTabActive" v-model:active="historyExpert.historyTabActive" @click="onTabHistoryClick">
+                                    <van-tab title="全部项目"></van-tab>
+                                    <van-tab title="同类项目"></van-tab>
+                                  </van-tabs>
+                                </div> -->
+                              </div>
+                          </div>
+                          <p v-if="isShow.showExperts" style="display: flex;justify-content: space-between;align-items: center;padding:0 .32rem;font-size: .24rem;color:#9B9CA3;height: .48rem;">
+                            <span style="width: 1.04rem;"></span>
+                            <span style="margin-left: 1.1rem">最近合作日期</span>
+                            <span>参评项目数量(个)</span>
+                          </p>
+                          <div class="progress-bar-container" v-if="isShow.showExperts">
+                              <div class="progress-bar-item" @click="setViewMore(item)" v-for="(item,index) in expertWinArr" :key="index">
+                                  <div class="item-label">
+                                      <span class="item-name">${item.key}</span>
+                                      <span class="item-time">${formatterLineTime(item.jgtime)}</span>
+                                      <span class="item-count">${item.doc_count}个</span>
+                                  </div>
+                                  <div class="item-progress">
+                                      <span class="item-progress-count blue-progress" :style="{width: item.parent}"></span>
+                                  </div>
+                              </div>
+                          </div>
+                          <div class="jy-empty" v-else>
+                            <div class="jy-empty-img"></div>
+                            <p class="jy-empty-text" style="padding-bottom: 0.32rem;">
+                              暂无数据
+                            </p>
+                          </div>
+                      </div>
+                      <div class="a-item navBar" v-if="isHaveTrue">
+                        <span>继续查看</span>
+                        <div class="link-btn" @click="onTabClick(0)" v-if="active !== 0 && listCount.BuyerCount > 0">采购单位同类项目分析</div>
+                        <div class="link-btn" @click="onTabClick(1)" v-if="active !== 1 && listCount.AreaCount > 0">${filterData.area}同类项目分析</div>
+                        <div class="link-btn" @click="onTabClick(2)" v-if="active !== 2">全国同类项目分析</div>
+                      </div>
+                      <div class="jy-empty jy-main-empty" v-if="!isHaveTrue && loadingEmpty">
+                        <div class="jy-empty-img"></div>
+                        <div class="jy-empty-text" style="padding-bottom: 0.32rem;">
+                          <span style="color: #171826;" v-if="active === 0">${filterData.pname}</span><br/>
+                          <span style="color: #9B9CA3;" v-if="active === 0">暂未采购过同类项目,您可前往查看:</span> 
+                          <span style="color: #9B9CA3;" v-if="active === 1">${filterData.area}地区暂无同类项目,您可前往查看:</span> 
+                          <div class="a-item navBar">
+                            <div class="link-btn" @click="onTabClick(0)" v-if="active !== 0 && listCount.BuyerCount > 0">采购单位同类项目分析</div>
+                            <div class="link-btn" @click="onTabClick(1)" v-if="active !== 1 && listCount.AreaCount > 0">${filterData.area}同类项目分析</div>
+                            <div class="link-btn" @click="onTabClick(2)" v-if="active !== 2">全国同类项目分析</div>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    <div class="jy-empty" v-if="listCount.pCount === 0 && isShow.isShowAll">
+                      <div class="jy-empty-img"></div>
+                      <p class="jy-empty-text" style="padding-bottom: 0.32rem;">
+                        对不起,没有匹配到同类项目<br/>
+                        请修改您的分析条件
+                      </p>
+                    </div>
                 </div>
             </div>
         </div>
@@ -319,6 +393,8 @@
 {{include "/big-member/commonjs.html"}}
 <script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/echarts_option.js?v={{Msg "seo" "version"}}'></script>
 <script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/chart_options.js?v={{Msg "seo" "version"}}'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/public/js/china-province-data.js?v={{Msg "seo" "version"}}'></script>
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/common-module/analysis-filter/js/analysis-filter.js?v={{Msg "seo" "version"}}'></script>
 <script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/analysis_result.js?v={{Msg "seo" "version"}}'></script>
 <!--小于100行同css,减少请求数-->
 

+ 103 - 0
src/jfw/modules/app/src/web/templates/big-member/page_bid_analysis_pro_list.html

@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <!--引入公共资源头部-->
+    {{include "/big-member/meta.html"}}
+    <title>投标决策分析项目明细</title>
+    <!--S-当前页必定需要预加载的资源-->
+    <link rel="preload" as="style" href=//cdn-common.jianyu360.com/cdn/lib/reset-css/5.0.1/reset.min.css />
+    <link rel="preload" as="style" href=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/index.css />
+    <link rel="preload" as="style" href=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/icon/local.css />
+    <!--E-当前页必定需要预加载的资源-->
+
+    <!--S-当前页面的css资源-->
+    <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/analysis_result.css?v={{Msg "seo" "version"}}' />
+    <!--E-当前页面的css资源-->
+    <!--head内避免script加载-->
+</head>
+<body>
+<div class="j-container">
+    {{include "/big-member/header.html"}}
+    <div class="j-main" id="analysis-result" v-cloak>
+      <div class="j-container">
+        <div class="j-main" ref="wrapper">
+          <div class="projects" v-if="projectListDetail.length && projectListDetail.length > 0">
+            <div class="filter-title">
+                <span>共 <span style="color: #2abed1;">${projectData.count}</span> 个项目</span>
+            </div>
+            <van-list
+              v-model:loading="listParams.loading"
+              :finished="listParams.finished"
+              finished-text="没有更多了"
+              @load="onLoad"
+            >
+            <div v-for="item in projectListDetail" :key="item._id" class="project-list">
+                <div class="pl-title" @click="goProjectDetail(item.infoid)">${item.projectname}</div>
+                <div class="pl-tags">
+                  <span v-if="item.area">${item.area}</span>
+                  <span v-if="item.subtype">${item.subtype}</span>
+                  <span v-if="item.buyerclass">${item.buyerclass}</span>
+                  <span v-if="item.bidamount || item.budget">${item.bidamount || item.budget}万元</span>
+                </div>
+                <div class="pl-info can-click" @click="goUnitImage(item.buyer)">
+                    <span>采购单位:</span>
+                    <span>${item.buyer || '--'}</span>
+                </div>
+                <div class="pl-info">
+                    <span>预算金额:</span>
+                    <span>${item.budget || '--'}${item.budget ? '万元' : ''}</span>
+                </div>
+                <div class="pl-info can-click">
+                    <span>中标单位:</span>
+                    <div class="winner-list">
+                      <span  @click="goEntImg(winner.id)" v-for="winner in item.s_winner" :key="winner.id">${winner.name}</span> 
+                    </div>
+                </div>
+                <div class="pl-info">
+                    <span>中标金额:</span>
+                    <span>${item.bidamount || '--'}${item.bidamount ? '万元' : ''}</span>
+                </div>
+                <div class="pl-info">
+                    <span>评标专家:</span>
+                    <span>${item.review_experts || '--'}</span>
+                </div>
+                <div class="pl-info">
+                    <span>成交时间:</span>
+                    <span>${item.jgtime || '--'}</span>
+                </div>
+            </div>
+            </van-list>
+          </div>
+          <div class="jy-empty" style="margin-top: 2rem;" v-else>
+            <div class="jy-empty-img"></div>
+            <p class="jy-empty-text" style="padding-bottom: 0.32rem;">
+              暂无明细
+            </p>
+          </div>
+        </div>
+        <div class="j-footer" v-if="projectData.count > 5000">
+          <div class="bottom-tip">为您展示前5000条,可细化筛选条件查看更多信息</div>
+        </div>
+      </div>
+    </div>
+</div>
+
+<!--S-必定需要预加载的资源-->
+<link rel="preload" as="script" href=//cdn-common.jianyu360.com/cdn/lib/vue/2.6.11/vue.min.js />
+<link rel="preload" as="script" href=//cdn-common.jianyu360.com/cdn/lib/vant/2.12.24/lib/vant.min.js />
+<link rel="preload" as="script" href=//cdn-common.jianyu360.com/cdn/lib/zepto/1.2.0/zepto.min.js />
+<!--E-必定需要预加载的资源-->
+
+<!--S-当前页面的资源-->
+<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>
+<!--E-当前页面的资源-->
+{{include "/big-member/commonjs.html"}}
+<script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/js/analysis_pro_list.js?v={{Msg "seo" "version"}}'></script>
+
+</body>
+</html>

文件差异内容过多而无法显示
+ 0 - 0
src/jfw/modules/app/src/web/templates/big-member/page_contrast.html


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

@@ -94,7 +94,7 @@
       <div class="insight" id="fx">
         <div class="action_out" style="font-size: 0;">
           <div>
-            <img src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/image/landpage_new/itemA_05.jpg'>
+            <img src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/image/landpage_new/itemA_05.jpg?v={{Msg "seo" "mod_version"}}'>
           </div>
           <div>
             <img src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/big-member/image/landpage_new/itemA_06.jpg'>

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

@@ -69,7 +69,7 @@
                 <div class="land_head">
                     <img src="/jyapp/big-member/image/landpage/title03.png" alt="" class="head_big">
                 </div>
-                <div class="land_intro">通过对类项目进行多维度分析,帮助企业决策是否投标或合作投标、以及投标报价金额等。</div>
+                <div class="land_intro">通过对类项目进行多维度分析,帮助企业决策是否投标或合作投标、以及投标报价金额等。</div>
                 <div class="land_main">
                     <ul class="landul">
                         <van-swipe :autoplay="3000">

+ 6 - 6
src/jfw/modules/app/src/web/templates/big-member/page_landingPage_old_1.html

@@ -79,7 +79,7 @@
                                 </div>
                                 <div class="forecast">
                                     <span class="cast_left">为你提供</span>
-                                    <span class="cast_right">类项目联系人 &nbsp; 联系方式</span>
+                                    <span class="cast_right">类项目联系人 &nbsp; 联系方式</span>
                                 </div>
                                 <div class="manysquare">
                                     <img src="/jyapp/big-member/image/landpage_new/square.png" alt="" class="manysquare_img">
@@ -422,11 +422,11 @@
                 '透视潜在投标企业的全景画像'
             ],
             offer:[
-                '类项目评标专家频次排名',
-                '类项目中标金额',
-                '类项目预算',
-                '类项目折扣率',
-                '类项目区域热度'
+                '类项目评标专家频次排名',
+                '类项目中标金额',
+                '类项目预算',
+                '类项目折扣率',
+                '类项目区域热度'
             ],
             pushcom:[
                 '企业中标动态',

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

@@ -56,7 +56,7 @@
                 <div class="land_head">
                     <img src="/jyapp/big-member/image/landpage/title03.png" alt="" class="head_big">
                 </div>
-                <div class="land_intro">通过对类项目进行多维度分析,帮助企业决策是否投标或合作投标、以及投标报价金额等。</div>
+                <div class="land_intro">通过对类项目进行多维度分析,帮助企业决策是否投标或合作投标、以及投标报价金额等。</div>
                 <div class="land_main">
                     <ul class="landul">
                         <van-swipe :autoplay="3000">

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

@@ -1046,9 +1046,9 @@
             goAnalysis: function () {
                 sessionStorage.removeItem('big-analysis_filter')
                 if (this.power.indexOf(6) > -1) {
-                    location.href = './analysis_filter?sId=' + this.sid
+                    location.href = './analysis_result?id=' + this.sid
                 } else {
-                    location.href = './analysis_filter?source=app_analysis_follow_project&sId=' + this.sid
+                    location.href = '/jyapp/frontPage/bigmember/free/perfect_info?source=app_analysis_follow_project'
                 }
             },
             callPhone() {

+ 178 - 1
src/jfw/modules/app/src/web/templates/dataSmt/index.html

@@ -1 +1,178 @@
-pc 落地页
+<!doctype html>
+<html lang="en">
+<head>
+    <title>数据超市</title>
+    <!--引入公共资源头部-->
+    {{include "/big-member/meta.html"}}
+    <!--S-当前页面的css资源-->
+    <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=//cdn-common.jianyu360.com/cdn/assets/iconfont/mobile/22.7.2/iconfont.css />
+    <link rel="stylesheet" href='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/dataSmt/css/index.css?v={{Msg "seo" "version"}}' />
+    <!--E-当前页面的css资源-->
+    <style>
+        .j-container.app > .j-main {
+            margin-top: -21.34vw;
+        }
+        .j-header.transparent-header .header-left, .j-header.transparent-header .header-title{
+            color: #171826 !important;
+            font-size: 18px !important;
+        }
+        .jy-app-header.transparent-header .icon-back{
+            display: block;
+        }
+        .j-header .header-left .j-icon{
+            width: .48rem;
+            height: .48rem;
+        }
+    </style>
+<body>
+    <div class="j-container app">
+        {{include "/big-member/header.html"}}
+        <div class="j-main data-sam-main">
+            <div class="header-banner">
+               <img class="header-banner-img" src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/dataSmt/images/header-banner.png' alt="头部背景">
+                <section class="header-box">
+                    <p><img class="supermarket-img" src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/dataSmt/images/data-market-text.png' alt="数据超市"></p>
+                    <p class="sub-description">提供海量热门行业数据,专业安全合规成品数据一键下载</p>
+                    <ul class="example-list">
+                        <li>
+                            <img src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/dataSmt/images/icon-1.png' alt="海量数据支持">
+                            <span>海量数据支持</span>
+                        </li>
+                        <li>
+                            <img src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/dataSmt/images/icon-1.png' alt="海量数据支持">
+                            <span>专业数据团队</span>
+                        </li>
+                        <li>
+                            <img src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/dataSmt/images/icon-1.png' alt="海量数据支持">
+                            <span>数据成本低</span>
+                        </li>
+                        <li>
+                            <img src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/dataSmt/images/icon-1.png' alt="海量数据支持">
+                            <span>多种数据获取方式</span>
+                        </li>
+                    </ul>
+                </section>
+            </div>
+            <div class="content-container">
+                <section class="section-search-com">
+                   <div class="search-component">
+                       <i class="j-icon base-icon icon-search"></i>
+                       <input class="search-input" type="text" onfocus="searchFocus()" placeholder="请输入业务范围,如物业管理">
+                   </div>
+                </section>
+                <section class="select-component" id="select-component">
+                    <div class="cell-left"  @click="showTypeHandle">
+                        <span>数据类型:</span>
+                        <span class="data-type">${typeText}</span>
+                        <i class="iconfont icon-youbian"></i>
+                    </div>
+                    <div class="cell-right" @click="showExplain = true">
+                        <span>包含字段</span>
+                        <i class="iconfont icon-help1"></i>
+                    </div>
+                    <van-popup
+                            v-model:show="showDataType"
+                            closeable
+                            round
+                            close-icon="clear"
+                            position="bottom"
+                            :style="{ height: '480px' }"
+                            class="custom-pop data-type-pop"
+                    >
+                        <div class="pop-container">
+                            <div class="pop-title">选择数据类型</div>
+                            <div class="pop-content">
+                                <van-cell v-for="item in typeList" :title="item.label" @click="changeDataType(item)">
+                                    <template #right-icon v-if="item.value === selectType">
+                                        <i class="iconfont icon-duihao"></i>
+                                    </template>
+                                </van-cell>
+                            </div>
+                            <div class="pop-bottom bottom-handle-box">
+                                <div class="confirm-btn" @click="typeConfirmHandle">确定</div>
+                            </div>
+                        </div>
+                    </van-popup>
+                    <van-popup
+                            v-model:show="showExplain"
+                            closeable
+                            round
+                            close-icon="clear"
+                            position="bottom"
+                            :style="{ height: '480px' }"
+                            class="custom-pop explain-pop"
+                    >
+                        <div class="pop-container">
+                            <div class="pop-title">字段包含说明</div>
+                            <div class="pop-content">
+                                <van-cell v-for="item in explainList" :title="item.title" :label="item.label" />
+                            </div>
+                            <div class="pop-bottom bottom-handle-box">
+                                <div class="confirm-btn" @click="showExplain = false">我知道了</div>
+                            </div>
+                        </div>
+                    </van-popup>
+                </section>
+                <section class="j-container list-component">
+                    <div class="j-main">
+                        <div class="list-row">
+                            <span class="corner-mark corner-color-1">采购意见</span>
+                            <p class="label-info">“新媒体运营”项目,近6个月全国采购意向数据批量下载</p>
+                            <div class="row-tags">
+                                <span class="tag-item tag-color-1">人工清洗</span>
+                                <span class="tag-item tag-color-1">格式:Excel、CSV</span>
+                            </div>
+                        </div>
+                        <div class="list-row">
+                            <span class="corner-mark corner-color-2">拟建项目</span>
+                            <p class="label-info">“新媒体运营”项目,近6个月全国采购意向数据批量下载</p>
+                            <div class="row-tags">
+                                <span class="tag-item tag-color-1">人工清洗</span>
+                                <span class="tag-item tag-color-1">格式:Excel、CSV</span>
+                            </div>
+                        </div>
+                        <div class="list-row">
+                            <span class="corner-mark corner-color-3">招标数据</span>
+                            <p class="label-info">“新媒体运营”项目,近6个月全国采购意向数据批量下载</p>
+                            <div class="row-tags">
+                                <span class="tag-item tag-color-1">人工清洗</span>
+                                <span class="tag-item tag-color-1">格式:Excel、CSV</span>
+                            </div>
+                        </div>
+                        <div class="list-row">
+                                <span class="corner-mark corner-color-4">中标数据</span>
+                                <p class="label-info">“新媒体运营”项目,近6个月全国采购意向数据批量下载</p>
+                                <div class="row-tags">
+                                    <span class="tag-item tag-color-1">人工清洗</span>
+                                    <span class="tag-item tag-color-1">格式:Excel、CSV</span>
+                                </div>
+                            </div>
+                    </div>
+                </section>
+            </div>
+        </div>
+        <div class="bottom-handle-box fixed">
+            <div class="confirm-btn">申请数据定制</div>
+        </div>
+    </div>
+    <!--S-当前页面的资源-->
+    <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/jquery/3.6.0/jquery.min.js></script>
+    <!--E-当前页面的资源-->
+    {{include "/big-member/commonjs.html"}}
+    <script src='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/dataSmt/js/index.js?v={{Msg "seo" "version"}}'></script>
+    <script>
+      $(function () {
+        var header = $('.j-header.jy-app-header')
+        header.addClass('transparent-header')
+      })
+    </script>
+    <script>
+
+    </script>
+</body>
+</html>

+ 22 - 2
src/jfw/modules/app/src/web/templates/dataSmt/list.html

@@ -1,2 +1,22 @@
-pc 列表页
-{{.T.dataType}}
+<!doctype html>
+<html lang="en">
+<head>
+    <title>数据超市</title>
+    <!--引入公共资源头部-->
+    {{include "/big-member/meta.html"}}
+    <!--S-当前页面的css资源-->
+    <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=//cdn-common.jianyu360.com/cdn/assets/iconfont/mobile/22.7.2/iconfont.css />
+    <link rel="stylesheet" href='{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/dataSmt/css/index.css?v={{Msg "seo" "version"}}' />
+</head>
+<body>
+<div class="j-container app">
+    {{include "/big-member/header.html"}}
+    <div class="app-layout-header">
+        555555
+    </div>
+</div>
+</body>
+</html>

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

@@ -2,7 +2,7 @@
 <head>
     {{include "/common/meta.html"}}
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
-    <meta name="keywords" content="">
+    <meta name="keywords" content="{{.T.obj.keywords}}">
     <meta name="description" content="{{.T.obj.description}}">
     <title>公告信息</title>
     <link href="{{Cdns .Host "seo" "cdn"|SafeUrl}}/jyapp/css/alertPopShow.css?v={{Msg "seo" "version"}}" rel="stylesheet">
@@ -2752,10 +2752,10 @@
         // 判断有没有投标决策分析权限
         if (hasServiceArr.indexOf(6) > -1) {
           // 有权限 带标讯id 跳转到开始分析页面
-          location.href = '/jyapp/big/page/analysis_filter?sId=' + id
+          location.href = '/jyapp/big/page/analysis_result?id=' + id
         } else {
-          // 没有投标决策分析权限 跳转到搜索页 走留资流程
-          location.href = '/jyapp/big/page/analysis_filter?source=app_analysis_bid_detail&sId=' + id
+          // 没有投标决策分析权限 走留资流程
+          location.href = '/jyapp/frontPage/bigmember/free/perfect_info?source=app_analysis_bid_detail'
         }
       })
       // 中标预测

文件差异内容过多而无法显示
+ 1 - 0
src/jfw/modules/bigmember/src/config.json


+ 264 - 77
src/jfw/modules/bigmember/src/entity/analysis.go

@@ -1,19 +1,19 @@
 package entity
 
 import (
+	qutil "app.yhyue.com/moapp/jybase/common"
 	"fmt"
 	"jy/src/jfw/modules/bigmember/src/util"
+	"log"
 	"regexp"
 	"strconv"
 	"strings"
 	"sync"
 	"time"
-
-	qutil "app.yhyue.com/moapp/jybase/common"
 )
 
 var (
-	query      = `{"query":{"bool":{"should":[%s],"must":[%s]}},"_source":[%s],"sort":[%s],"from":0,"size":%d,"aggs":{%s}}`
+	query      = `{"track_total_hits": true,"query":{"bool":{"must":[%s]}},"_source":[%s],"sort":[%s],"from":%d,"size":%d,"aggs":{%s}}`
 	query_bool = `{"bool":{"should":[%s],"minimum_should_match":%d}}`
 	//关键词匹配
 	multi_match_public = `{"multi_match":{"query":%s,"type":"phrase","fields":[%s]}}`
@@ -26,25 +26,24 @@ var (
 )
 
 const (
-	PSearch_DecField    = `"projectname","_id","buyer","firsttime","area","city","s_winner","review_experts","budget","bidamount","project_rate","bidtype","ids","winnerorder","bidtype","bidcycle"`
+	PSearch_DecField    = `"projectname","_id","buyer","firsttime","area","city","s_winner","review_experts","budget","bidamount","project_rate","bidtype","ids","winnerorder","entidlist","bidtype","bidcycle","buyerclass","jgtime","list"`
 	PSearch_DecMust     = `"bidstatus": ["中标","成交","合同"]`
-	PSearch_DecSimCount = 100                    //决策分析类似项目明细数据量
-	PSearch_DecSort     = `{"firsttime":"desc"}` //决策分析类似项目明细排序
+	PSearch_DecSimCount = 100                 //决策分析类似项目明细数据量
+	PSearch_DecSort     = `{"jgtime":"desc"}` //决策分析类似项目明细排序
 )
 
 var RegExperts = regexp.MustCompile("^[\\p{Han}]{2,4}$")
 
-//查询此中标企业 和 此采购单位 所有合作的项目
+// 查询此中标企业 和 此采购单位 所有合作的项目
 func (this *AnalysisDec) GetAllBWQueryByBW() string {
 	return fmt.Sprintf(query_allmsg_buyer_winner, this.Buyer, this.Winner, PSearch_DecField, PSearch_DecSimCount)
 }
 
-////投标决策分析查询语句-中标企业和采购单位 类似项目明细
+// //投标决策分析查询语句-中标企业和采购单位 类似项目明细
 func (this *AnalysisDec) DecQueryNewSimilarMsgByBW() (qstr string) {
 	//基础查询
 	bools := []string{}
 	musts := []string{}
-	shoulds := []string{}
 	var BWExists = 0
 	//中标单位 类似项目合作历史||采购单位类似项目
 	if this.Winner != "" {
@@ -60,62 +59,57 @@ func (this *AnalysisDec) DecQueryNewSimilarMsgByBW() (qstr string) {
 		musts = append(musts, winnerterms)
 	}
 	//中标单位 类似项目合作历史||采购单位类似项目
-	if this.Buyer != "" {
+	if this.Buyer != "" && this.SearchItem == 1 {
+		buyerterms := fmt.Sprintf(`{"query_string": {"default_field": "buyer","query": "*%s*"}}`, this.Buyer)
 		BWExists += 1
-		buyerterms := `{"terms":{"buyer":[`
-		for k, v := range strings.Split(this.Buyer, ",") {
-			if k > 0 {
-				buyerterms += `,`
-			}
-			buyerterms += `"` + v + `"`
-		}
-		buyerterms += `]}}`
 		musts = append(musts, buyerterms)
 	}
 	//searchType ==1; buyer & winner 不能为空
 	if BWExists < 2 && this.SearchType == 1 {
 		this.SearchType = 0
 	}
-	//省份
-	areaCity := []string{}
-	citys := []string{}
-	if len(this.Area) > 0 {
-		areaquery := `{"terms":{"area":[`
-		var i = 0
-		for k, v := range this.Area {
-			if len(qutil.ObjArrToStringArr(v.([]interface{}))) == 0 {
-				if i > 0 {
-					areaquery += `,`
+	if this.SearchItem == 2 {
+		//省份
+		areaCity := []string{}
+		citys := []string{}
+		if len(this.Area) > 0 {
+			areaquery := `{"terms":{"area":[`
+			var i = 0
+			for k, v := range this.Area {
+				if len(qutil.ObjArrToStringArr(v.([]interface{}))) == 0 {
+					if i > 0 {
+						areaquery += `,`
+					}
+					areaquery += `"` + strings.ReplaceAll(strings.ReplaceAll(k, "省", ""), "市", "") + `"`
+					i += 1
+				} else {
+					citys = append(citys, qutil.ObjArrToStringArr(v.([]interface{}))...)
 				}
-				areaquery += `"` + k + `"`
-				i += 1
-			} else {
-				citys = append(citys, qutil.ObjArrToStringArr(v.([]interface{}))...)
+			}
+			areaquery += `]}}`
+			if i > 0 {
+				areaCity = append(areaCity, areaquery)
 			}
 		}
-		areaquery += `]}}`
-		if i > 0 {
+		//城市
+		if len(citys) > 0 {
+			//城市对应前三十个
+			if len(citys) > 30 {
+				citys = citys[:30]
+			}
+			areaquery := `{"terms":{"city":[`
+			for k, v := range citys {
+				if k > 0 {
+					areaquery += `,`
+				}
+				areaquery += `"` + v + `"`
+			}
+			areaquery += `]}}`
 			areaCity = append(areaCity, areaquery)
 		}
-	}
-	//城市
-	if len(citys) > 0 {
-		//城市对应前三十个
-		if len(citys) > 30 {
-			citys = citys[:30]
-		}
-		areaquery := `{"terms":{"city":[`
-		for k, v := range citys {
-			if k > 0 {
-				areaquery += `,`
-			}
-			areaquery += `"` + v + `"`
+		if len(areaCity) > 0 {
+			musts = append(musts, strings.Join(areaCity, ","))
 		}
-		areaquery += `]}}`
-		areaCity = append(areaCity, areaquery)
-	}
-	if len(areaCity) > 0 {
-		shoulds = append(shoulds, strings.Join(areaCity, ","))
 	}
 
 	//金额区间
@@ -133,16 +127,29 @@ func (this *AnalysisDec) DecQueryNewSimilarMsgByBW() (qstr string) {
 		pricequery += `}}}`
 		musts = append(musts, pricequery)
 	}
+
+	//检索日期
+	var (
+		gteTime time.Time
+		gte     int64
+	)
+	sTime := time.Now()
+	switch this.LimitTime {
+	case "oneYear":
+		gteTime = sTime.AddDate(-1, 0, 0)
+	case "threeYear":
+		gteTime = sTime.AddDate(-3, 0, 0)
+	case "fiveYear": // 默认近五年
+		gteTime = sTime.AddDate(-5, 0, 0)
+	default:
+		gte = qutil.Int64All(P_Starttime)
+	}
+	if this.LimitTime != "" {
+		gte = time.Date(gteTime.Year(), 1, 1, 0, 0, 0, 0, time.Local).Unix()
+	}
 	//检索日期
-	if P_Starttime != "" {
-		now := time.Now()
-		endtime := now.Unix()
-		timequery := `{"range":{"firsttime":{`
-		timequery += `"gte":` + P_Starttime
-		timequery += `,`
-		timequery += `"lt":` + strconv.FormatInt(endtime, 10)
-		timequery += `}}}`
-		musts = append(musts, timequery)
+	if gte > 0 {
+		musts = append(musts, fmt.Sprintf(`{"range":{"jgtime":{"gte":%d,"lt":%d}}}`, gte, sTime.Unix()))
 	}
 	//中标项目
 	if PSearch_DecMust != "" {
@@ -210,11 +217,17 @@ func (this *AnalysisDec) DecQueryNewSimilarMsgByBW() (qstr string) {
 	if len(bools) > 0 {
 		musts = append(musts, fmt.Sprintf(query_bool, strings.Join(bools, ","), boolsNum))
 	}
-	qstr = fmt.Sprintf(query, strings.Join(shoulds, ","), strings.Join(musts, ","), PSearch_DecField, PSearch_DecSort, PSearch_DecSimCount, "")
+	if this.Page == 0 {
+		this.Page = 1
+	}
+	if this.PageSize == 0 {
+		this.PageSize = 10
+	}
+	qstr = fmt.Sprintf(query, strings.Join(musts, ","), PSearch_DecField, PSearch_DecSort, (this.Page-1)*this.PageSize, this.PageSize, "")
+	log.Println("投标决策分析查询语句-中标企业和采购单位 类似项目明细", qstr)
 	return qstr
 }
 
-//
 func ThisLock(userId string) *sync.Mutex {
 	UIL.Lock()
 	if UIL.DecLock[userId] == nil {
@@ -224,8 +237,7 @@ func ThisLock(userId string) *sync.Mutex {
 	return UIL.DecLock[userId]
 }
 
-//
-//采购内容 精准or模糊匹配处理
+// 采购内容 精准or模糊匹配处理
 func BuyerContentStruct(BC []ViewKeyWord) (arr []ViewKeyWord) {
 	if len(BC) > 0 {
 		for _, kw := range BC {
@@ -250,7 +262,7 @@ func BuyerContentStruct(BC []ViewKeyWord) (arr []ViewKeyWord) {
 	return arr
 }
 
-//决策分析 根据字段权重排序 中标企业和中标价格
+// 决策分析 根据字段权重排序 中标企业和中标价格
 var (
 	bidtype_score        = 1 //采购方式
 	review_experts_score = 1 //评审专家
@@ -261,6 +273,59 @@ var (
 	winnerorder_score    = 1 //中标候选人
 )
 
+// NewSequence 成交时间
+func NewSequence(seqData []map[string]interface{}) []map[string]interface{} {
+	var data []map[string]interface{}
+	for _, v := range seqData {
+		var score = 0
+		if v["s_winner"] != nil && qutil.InterfaceToStr(v["s_winner"]) != "" {
+			var s_winner = qutil.ObjToString(v["s_winner"])
+			entidlist, _ := v["entidlist"].([]interface{})
+			//中标单位id
+			winnerList := strings.Split(s_winner, ",")
+			if len(entidlist) == len(winnerList) {
+				var entidlists []string
+				for _, v2 := range entidlist {
+					entidlists = append(entidlists, util.EncodeId(qutil.InterfaceToStr(v2)))
+				}
+				v["entidlist"] = entidlists
+			} else {
+				delete(v, "entidlist") //中标单位id有误 删除id处理
+			}
+		}
+		//评审专家
+		review_experts := []string{}
+		if v["review_experts"] != nil {
+			for _, v1 := range qutil.ObjArrToStringArr(v["review_experts"].([]interface{})) {
+				if RegExperts.MatchString(v1) {
+					review_experts = append(review_experts, v1)
+				}
+			}
+			v["review_experts"] = review_experts
+		}
+		if len(review_experts) > 0 {
+			score += review_experts_score
+		}
+		list, _ := v["list"].([]interface{})
+		if len(list) > 0 {
+			listMap, _ := list[len(list)-1].(map[string]interface{})
+			v["subtype"] = listMap["subtype"]
+			delete(v, "list")
+		}
+
+		if v["ids"] != nil {
+			ids := qutil.ObjArrToStringArr(v["ids"].([]interface{}))
+			if len(ids) > 0 {
+				v["infoid"] = util.EncodeId(ids[0])
+				delete(v, "ids")
+			}
+		}
+		v["_id"] = util.EncodeId(v["_id"].(string))
+		data = append(data, v)
+	}
+	return data
+}
+
 func Sequence(seqData []map[string]interface{}) []map[string]interface{} {
 	var sequenceArr3 = []map[string]interface{}{}
 	var sequenceArr4 = []map[string]interface{}{}
@@ -271,24 +336,36 @@ func Sequence(seqData []map[string]interface{}) []map[string]interface{} {
 	var sequenceArr9 = []map[string]interface{}{}
 	for k, v := range seqData {
 		var score = 0
-		if v["s_winner"] == nil {
+		if v["s_winner"] != nil && qutil.InterfaceToStr(v["s_winner"]) != "" {
 			var s_winner = qutil.ObjToString(v["s_winner"])
-			var s_length = 0
-			for _, v := range strings.Split(s_winner, ",") {
-				if RegWinner.MatchString(v) {
-					s_length += 1
+			entidlist, _ := v["entidlist"].([]interface{})
+			//中标单位id
+			winnerList := strings.Split(s_winner, ",")
+			if len(entidlist) == len(winnerList) {
+				var entidlists []string
+				for _, v2 := range entidlist {
+					entidlists = append(entidlists, util.EncodeId(qutil.InterfaceToStr(v2)))
 				}
+				v["entidlist"] = entidlists
+			} else {
+				delete(v, "entidlist") //中标单位id有误 删除id处理
 			}
-			if s_length == 0 {
-				continue
-			}
+			//var s_length = 0
+			//for _, v1 := range winnerList {
+			//	if RegWinner.MatchString(v1) {
+			//		s_length += 1
+			//	}
+			//}
+			//if s_length == 0 {
+			//	continue
+			//}
 		}
 		//评审专家
 		review_experts := []string{}
 		if v["review_experts"] != nil {
-			for _, v := range qutil.ObjArrToStringArr(v["review_experts"].([]interface{})) {
-				if RegExperts.MatchString(v) {
-					review_experts = append(review_experts, v)
+			for _, v1 := range qutil.ObjArrToStringArr(v["review_experts"].([]interface{})) {
+				if RegExperts.MatchString(v1) {
+					review_experts = append(review_experts, v1)
 				}
 			}
 			v["review_experts"] = review_experts
@@ -296,6 +373,12 @@ func Sequence(seqData []map[string]interface{}) []map[string]interface{} {
 		if len(review_experts) > 0 {
 			score += review_experts_score
 		}
+		list, _ := v["list"].([]interface{})
+		if len(list) > 0 {
+			listMap, _ := list[len(list)-1].(map[string]interface{})
+			v["subtype"] = listMap["subtype"]
+			delete(v, "list")
+		}
 		//采购方式
 		if v["bidtype"] != nil && qutil.ObjToString(v["bidtype"].(string)) != "" {
 			score += bidtype_score
@@ -351,3 +434,107 @@ func Sequence(seqData []map[string]interface{}) []map[string]interface{} {
 	}
 	return append(append(append(append(append(append(sequenceArr9, sequenceArr8...), sequenceArr7...), sequenceArr6...), sequenceArr5...), sequenceArr4...), sequenceArr3...)
 }
+
+func GetReviewExpertsProjects(expertName string, area map[string]interface{}, business_scope []ViewKeyWord, buyer, limitTime string, searchItem, projectScope, page, pageSize int) string {
+	var query = `{"track_total_hits": true,"query":{"bool":{"must":[{"bool":{"should":[%s],"must":[%s]}},{"bool":{"should":[%s],"minimum_should_match":%d}},{"term":{"review_experts":"%s"}}]}},"_source":[%s],"sort":[%s],"from":%d,"size":%d}`
+
+	//基础查询
+	bools := []string{}
+	musts := []string{}
+	shoulds := []string{}
+
+	if searchItem == 1 { //采购单位同类型检索
+		//项目采购单位 模糊匹配
+		buyerSql := fmt.Sprintf(`{"query_string": {"default_field": "buyer","query": "*%s*"}}`, buyer)
+		musts = append(musts, buyerSql)
+	}
+
+	if searchItem == 2 { //地区同类型检索
+		//省份
+		areaCity := []string{}
+		//citys := []string{}
+		if len(area) > 0 {
+			areaquery := `{"terms":{"area":[`
+			var i = 0
+			for k, v := range area {
+				if len(qutil.ObjArrToStringArr(v.([]interface{}))) == 0 {
+					if i > 0 {
+						areaquery += `,`
+					}
+					areaquery += `"` + strings.ReplaceAll(strings.ReplaceAll(k, "省", ""), "市", "") + `"`
+					i += 1
+				}
+			}
+			areaquery += `]}}`
+			if i > 0 {
+				areaCity = append(areaCity, areaquery)
+			}
+		}
+
+		if len(areaCity) > 0 {
+			musts = append(musts, strings.Join(areaCity, ","))
+		}
+	}
+
+	//检索日期
+	if limitTime != "" {
+		var (
+			gteTime time.Time
+			gte     int64
+		)
+		sTime := time.Now()
+		switch limitTime {
+		case "oneYear":
+			gteTime = sTime.AddDate(-1, 0, 0)
+		case "threeYear":
+			gteTime = sTime.AddDate(-3, 0, 0)
+		default: // 默认近五年
+			gteTime = sTime.AddDate(-5, 0, 0)
+		}
+		gte = time.Date(gteTime.Year(), 1, 1, 0, 0, 0, 0, time.Local).Unix()
+		musts = append(musts, fmt.Sprintf(`{"range":{"jgtime":{"gte":%d,"lt":%d}}}`, gte, sTime.Unix()))
+	}
+	//中标项目
+	if PSearch_DecMust != "" {
+		musts = append(musts, fmt.Sprintf(query_bool_must, PSearch_DecMust))
+	}
+	boolsNum := 0
+	//should
+	if len(business_scope) > 0 && projectScope != 1 {
+		boolsNum = 1
+		findfields := `"projectname.pname","purchasing"`
+		multi_match := fmt.Sprintf(multi_match_public, "%s", findfields)
+		for _, kv := range business_scope {
+			shoulds := []string{}
+			must_not := []string{}
+			//关键词
+			for _, v := range kv.Keyword {
+				shoulds = append(shoulds, fmt.Sprintf(multi_match, "\""+v+"\""))
+			}
+			//附加词
+			if len(kv.Appended) > 0 {
+				for _, vv := range kv.Appended {
+					shoulds = append(shoulds, fmt.Sprintf(multi_match, "\""+vv+"\""))
+				}
+			}
+			if len(kv.Exclude) > 0 {
+				//排除词
+				for _, vv := range kv.Exclude {
+					must_not = append(must_not, fmt.Sprintf(multi_match, "\""+vv+"\""))
+				}
+			}
+			//添加
+			if len(shoulds) > 0 {
+				notStr := ""
+				if len(must_not) > 0 {
+					notStr = fmt.Sprintf(`,"must_not":[%s]`, strings.Join(must_not, ","))
+				}
+				bools = append(bools, fmt.Sprintf(query_bool_must_and, strings.Join(shoulds, ","), notStr))
+			}
+		}
+	}
+	start := (page - 1) * pageSize
+	qstr := fmt.Sprintf(query, strings.Join(shoulds, ","), strings.Join(musts, ","), strings.Join(bools, ","), boolsNum, expertName, PSearch_DecField, `{"jgtime":"desc"}`, start, pageSize)
+	log.Println("str:", qstr)
+	return qstr
+}

+ 112 - 55
src/jfw/modules/bigmember/src/entity/analysisEntName.go

@@ -2,31 +2,49 @@
 package entity
 
 import (
+	qutil "app.yhyue.com/moapp/jybase/common"
+	elastic "app.yhyue.com/moapp/jybase/es"
+	"app.yhyue.com/moapp/jybase/go-xweb/httpsession"
 	"fmt"
 	"jy/src/jfw/modules/bigmember/src/db"
 	"jy/src/jfw/modules/bigmember/src/util"
+	"log"
 	"regexp"
 	"strings"
 	"sync"
-
-	qutil "app.yhyue.com/moapp/jybase/common"
-	elastic "app.yhyue.com/moapp/jybase/es"
-	"app.yhyue.com/moapp/jybase/go-xweb/httpsession"
+	"time"
 )
 
-/**即时获取项目名称列表
+/*
+*即时获取项目名称列表
 name  名称
 limit 取几条
 */
-var pnquery = `{"query": {"bool": {"must": [{"match": {"projectname.pname": "%s"}}]}},"_source": ["projectname","_id","buyer","firsttime","area","city","sourceinfoid"],"from": 0,"size": %d}`
+var pnquery = `{"query": {"bool": {"must": [{"match": {"%s": "%s"}}]}},"_source": ["projectname","_id","buyer","firsttime","area","city","sourceinfoid"],"from": 0,"size": %d}`
 
-func GetProNameImmediate(name string, limit int) []map[string]interface{} {
-	query := fmt.Sprintf(pnquery, name, limit)
-	list := *elastic.Get("projectset", "projectset", query)
-	return list
+func GetProNameImmediate(sType, name string, limit int) []map[string]interface{} {
+	var queryName string
+	if sType == "1" {
+		var list []map[string]interface{}
+		r := elastic.Get("buyer", "buyer", fmt.Sprintf(`{"query": {"match_phrase": {"name": "%s"}},"_source": ["name"],"size": %d}`, name, limit))
+		if r != nil {
+			for _, v := range *r {
+				list = append(list, map[string]interface{}{"buyer": qutil.InterfaceToStr(v["name"])})
+			}
+		}
+		return list
+	} else {
+		queryName = fmt.Sprintf(pnquery, "projectname.pname", name, limit)
+	}
+
+	list := elastic.Get("projectset", "projectset", queryName)
+	if list == nil {
+		return nil
+	}
+	return *list
 }
 
-//根据项目名称查询项目信息
+// 根据项目名称查询项目信息
 func GetProInfoById(ids, sourceinfoids []string) []map[string]interface{} {
 	var res []map[string]interface{}
 	if len(ids) > 0 {
@@ -58,14 +76,30 @@ func GetProInfoById(ids, sourceinfoids []string) []map[string]interface{} {
 	return res
 }
 
-//
 var pcquery = `{"query": {"bool": {"must": [{"terms": {"%s": [%s]}}],"must_not": [],"should": []}},"from": 0,"size": 20,"sort": []}`
+var qurySql = `{"query": {"bool": {"must": [],"must_not": [],"should": [%s]}},"from": 0,"size": 10,"sort": []}`
+
+// 采购单位模糊
+func GetEntBlur(entName []string) []map[string]interface{} {
+	var data []string
+	for _, v := range entName {
+		data = append(data, fmt.Sprintf(`{"query_string": {"default_field": "buyer_name","query": "*%s*"}}`, v))
+	}
+	query := fmt.Sprintf(qurySql, strings.Join(data, ","))
+	list := elastic.Get("buyer", "buyer", query)
+	if list == nil {
+		return nil
+	}
+	return *list
+}
 
-//潜在客户 获取省份和城市
 func GetEntPC(entName []string) []map[string]interface{} {
 	query := fmt.Sprintf(pcquery, "buyer_name", `"`+strings.Join(entName, `","`)+`"`)
-	list := *elastic.Get("buyer", "buyer", query)
-	return list
+	list := elastic.Get("buyer", "buyer", query)
+	if list == nil {
+		return nil
+	}
+	return *list
 }
 
 type EnterQYXYInfo struct {
@@ -75,7 +109,7 @@ type EnterQYXYInfo struct {
 	City string
 }
 
-//企业库是否有此企业信息
+// 企业库是否有此企业信息
 func GetEntInfo(entName []string, p string) (entName_r []*EnterQYXYInfo) {
 	if len(entName) > 0 {
 		query := map[string]interface{}{}
@@ -105,7 +139,7 @@ func GetEntInfo(entName []string, p string) (entName_r []*EnterQYXYInfo) {
 	return entName_r
 }
 
-//企业库是否有此企业信息
+// 企业库是否有此企业信息
 func GetEntInfoByQYXY(entName []string, p string) []*EnterQYXYInfo {
 	entName_r := []*EnterQYXYInfo{}
 	if len(entName) > 0 {
@@ -136,7 +170,7 @@ func GetEntInfoByQYXY(entName []string, p string) []*EnterQYXYInfo {
 	return entName_r
 }
 
-//企业库是否有此企业信息 并返回加密后id
+// 企业库是否有此企业信息 并返回加密后id
 func GetEntIdByQYXY(entName string) string {
 	var entId = ""
 	if entName != "" {
@@ -155,30 +189,25 @@ func GetEntIdByQYXY(entName string) string {
 	return entId
 }
 
-//中标企业库是否有此企业注册金额
+// 中标企业库是否有此企业注册金额
 func GetWinnerCapitals(entName []string) map[string]int64 {
+	esSql := `{"query": {"bool": {"must": [{"terms": {"id": [%s]}}],"must_not": [],"should": []}},"_source":["id","capital"],"from": 0,"size": %d,"sort": [],"aggs": {}}`
+	querySql := fmt.Sprintf(esSql, strings.Join(entName, ","), len(entName))
+	r := elastic.Get("qyxy", "qyxy", querySql)
+	if r == nil || len(*r) == 0 {
+		return nil
+	}
 	entName_capitals := map[string]int64{}
-	if len(entName) > 0 {
-		query := map[string]interface{}{
-			"company_name": map[string]interface{}{
-				"$in": entName,
-			},
-		}
-		sess := db.Mgo_Ent.GetMgoConn()
-		defer db.Mgo_Ent.DestoryMongoConn(sess)
-		it := sess.DB(db.Mgo_Ent.DbName).C("winner_enterprise").Find(query).Select(map[string]interface{}{"company_name": 1, "capital": 1}).Iter()
-		for m := make(map[string]interface{}); it.Next(&m); {
-			if m["company_name"] != nil && m["company_name"].(string) != "" && m["capital"] != nil {
-				entName_capitals[m["company_name"].(string)] = qutil.Int64All(m["capital"])
-			}
-		}
+	for _, v := range *r {
+		id := util.EncodeId(qutil.InterfaceToStr(v["id"]))
+		entName_capitals[id] = qutil.Int64All(v["capital"])
 	}
 	return entName_capitals
 }
 
 var P_Starttime = "1514736000" //2018.01.01
 
-var RegWinner = regexp.MustCompile(".+[司院厂所心处普]$")
+var RegWinner = regexp.MustCompile(".+[司院厂所心处普学]$")
 
 type UserInfoLock struct {
 	sync.Mutex
@@ -195,7 +224,7 @@ func NewUserInfoLock() *UserInfoLock {
 	}
 }
 
-//决策分析-中标企业和采购单位 其他项目明细
+// 决策分析-中标企业和采购单位 其他项目明细
 type AnalysisDec struct {
 	Area             map[string]interface{} //地区
 	BuyerContent     []ViewKeyWord          //采购内容
@@ -210,11 +239,17 @@ type AnalysisDec struct {
 	MobileModel      string                 //手机型号
 	AppVersion       string                 //app版本号
 	Winner           string                 //中标企业
-	SearchType       int                    //默认0:中标企业||采购单位||(中标企业&&采购单位)-类似项目明细;1:中标企业和采购单位其他项目明细
+	SearchType       int                    //默认0:中标企业||采购单位||(中标企业&&采购单位)-类似项目明细;1:中标企业和采购单位其他项目明细 2:分析项目明细 3:专家项目明细
 	UserId           string                 //用户id
 	IsPower          bool                   //是否有权限
 	UserLock         sync.Mutex             //用户锁
 	Buyer_BuyerClass string                 //当前采购单位的采购单位类型
+	ExpertName       string                 //专家名字
+	ProjectScope     int                    //0 同类项目(默认搜索) 1 全部项目
+	LimitTime        string
+	SearchItem       int
+	Page             int //页码
+	PageSize         int //数量
 }
 
 /*已选条件--关键词*/
@@ -230,29 +265,30 @@ func CheckPower(session *httpsession.Session) (string, bool) {
 	return main_userId, member_status > 0
 }
 
-//
-func (this *AnalysisDec) GetProjectInfoByBW() (res []map[string]interface{}) {
-	this.UserLock.Lock()
-	defer this.UserLock.Unlock()
+func (this *AnalysisDec) GetProjectInfoByBW() (count int64, res []map[string]interface{}) {
+	//this.UserLock.Lock()
+	//defer this.UserLock.Unlock()
 	//采购单位的采购类型
-	if this.Buyer != "" {
-		buyerData := GetEntPC(strings.Split(this.Buyer, ","))
-		if buyerData != nil && len(buyerData) > 0 {
-			buyer_one := *qutil.ObjToMap(buyerData[0])
-			if buyer_one["buyerclass"] != nil {
-				this.Buyer_BuyerClass = buyer_one["buyerclass"].(string)
-			}
-		}
-	}
-	this.BuyerContent = BuyerContentStruct(this.BuyerContent)
+	//if this.Buyer != "" {
+	//	buyerData := GetEntPC(strings.Split(this.Buyer, ","))
+	//	if buyerData != nil && len(buyerData) > 0 {
+	//		buyer_one := *qutil.ObjToMap(buyerData[0])
+	//		if buyer_one["buyerclass"] != nil {
+	//			this.Buyer_BuyerClass = buyer_one["buyerclass"].(string)
+	//		}
+	//	}
+	//}
+	this.ParameterCheck()
+	//this.BuyerContent = BuyerContentStruct(this.BuyerContent)
 	//中标企业和采购单位类似项目明细
 	decQuery := this.DecQueryNewSimilarMsgByBW()
-	similarMsg, _idMap := this.GetAllMsgByBW(decQuery)
+	tm := time.Now()
 	//其他项目明细
 	switch this.SearchType {
-	case 0:
-		res = similarMsg
+	case 0: //分析项目明细||中标单位项目明细
+		_, count, res = elastic.GetAggs("projectset", "projectset", decQuery)
 	case 1:
+		_, _idMap := this.GetAllMsgByBW(decQuery)
 		//中标企业和采购单位 所有项目明细
 		allQuery := this.GetAllBWQueryByBW()
 		allMsg, _ := this.GetAllMsgByBW(allQuery)
@@ -265,11 +301,32 @@ func (this *AnalysisDec) GetProjectInfoByBW() (res []map[string]interface{}) {
 				res = append(res, v)
 			}
 		}
+	case 2: //中标单位top10项目明细
+		_, count, res = elastic.GetAggs("projectset", "projectset", decQuery)
+	case 3: // 专家明细
+		decQuery := GetReviewExpertsProjects(this.ExpertName, this.Area, this.BuyerContent, this.Buyer, this.LimitTime, this.SearchItem, this.ProjectScope, this.Page, this.PageSize)
+		_, count, res = elastic.GetAggs("projectset", "projectset", decQuery)
+		log.Println("各类项目明细耗时:", time.Since(tm))
+
+	}
+	log.Println("各类项目明细耗时:", time.Since(tm))
+	return count, NewSequence(res)
+}
+
+func (this *AnalysisDec) ParameterCheck() {
+	this.BuyerContent = BuyerContentStruct(this.BuyerContent)
+	switch this.SearchType {
+	case 0: //类似项目 过滤无用字段
+		this.Winner = ""
+		this.ExpertName = ""
+	case 2: //中标top10项目明细 过滤无用字段
+		this.ExpertName = ""
+	case 3: //专家项目明细 过滤无用字段
+		this.Winner = ""
 	}
-	return Sequence(res)
 }
 
-//获取数据
+// 获取数据
 func (this *AnalysisDec) GetAllMsgByBW(decQuery string) (res []map[string]interface{}, idMap map[string]bool) {
 	newRes := elastic.Get("projectset", "projectset", decQuery)
 	if newRes != nil {

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

@@ -1,6 +1,6 @@
 module jy/src/jfw/modules/bigmember/src
 
-go 1.20
+go 1.19
 
 require (
 	app.yhyue.com/moapp/jybase v0.0.0-20230523020646-528a068dac39

+ 77 - 41
src/jfw/modules/bigmember/src/service/analysis/analysis.go

@@ -19,23 +19,25 @@ import (
 
 type Analysis struct {
 	*xweb.Action
-	pName           xweb.Mapper `xweb:"/analysis/projectName"`     //根据项目名称关键词连带项目名称
-	pInfo           xweb.Mapper `xweb:"/analysis/projectInfo"`     //根据项目名称获取项目信息
-	csORRsList      xweb.Mapper `xweb:"/potential/corList"`        //潜在客户customers or 潜在竞争对手rivals
-	rMyRivals       xweb.Mapper `xweb:"/potential/rMyRivals"`      //移除我的潜在竞争对手rivals
-	decInfo         xweb.Mapper `xweb:"/decision/decInfo"`         //投标决策分析
-	trialInfo       xweb.Mapper `xweb:"/decision/trialInfo"`       //投标决策分析-使用用户 剩余次数
-	forPList        xweb.Mapper `xweb:"/forecast/forPList"`        //新项目预测结果list
-	forPContent     xweb.Mapper `xweb:"/forecast/forPContent"`     //新项目预测结果详情
-	fWData          xweb.Mapper `xweb:"/forecast/forWData"`        //中标预测分析
-	fWStatus        xweb.Mapper `xweb:"/forecast/forWStatus"`      //查看中标预测状态
-	fWResult        xweb.Mapper `xweb:"/forecast/forWResult"`      //中标预测结果
-	fWOvertime      xweb.Mapper `xweb:"/forecast/forWOvertime"`    //中标预测超时处理
-	bdInfoStatus    xweb.Mapper `xweb:"/forecast/bdInfoStatus"`    //中标预测-项目是否已完成招标
-	freeDecInfo     xweb.Mapper `xweb:"/decision/freeDecInfo"`     //投标决策分析-免费用户
-	potIndex        xweb.Mapper `xweb:"/potential/index"`          //潜在客户customers or 潜在竞争对手rivals 首页接口
-	projectInfoByBW xweb.Mapper `xweb:"/decision/projectInfoByBW"` //投标决策分析-采购单位和中标企业 其他项目明细/类似项目明细
-
+	pName            xweb.Mapper `xweb:"/analysis/projectName"`      //根据项目名称关键词连带项目名称
+	pInfo            xweb.Mapper `xweb:"/analysis/projectInfo"`      //根据项目名称获取项目信息
+	csORRsList       xweb.Mapper `xweb:"/potential/corList"`         //潜在客户customers or 潜在竞争对手rivals
+	rMyRivals        xweb.Mapper `xweb:"/potential/rMyRivals"`       //移除我的潜在竞争对手rivals
+	decInfo          xweb.Mapper `xweb:"/decision/decInfo"`          //投标决策分析
+	trialInfo        xweb.Mapper `xweb:"/decision/trialInfo"`        //投标决策分析-使用用户 剩余次数
+	forPList         xweb.Mapper `xweb:"/forecast/forPList"`         //新项目预测结果list
+	forPContent      xweb.Mapper `xweb:"/forecast/forPContent"`      //新项目预测结果详情
+	fWData           xweb.Mapper `xweb:"/forecast/forWData"`         //中标预测分析
+	fWStatus         xweb.Mapper `xweb:"/forecast/forWStatus"`       //查看中标预测状态
+	fWResult         xweb.Mapper `xweb:"/forecast/forWResult"`       //中标预测结果
+	fWOvertime       xweb.Mapper `xweb:"/forecast/forWOvertime"`     //中标预测超时处理
+	bdInfoStatus     xweb.Mapper `xweb:"/forecast/bdInfoStatus"`     //中标预测-项目是否已完成招标
+	freeDecInfo      xweb.Mapper `xweb:"/decision/freeDecInfo"`      //投标决策分析-免费用户
+	potIndex         xweb.Mapper `xweb:"/potential/index"`           //潜在客户customers or 潜在竞争对手rivals 首页接口
+	projectInfoByBW  xweb.Mapper `xweb:"/decision/projectInfoByBW"`  //投标决策分析-采购单位和中标企业 其他项目明细/类似项目明细
+	decReviewExperts xweb.Mapper `xweb:"/decision/decReviewExperts"` //投标决策分析-评标专家
+	getREProjects    xweb.Mapper `xweb:"/decision/getREProjects"`    //投标决策分析-评标专家de项目
+	hotWinnerTop     xweb.Mapper `xweb:"/decision/hotWinnerTop"`     //投标决策分析-同类热点中标企业top10
 }
 
 const (
@@ -104,16 +106,17 @@ func (this *Analysis) PInfo() {
 				buyerperson := qutil.ObjToString(ptdata["buyerperson"])         //采购联系人
 				buyertel := qutil.ObjToString(ptdata["buyertel"])               //采购联系方式
 				if this.GetString("D") == "" {
-					var keyArr = []map[string]interface{}{}
-					var a_key = []map[string]interface{}{}
+					var keyArr []map[string]interface{}
+					var a_key []map[string]interface{}
+
 					//查库获得大会员用户的信息
-					o_mb, ok := &map[string]interface{}{}, false
+					o_mb := &map[string]interface{}{}
 					o_mb = Compatible.Select(userId, `{"o_member_jy":1,"s_member_mainid":1,"i_member_sub_status":1}`)
 					if o_mb != nil && (*o_mb) != nil && (*o_mb)["s_member_mainid"] != nil && qutil.IntAllDef((*o_mb)["i_member_sub_status"], 0) == 1 { //如果是子账号 查询主账号信息
 						mainId := qutil.ObjToString((*o_mb)["s_member_mainid"])
 						o_mb = Compatible.Select(mainId, `{"o_member_jy":1}`)
 					}
-					if ok && o_mb != nil && (*o_mb) != nil && (*o_mb)["o_member_jy"] != nil {
+					if o_mb != nil && (*o_mb)["o_member_jy"] != nil {
 						o_member_jy := qutil.ObjToMap((*o_mb)["o_member_jy"])
 						if (*o_member_jy)["a_items"] != nil {
 							a_items := qutil.ObjArrToMapArr((*o_member_jy)["a_items"].([]interface{}))
@@ -136,12 +139,10 @@ func (this *Analysis) PInfo() {
 					}
 					if len(keyArr) == 0 {
 						if purchasing != "" {
-							if len(strings.Split(purchasing, ",")) > 0 {
-								for _, v := range strings.Split(purchasing, ",") {
-									keyArr = append(keyArr, map[string]interface{}{
-										"key": []string{v},
-									})
-								}
+							for _, v := range strings.Split(purchasing, ",") {
+								keyArr = append(keyArr, map[string]interface{}{
+									"key": []string{v},
+								})
 							}
 						}
 					}
@@ -173,6 +174,23 @@ func (this *Analysis) PInfo() {
 						}
 					}
 				} else {
+					var keyArr []ViewKeyWord
+					if purchasing != "" {
+						key := strings.Split(purchasing, ",")
+						if len(key) > 0 {
+							//最多取10个
+							if len(key) > 10 {
+								key = key[:10]
+							}
+							for _, v := range key {
+								keyArr = append(keyArr, ViewKeyWord{
+									Keyword:  []string{v},
+									MatchWay: 1,
+								})
+							}
+						}
+					}
+					ArrPS["buyerContent"] = keyArr
 					if s_subscopeclass != "" {
 						ArrPS["s_subscopeclass"] = s_subscopeclass
 					} else {
@@ -236,6 +254,7 @@ func (this *Analysis) PName() {
 	}
 	if this.Method() == METHOD {
 		var pName = this.GetString("pName")
+		var sType = this.GetString("sType")
 		limit := Config.RdProLimit //匹配项目数量
 		if limit == 0 {
 			limit = 10
@@ -243,25 +262,42 @@ func (this *Analysis) PName() {
 		if pName != "" {
 			if len([]rune(pName)) > 2 {
 				pName = strings.ReplaceAll(pName, "\"", "")
-				data := entity.GetProNameImmediate(pName, limit)
+				data := entity.GetProNameImmediate(sType, pName, limit)
 				ArrPS := []map[string]interface{}{}
 				if data != nil && len(data) > 0 {
 					var pjtMap = map[string]bool{}
-					for _, v := range data {
-						r_data := qutil.ObjToMap(v)
-						//过滤重复名称的项目
-						if pjtMap[(*r_data)["projectname"].(string)] {
-							continue
+					var buyerMap = map[string]bool{}
+					for _, r_data := range data {
+						//过滤重复名称
+						buyer := qutil.InterfaceToStr(r_data["buyer"])
+						projectname, _ := r_data["projectname"].(string)
+						if sType == "1" {
+							if buyer == "" || buyerMap[buyer] {
+								continue
+							}
+						} else {
+							if projectname == "" || pjtMap[projectname] {
+								continue
+							}
 						}
-						if (*r_data)["firsttime"] != nil {
-							firsttime := (*r_data)["firsttime"]
-							(*r_data)["firsttime"] = FormatDateWithObj(&firsttime, Date_Short_Layout)
+
+						if r_data["firsttime"] != nil {
+							firsttime := r_data["firsttime"]
+							r_data["firsttime"] = FormatDateWithObj(&firsttime, Date_Short_Layout)
+						}
+						if r_data["_id"] != nil {
+							r_data["s_id"] = util.EncodeId(r_data["_id"].(string))
+							delete(r_data, "_id")
+						}
+						if r_data["sourceinfoid"] != nil {
+							r_data["sourceinfoid"] = util.EncodeId(r_data["sourceinfoid"].(string))
+						}
+						if sType == "1" {
+							buyerMap[buyer] = true
+						} else {
+							pjtMap[projectname] = true
 						}
-						(*r_data)["s_id"] = util.EncodeId((*r_data)["_id"].(string))
-						(*r_data)["sourceinfoid"] = util.EncodeId((*r_data)["sourceinfoid"].(string))
-						delete(v, "_id")
-						pjtMap[(*r_data)["projectname"].(string)] = true
-						ArrPS = append(ArrPS, v)
+						ArrPS = append(ArrPS, r_data)
 					}
 				}
 				regMap.Data = ArrPS

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

@@ -2,37 +2,39 @@
 package analysis
 
 import (
+	elastic "app.yhyue.com/moapp/jybase/es"
 	"encoding/json"
 	"fmt"
 	"jy/src/jfw/modules/bigmember/src/config"
 	"jy/src/jfw/modules/bigmember/src/entity"
 	"jy/src/jfw/modules/bigmember/src/util"
 	"log"
-	"sort"
 	"strconv"
-	"strings"
 	"sync"
 	"time"
 
 	. "app.yhyue.com/moapp/jybase/api"
 	qutil "app.yhyue.com/moapp/jybase/common"
-	. "app.yhyue.com/moapp/jybase/date"
 	"app.yhyue.com/moapp/jypkg/common/src/qfw/util/jy"
 )
 
 type DecParam struct {
-	Area         map[string]interface{} //地区
-	BuyerContent []ViewKeyWord          //采购内容
-	BuyerClass   []string               //采购单位行业
-	Sid          string                 //项目招标信息id
-	Pname        string                 //项目名称
-	Industry     string                 //招标行业
-	MinPrice     int                    //最小价格
-	MaxPrice     int                    //最大价格
-	Buyer        string                 //采购单位
-	ServiceId    int                    //大会员服务id
-	MobileModel  string                 //手机型号
-	AppVersion   string                 //app版本号
+	SearchItem    int
+	Area          map[string]interface{} //地区
+	BuyerContent  []ViewKeyWord          //采购内容
+	BuyerClass    []string               //采购单位行业
+	Sid           string                 //项目招标信息id
+	Pname         string                 //项目名称
+	Industry      string                 //招标行业
+	MinPrice      int                    //最小价格
+	MaxPrice      int                    //最大价格
+	Buyer         string                 //采购单位
+	ServiceId     int                    //大会员服务id
+	MobileModel   string                 //手机型号
+	AppVersion    string                 //app版本号
+	LimitTime     string                 //检索日期
+	ProjectScope  int                    //0 同类项目(默认搜索) 1 全部项目
+	HotWinnerType int                    // 热门中标企业top10 排序 0 默认金额排序 1:数量
 }
 
 /*已选条件--关键词*/
@@ -43,6 +45,19 @@ type ViewKeyWord struct {
 	MatchWay int      `json:"matchway"`  //匹配模式
 }
 
+type GetProParam struct {
+	ExpertName   string //专家名字
+	LimitTime    string //检索日期
+	ProjectScope int    //0 同类项目(默认搜索) 1 全部项目
+	SearchItem   int
+	Area         map[string]interface{} //地区
+	Buyer        string                 //采购单位
+	ServiceId    int                    //大会员服务id
+	BuyerContent []ViewKeyWord          //采购内容
+	Page         int
+	PageSize     int
+}
+
 // 投标决策分析id
 var ServiceId = 6
 
@@ -59,7 +74,7 @@ func (this *Analysis) ProjectInfoByBW() {
 		EAD := entity.AnalysisDec{}
 		//接收参数
 		json.Unmarshal(this.Body(), &EAD)
-		if EAD.Sid == "" || EAD.Pname == "" || len(EAD.BuyerContent) == 0 {
+		if len(EAD.BuyerContent) == 0 {
 			return Result{Data: nil, Error_msg: Error_msg_1003}
 		}
 		//是否是大会员用户
@@ -67,8 +82,10 @@ func (this *Analysis) ProjectInfoByBW() {
 			return Result{Data: nil, Error_msg: Error_msg_1004}
 		}
 		EAD.ServiceId = ServiceId
-		EAD.UserLock = *entity.ThisLock(EAD.UserId)
-		return Result{Data: EAD.GetProjectInfoByBW()}
+		//EAD.UserLock = *entity.ThisLock(EAD.UserId)
+
+		count, res := EAD.GetProjectInfoByBW()
+		return Result{Data: map[string]interface{}{"count": count, "res": res}}
 	}()
 	this.ServeJson(r)
 }
@@ -131,7 +148,8 @@ func (this *Analysis) FreeDecInfo() {
 			//接收参数
 			json.Unmarshal(this.Body(), &getRes)
 		}
-		if getRes.Sid != "" && getRes.Pname != "" && len(getRes.BuyerContent) > 0 {
+
+		if getRes.Area != nil && getRes.Buyer != "" && len(getRes.BuyerContent) > 0 {
 			userId, _ := this.GetSession("userId").(string)
 			bigMsg := jy.GetBigVipUserBaseMsg(this.Session(), *config.Middleground)
 			mainUserid, phone := qutil.If(bigMsg.Data.Member.Pid != "", bigMsg.Data.Member.Pid, userId).(string), bigMsg.Data.Free.Phone
@@ -147,17 +165,8 @@ func (this *Analysis) FreeDecInfo() {
 			}
 			//采购单位的采购类型
 			buyer_buyerClass := ""
-			if getRes.Buyer != "" {
-				buyerData := entity.GetEntPC(strings.Split(getRes.Buyer, ","))
-				if buyerData != nil && len(buyerData) > 0 {
-					buyer_one := *qutil.ObjToMap(buyerData[0])
-					if buyer_one["buyerclass"] != nil {
-						buyer_buyerClass = buyer_one["buyerclass"].(string)
-					}
-				}
-			}
 			getRes.BuyerContent = BuyerContentStruct(getRes.BuyerContent)
-			decQuery := DecQueryFree(getRes.Area, getRes.BuyerClass, getRes.BuyerContent, getRes.Industry, getRes.Buyer, buyer_buyerClass, getRes.MinPrice, getRes.MaxPrice)
+			decQuery := DecQueryFree(getRes.Area, getRes.BuyerContent, getRes.LimitTime, getRes.Buyer, getRes.SearchItem)
 			regMap.Data = getDecInfoFree(decQuery, buyer_buyerClass, getRes)
 			//投标决策分析历史记录
 			go SaveDecHistortList(getRes, userId, mainUserid, phone, "", 0, this.Request, "free")
@@ -187,7 +196,8 @@ func (this *Analysis) DecInfo() {
 			//接收参数
 			json.Unmarshal(this.Body(), &getRes)
 		}
-		if getRes.Sid != "" && getRes.Pname != "" && len(getRes.BuyerContent) > 0 {
+
+		if getRes.Area != nil && getRes.Buyer != "" && len(getRes.BuyerContent) > 0 {
 			var decCount = 0   //功能剩余次数
 			var base64Key = "" //加密串
 			userId, _ := this.GetSession("userId").(string)
@@ -217,23 +227,236 @@ func (this *Analysis) DecInfo() {
 				if getRes.ServiceId == 0 {
 					getRes.ServiceId = 6
 				}
-				// getRes.Buyer = "北京市交通委员会密云公路分局"
+				var buyer_buyerClass string
+				//采购单位的采购类型
+				/*
+				   if getRes.Buyer != "" {
+				   	buyerData := entity.GetEntBlur(strings.Split(getRes.Buyer, ","))
+				   	if buyerData != nil && len(buyerData) > 0 {
+				   		buyer_one := *qutil.ObjToMap(buyerData[0])
+				   		if buyer_one["buyerclass"] != nil {
+				   			buyer_buyerClass = buyer_one["buyerclass"].(string)
+				   		}
+				   	}
+				   }*/
+				getRes.BuyerContent = BuyerContentStruct(getRes.BuyerContent)
+				//各维度项目数量
+				all_count, area_count, buyer_count := AnalyzeNumber(getRes.Area, getRes.BuyerContent, getRes.Buyer, getRes.LimitTime)
+				var isAnalyze bool
+				if all_count == 0 || (getRes.SearchItem == 1 && buyer_count == 0) ||
+					(getRes.SearchItem == 2 && area_count == 0) {
+					isAnalyze = true
+				}
+				if isAnalyze {
+					regMap.Data = map[string]interface{}{
+						"PAnalysis":  nil,
+						"PCount":     all_count,
+						"AreaCount":  area_count,
+						"BuyerCount": buyer_count,
+					}
+					this.ServeJson(regMap)
+					return
+				}
+
+				var rMap = sync.Map{}
+				sy := sync.WaitGroup{}
+				for _, v := range []int{1, 2, 3} {
+					sy.Add(1)
+					go func(stype int) {
+						defer sy.Done()
+						decQuery := DecQuery(getRes.Area, getRes.BuyerContent, getRes.Buyer, getRes.LimitTime, getRes.SearchItem, stype)
+						aggsArr := getDecInfo(decQuery, buyer_buyerClass, getRes, stype)
+						for k, v1 := range aggsArr {
+							rMap.Store(k, v1)
+						}
+					}(v)
+				}
+				sy.Wait()
+				rMaps := make(map[string]interface{})
+				rMap.Range(func(key, value interface{}) bool {
+					rMaps[qutil.InterfaceToStr(key)] = value
+					return true
+				})
+				regMap.Data = map[string]interface{}{
+					"PAnalysis":  rMaps,
+					"PCount":     all_count,
+					"AreaCount":  area_count,
+					"BuyerCount": buyer_count,
+				}
+				//投标决策分析历史记录
+				go SaveDecHistortList(getRes, userId, mainUserid, phone, base64Key, decCount, this.Request, "pay")
+			}
+		} else {
+			regMap.Error_code = Error_code_1002
+			regMap.Error_msg = Error_msg_1002
+		}
+	} else {
+		regMap.Error_code = Error_code_1005
+		regMap.Error_msg = Error_msg_1005
+	}
+	this.ServeJson(regMap)
+}
+
+func (this *Analysis) HotWinnerTop() {
+	defer qutil.Catch()
+	var regMap = Result{
+		Data:       []map[string]interface{}{},
+		Error_code: Error_code,
+		Error_msg:  "",
+	}
+	if this.Method() == METHOD {
+		//接受前端参数
+		getRes := new(DecParam)
+		if string(this.Body()) != "" {
+			//接收参数
+			json.Unmarshal(this.Body(), &getRes)
+		}
+
+		if getRes.Area != nil && getRes.Buyer != "" && len(getRes.BuyerContent) > 0 {
+			//是否是子账号
+			//main_userId, phone, member_status := util.MainUserId(this.Session())
+			bigMsg := jy.GetBigVipUserBaseMsg(this.Session(), *config.Middleground)
+			isAble := false
+			if len(bigMsg.Data.Member.MemberPowerList) > 0 {
+				for _, v := range bigMsg.Data.Member.MemberPowerList {
+					if v == 6 {
+						isAble = true
+					}
+				}
+			}
+			if !isAble {
+				regMap.Error_code = Error_code_1004
+				regMap.Error_msg = Error_msg_1004
+			} else {
+				if getRes.ServiceId == 0 {
+					getRes.ServiceId = 6
+				}
 				//采购单位的采购类型
 				buyer_buyerClass := ""
-				if getRes.Buyer != "" {
-					buyerData := entity.GetEntPC(strings.Split(getRes.Buyer, ","))
-					if buyerData != nil && len(buyerData) > 0 {
-						buyer_one := *qutil.ObjToMap(buyerData[0])
-						if buyer_one["buyerclass"] != nil {
-							buyer_buyerClass = buyer_one["buyerclass"].(string)
+				getRes.BuyerContent = BuyerContentStruct(getRes.BuyerContent)
+				decQuery := DecWinnerQuery(getRes.Area, getRes.BuyerContent, getRes.Buyer, getRes.LimitTime, getRes.SearchItem, getRes.HotWinnerType)
+				aggsArr := getDecInfo(decQuery, buyer_buyerClass, getRes, 0)
+				//top明细数量错误问题特殊处理 数量重新查询
+				var rMap = sync.Map{}
+				sy := sync.WaitGroup{}
+				winnerAmount, _ := aggsArr["winnerAmount"].([]*DecWinnerInfo)
+				if len(winnerAmount) > 0 {
+					for _, v := range winnerAmount {
+						sy.Add(1)
+						go func(winner string) {
+							defer sy.Done()
+							winnerSql := DecQueryNewSimilarMsgByBW(winner, getRes, 0)
+							_, count, _ := elastic.GetAggs(P_INDEX, P_TYPE, winnerSql)
+							rMap.Store(winner, count)
+						}(v.Key)
+					}
+					sy.Wait()
+					for _, v := range winnerAmount {
+						if v1, ok := rMap.Load(v.Key); ok {
+							v.Doc_count = qutil.Float64All(v1)
 						}
 					}
+					sortkey := "doc_count" //默认金额
+					if getRes.HotWinnerType == 0 {
+						sortkey = "total_project"
+					}
+					util.SortData(&winnerAmount, sortkey, true) //排序
+					aggsArr["winnerAmount"] = winnerAmount
+				}
+
+				regMap.Data = map[string]interface{}{
+					"PAnalysis": aggsArr,
+				}
+			}
+		} else {
+			regMap.Error_code = Error_code_1002
+			regMap.Error_msg = Error_msg_1002
+		}
+	} else {
+		regMap.Error_code = Error_code_1005
+		regMap.Error_msg = Error_msg_1005
+	}
+	this.ServeJson(regMap)
+}
+
+// 决策分析内容-评标专家top十
+func (this *Analysis) DecReviewExperts() {
+	defer qutil.Catch()
+	var regMap = Result{
+		Data:       []map[string]interface{}{},
+		Error_code: Error_code,
+		Error_msg:  "",
+	}
+	if this.Method() == METHOD {
+		//接受前端参数
+		getRes := new(DecParam)
+		if string(this.Body()) != "" {
+			//接收参数
+			json.Unmarshal(this.Body(), &getRes)
+		}
+
+		if getRes.Area != nil && getRes.Buyer != "" && len(getRes.BuyerContent) > 0 {
+			//是否是子账号
+			//main_userId, phone, member_status := util.MainUserId(this.Session())
+			bigMsg := jy.GetBigVipUserBaseMsg(this.Session(), *config.Middleground)
+			isAble := false
+			if len(bigMsg.Data.Member.MemberPowerList) > 0 {
+				for _, v := range bigMsg.Data.Member.MemberPowerList {
+					if v == 6 {
+						isAble = true
+					}
+				}
+			}
+			if !isAble {
+				regMap.Error_code = Error_code_1004
+				regMap.Error_msg = Error_msg_1004
+			} else {
+				if getRes.ServiceId == 0 {
+					getRes.ServiceId = 6
+				}
+				//各维度项目数量
+				all_count, area_count, buyer_count := AnalyzeNumber(getRes.Area, getRes.BuyerContent, getRes.Buyer, getRes.LimitTime)
+				var isAnalyze bool
+				if all_count == 0 || (getRes.SearchItem == 1 && buyer_count == 0) ||
+					(getRes.SearchItem == 2 && area_count == 0) {
+					isAnalyze = true
+				}
+				if isAnalyze {
+					regMap.Data = map[string]interface{}{
+						"PAnalysis": nil,
+					}
+					this.ServeJson(regMap)
+					return
 				}
+				// getRes.Buyer = "北京市交通委员会密云公路分局"
+				//采购单位的采购类型
+				buyer_buyerClass := ""
 				getRes.BuyerContent = BuyerContentStruct(getRes.BuyerContent)
-				decQuery := DecQuery(getRes.Area, getRes.BuyerClass, getRes.BuyerContent, getRes.Industry, getRes.Buyer, buyer_buyerClass, getRes.MinPrice, getRes.MaxPrice)
-				regMap.Data = getDecInfo(decQuery, buyer_buyerClass, getRes)
+				decQuery := DecReviewExpertsQuery(getRes.Area, getRes.BuyerContent, getRes.Buyer, buyer_buyerClass, getRes.LimitTime, getRes.SearchItem, getRes.ProjectScope)
+				aggsArr := getDecInfo(decQuery, buyer_buyerClass, getRes, 0)
+				//log.Println("专家top10", aggsArr["reviewExperts"])
+				var expertlist []map[string]interface{}
+				if reviewExperts, ok := aggsArr["reviewExperts"].([]map[string]interface{}); ok {
+					for k, v := range reviewExperts {
+						if k < 10 {
+							expertName := qutil.ObjToString(v["key"])
+							decQuery := ExpertsCooperationProjectCount(expertName, getRes.Area, getRes.BuyerContent, getRes.Buyer, getRes.LimitTime, getRes.SearchItem, getRes.ProjectScope)
+							_, count, _ := elastic.GetAggs("projectset", "projectset", decQuery)
+							v["doc_count"] = count
+							expertlist = append(expertlist, v)
+						} else {
+							break
+						}
+					}
+					util.SortData(&expertlist, "doc_count", true)
+					aggsArr["reviewExperts"] = expertlist
+				}
+
+				regMap.Data = map[string]interface{}{
+					"PAnalysis": aggsArr,
+				}
 				//投标决策分析历史记录
-				go SaveDecHistortList(getRes, userId, mainUserid, phone, base64Key, decCount, this.Request, "pay")
+				//go SaveDecHistortList(getRes, userId, mainUserid, phone, base64Key, decCount, this.Request, "pay")
 			}
 		} else {
 			regMap.Error_code = Error_code_1002
@@ -246,6 +469,31 @@ func (this *Analysis) DecInfo() {
 	this.ServeJson(regMap)
 }
 
+type TRecentProject struct {
+	//RecentProject struct {
+	Hits struct {
+		Total struct {
+			Value    int    `json:"value"`
+			Relation string `json:"relation"`
+		} `json:"total"`
+		MaxScore interface{} `json:"max_score"`
+		Hits     []struct {
+			Index  string      `json:"_index"`
+			Type   string      `json:"_type"`
+			Id     string      `json:"_id"`
+			Score  interface{} `json:"_score"`
+			Source struct {
+				Bidamount   float64 `json:"bidamount"`
+				Projectname string  `json:"projectname"`
+				Jgtime      int     `json:"jgtime"`
+				Id          string  `json:"id"`
+			} `json:"_source"`
+			Sort []int `json:"sort"`
+		} `json:"hits"`
+	} `json:"hits"`
+	//} `json:"recent_project"`
+}
+
 // 投标决策分析
 func getDecInfoFree(decQuery, buyer_buyerClass string, dec *DecParam) map[string]interface{} {
 	t1 := time.Now()
@@ -299,44 +547,41 @@ func getDecInfoFree(decQuery, buyer_buyerClass string, dec *DecParam) map[string
 }
 
 // 投标决策分析
-func getDecInfo(decQuery, buyer_buyerClass string, dec *DecParam) map[string]interface{} {
+func getDecInfo(decQuery, buyer_buyerClass string, dec *DecParam, buyerSty int) map[string]interface{} {
 	t1 := time.Now()
 	//
 	var aggsArr = map[string]interface{}{}
-	//类似项目采购单位采购历史
-	var buyerHistroyList = []map[string]interface{}{}
-	if dec.Buyer != "" {
-		list := GetListByBuyer(dec)
-		if list != nil && len(list) > 0 {
-			for _, v := range list {
-				var firsttime = v["firsttime"]
-				infoid := ""
-				if v["ids"] != nil {
-					ids := qutil.ObjArrToStringArr(v["ids"].([]interface{}))
-					if len(ids) > 0 {
-						infoid = util.EncodeId(ids[0])
-					}
-				}
-				var projectMap = map[string]interface{}{
-					"projectname": v["projectname"],
-					"_id":         util.EncodeId(v["_id"].(string)),
-					"area":        v["area"],
-					"bidstatus":   v["bidstatus"],
-					"firsttime":   FormatDateWithObj(&firsttime, Date_Short_Layout),
-					"infoid":      infoid,
-				}
-				buyerHistroyList = append(buyerHistroyList, projectMap)
-			}
-		}
-	}
-	// log.Println("buyerHistroyList.length:", len(buyerHistroyList))
-	aggsArr["buyerHistroyList"] = buyerHistroyList
+	/*
+		//类似项目采购单位采购历史
+		var buyerHistroyList = []map[string]interface{}{}
+		  if dec.Buyer != "" && buyerSty == 1 {
+		  	list := GetListByBuyer(dec)
+		  	if list != nil && len(list) > 0 {
+		  		for _, v := range list {
+		  			var firsttime = v["firsttime"]
+		  			infoid := ""
+		  			if v["ids"] != nil {
+		  				ids := qutil.ObjArrToStringArr(v["ids"].([]interface{}))
+		  				if len(ids) > 0 {
+		  					infoid = util.EncodeId(ids[0])
+		  				}
+		  			}
+		  			var projectMap = map[string]interface{}{
+		  				"projectname": v["projectname"],
+		  				"_id":         util.EncodeId(v["_id"].(string)),
+		  				"area":        v["area"],
+		  				"bidstatus":   v["bidstatus"],
+		  				"firsttime":   FormatDateWithObj(&firsttime, Date_Short_Layout),
+		  				"infoid":      infoid,
+		  			}
+		  			buyerHistroyList = append(buyerHistroyList, projectMap)
+		  		}
+		  	}
+		  	aggsArr["buyerHistroyList"] = buyerHistroyList
+		  }*/
 	//聚合
-	aggs, res := GetAggs(P_INDEX, P_TYPE, decQuery)
-	log.Println("请求数据时间:", time.Since(t1))
-	if res != nil && len(res) > 0 {
-		res = Sequence(res)
-	}
+	aggs, _ := GetAggs(P_INDEX, P_TYPE, decQuery)
+
 	log.Println("-请求数据时间-:", time.Since(t1))
 	if aggs != nil {
 		//标书编制周期
@@ -439,7 +684,7 @@ func getDecInfo(decQuery, buyer_buyerClass string, dec *DecParam) map[string]int
 								continue
 							}
 							var this_bool = false
-							if buyer_buyerClass == v["key"].(string) {
+							if buyer_buyerClass != "" && buyer_buyerClass == v["key"].(string) {
 								buyer_buyerClass_bool = true
 								this_bool = true
 							}
@@ -551,12 +796,24 @@ func getDecInfo(decQuery, buyer_buyerClass string, dec *DecParam) map[string]int
 			if len(bs) > 0 {
 				json.Unmarshal(bs, &aggsMap)
 				if len(aggsMap) > 0 {
-					// log.Println(aggsMap)
+					if len(aggsMap) > 10 {
+						aggsMap = aggsMap[:10]
+					}
 					var _aggsMap = []map[string]interface{}{}
 					for k, v := range aggsMap {
 						if !entity.RegExperts.MatchString(qutil.ObjToString(v["key"])) {
 							continue
 						}
+						var recentProject TRecentProject
+						rp, err := json.Marshal(v["recent_project"])
+						if err == nil {
+							err = json.Unmarshal(rp, &recentProject)
+							if err == nil && len(recentProject.Hits.Hits) > 0 {
+								data := recentProject.Hits.Hits[0]
+								v["jgtime"] = data.Source.Jgtime //成交时间
+							}
+						}
+						delete(aggsMap[k], "recent_project")
 						_aggsMap = append(_aggsMap, aggsMap[k])
 					}
 					aggsArr["reviewExperts"] = _aggsMap
@@ -592,18 +849,37 @@ func getDecInfo(decQuery, buyer_buyerClass string, dec *DecParam) map[string]int
 				var winners = []string{}
 				json.Unmarshal(bs, &aggsMap)
 				if len(aggsMap) > 0 {
+					if len(aggsMap) > 10 {
+						aggsMap = aggsMap[:10]
+					}
 					var buckets = []*DecWinnerInfo{}
 					for _, v := range aggsMap {
-						if !entity.RegWinner.MatchString(qutil.ObjToString(v["key"])) {
-							continue
-						}
+						//if !entity.RegWinner.MatchString(qutil.ObjToString(v["key"])) {
+						//	continue
+						//}
 						//类似项目金额
 						var total_map = *qutil.ObjToMap(v["total"].(map[string]interface{}))
 						var total_project = 0
 						if total_map["value"] != nil {
 							total_project = qutil.IntAll(total_map["value"])
 						}
-						//
+
+						//中标企业最近合作项目
+						var recentProject TRecentProject
+						latestProject := make(map[string]interface{})
+						rp, err := json.Marshal(v["recent_project"])
+						if err == nil {
+							err = json.Unmarshal(rp, &recentProject)
+							if err == nil && len(recentProject.Hits.Hits) > 0 {
+								latestProject["_id"] = recentProject.Hits.Hits[0].Id
+								data := recentProject.Hits.Hits[0]
+								latestProject["_id"] = util.EncodeId(data.Id)
+								latestProject["bidamount"] = data.Source.Bidamount     //金额
+								latestProject["projectname"] = data.Source.Projectname //项目名称
+								latestProject["jgtime"] = data.Source.Jgtime           //成交时间
+							}
+						}
+
 						var max_jytime_map = *qutil.ObjToMap(v["max_jytime"].(map[string]interface{}))
 						var max_jytime int64 = 0
 						if max_jytime_map["value"] != nil {
@@ -617,13 +893,15 @@ func getDecInfo(decQuery, buyer_buyerClass string, dec *DecParam) map[string]int
 							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"]))
+							ent_id := qutil.ObjToString(buckets[0]["key"])
+							winners = append(winners, fmt.Sprintf(`"%s"`, ent_id))
+							entId = util.EncodeId(ent_id)
 						}
 						//此中标企业与采购单位类似项目采购历史
 						var buyer_similar_list = BuyerSOOL{}
 						//此中标企业与采购单位其它项目采购历史
 						var buyer_other_list = BuyerSOOL{}
-						if dec.Buyer != "" {
+						/*if dec.Buyer != "" {
 							var buyer_map = *qutil.ObjToMap(v["this_buyer"].(map[string]interface{}))
 							var buyer_map_count = buyer_map["doc_count"] //类似项目数量
 							var buyer_map_tatil_map = *qutil.ObjToMap(buyer_map["total"].(map[string]interface{}))
@@ -641,7 +919,7 @@ func getDecInfo(decQuery, buyer_buyerClass string, dec *DecParam) map[string]int
 										if jgtime != nil && bid_winner_time == "" {
 											bid_winner_time = FormatDateWithObj(&jgtime, "2006/01/02")
 										}
-										buyer_winner_map[hits_source_map["_id"].(string)] = hits_source_map["jgtime"]
+										buyer_winner_map[qutil.InterfaceToStr(hits_source_map["id"])] = hits_source_map["jgtime"]
 									}
 								}
 							}
@@ -682,9 +960,8 @@ func getDecInfo(decQuery, buyer_buyerClass string, dec *DecParam) map[string]int
 									bid_winner_time,
 								}
 							}
-						}
+						}*/
 						//中标企业名称
-						winners = append(winners, v["key"].(string))
 						buckets = append(buckets, &DecWinnerInfo{
 							v["key"].(string),        //中标企业名称
 							v["doc_count"].(float64), //类似项目总数
@@ -694,141 +971,38 @@ func getDecInfo(decQuery, buyer_buyerClass string, dec *DecParam) map[string]int
 							0,                        //中标企业注册资本
 							entId,                    //中标企业加密id
 							max_jytime,               //类似项目中标时间
+							latestProject,            //中标企业最近合作项目
 						})
 					}
 					//获取中标企业注资金信息
-					capitals := entity.GetWinnerCapitals(winners)
-					var isSortBool = false
-					var bvdoc_count float64 = -1
-					var bvtotal_project = -1
-					for k, v := range buckets {
-						//类似项目或者其它项目
-						if k > 0 && (v.Buyer_other_list.Doc_count > 0 || v.Buyer_similar_list.Doc_count > 0) {
-							isSortBool = true
-						}
-						//项目数相同 且 此中标企业金额大于前一个中标企业金额 允许再次排序
-						if bvdoc_count == v.Doc_count && bvtotal_project < v.Total_project {
-							isSortBool = true
-						}
-						bvdoc_count = v.Doc_count
-						bvtotal_project = v.Total_project
-						v.Capital = capitals[v.Key]
-					}
-					//根据金额二次排序
-					fmt.Println("isSortBool:", isSortBool)
-					if isSortBool {
-						sort.Sort(DWIArray(buckets))
-					}
+					/*capitals := entity.GetWinnerCapitals(winners)
+					  log.Println("查询获取中标企业注资金信息消耗时间", time.Since(t1))
+					  var isSortBool = false
+					  var bvdoc_count float64 = -1
+					  var bvtotal_project = -1
+					  for _, v := range buckets {
+					  	//类似项目或者其它项目
+					  	if k > 0 && (v.Buyer_other_list.Doc_count > 0 || v.Buyer_similar_list.Doc_count > 0) {
+					  	   isSortBool = true
+					  	}
+					  	//项目数相同 且 此中标企业金额大于前一个中标企业金额 允许再次排序
+					  	if bvdoc_count == v.Doc_count && bvtotal_project < v.Total_project {
+					  	   isSortBool = true
+					  	}
+					  	bvdoc_count = v.Doc_count
+					  	bvtotal_project = v.Total_project
+					  	v.Capital = capitals[v.EntId]
+					  }
+					  //根据金额二次排序
+					  fmt.Println("isSortBool:", isSortBool)
+					  if isSortBool {
+					     sort.Sort(DWIArray(buckets))
+					  }*/
 					aggsArr["winnerAmount"] = buckets
 				}
 			}
 		}
 	}
 	log.Println("运行时间:", time.Since(t1))
-	return map[string]interface{}{
-		"PDeatils":  res,
-		"PAnalysis": aggsArr,
-	}
-}
-
-// 决策分析 根据字段权重排序 中标企业和中标价格
-var (
-	bidtype_score        = 1 //采购方式
-	review_experts_score = 1 //评审专家
-	zbtime_score         = 1 //招标时间
-	bidamount_score      = 2 //中标价格
-	budget_score         = 2 //预算
-	project_rate_score   = 1 //折扣率
-	winnerorder_score    = 1 //中标候选人
-)
-
-func Sequence(seqData []map[string]interface{}) []map[string]interface{} {
-	var sequenceArr3 = []map[string]interface{}{}
-	var sequenceArr4 = []map[string]interface{}{}
-	var sequenceArr5 = []map[string]interface{}{}
-	var sequenceArr6 = []map[string]interface{}{}
-	var sequenceArr7 = []map[string]interface{}{}
-	var sequenceArr8 = []map[string]interface{}{}
-	var sequenceArr9 = []map[string]interface{}{}
-	for k, v := range seqData {
-		var score = 0
-		if v["s_winner"] == nil {
-			var s_winner = qutil.ObjToString(v["s_winner"])
-			var s_length = 0
-			for _, v := range strings.Split(s_winner, ",") {
-				if entity.RegWinner.MatchString(v) {
-					s_length += 1
-				}
-			}
-			if s_length == 0 {
-				continue
-			}
-		}
-		//评审专家
-		review_experts := []string{}
-		if v["review_experts"] != nil {
-			for _, v := range qutil.ObjArrToStringArr(v["review_experts"].([]interface{})) {
-				if entity.RegExperts.MatchString(v) {
-					review_experts = append(review_experts, v)
-				}
-			}
-			v["review_experts"] = review_experts
-		}
-		if len(review_experts) > 0 {
-			score += review_experts_score
-		}
-		//采购方式
-		if v["bidtype"] != nil && qutil.ObjToString(v["bidtype"].(string)) != "" {
-			score += bidtype_score
-		}
-		//招标时间
-		if v["firsttime"] != nil && qutil.Float64All(v["firsttime"].(float64)) > 0 {
-			score += zbtime_score
-		}
-		//预算
-		if v["budget"] != nil && qutil.Float64All(v["budget"].(float64)) > 0 {
-			score += budget_score
-		}
-		//中标价格
-		if v["bidamount"] != nil && qutil.Float64All(v["bidamount"].(float64)) > 0 {
-			score += bidamount_score
-		}
-		//折扣率
-		if v["project_rate"] != nil && qutil.Float64All(v["project_rate"].(float64)) > 0 {
-			score += project_rate_score
-		}
-		//中标候选人
-		if v["winnerorder"] != nil && len(qutil.ObjArrToStringArr(v["winnerorder"].([]interface{}))) > 0 {
-			score += winnerorder_score
-		}
-		//低于三分排除
-		if score < 4 {
-			// continue
-		}
-		if v["ids"] != nil {
-			ids := qutil.ObjArrToStringArr(v["ids"].([]interface{}))
-			if len(ids) > 0 {
-				v["infoid"] = util.EncodeId(ids[0])
-				delete(v, "ids")
-			}
-		}
-		v["_id"] = util.EncodeId(v["_id"].(string))
-		switch score {
-		case 4:
-			sequenceArr4 = append(sequenceArr4, seqData[k])
-		case 5:
-			sequenceArr5 = append(sequenceArr5, seqData[k])
-		case 6:
-			sequenceArr6 = append(sequenceArr6, seqData[k])
-		case 7:
-			sequenceArr7 = append(sequenceArr7, seqData[k])
-		case 8:
-			sequenceArr8 = append(sequenceArr8, seqData[k])
-		case 9:
-			sequenceArr9 = append(sequenceArr9, seqData[k])
-		default:
-			sequenceArr3 = append(sequenceArr3, seqData[k])
-		}
-	}
-	return append(append(append(append(append(append(sequenceArr9, sequenceArr8...), sequenceArr7...), sequenceArr6...), sequenceArr5...), sequenceArr4...), sequenceArr3...)
+	return aggsArr
 }

文件差异内容过多而无法显示
+ 691 - 179
src/jfw/modules/bigmember/src/service/analysis/esquery.go


+ 2 - 0
src/jfw/modules/bigmember/src/service/analysis/power.go

@@ -125,6 +125,8 @@ func SaveDecHistortList(res *DecParam, userId, main_userId, phone, base64Key str
 		"maxPrice":     res.MaxPrice,
 		"minPrice":     res.MinPrice,
 		"pname":        res.Pname,
+		"limitTime":    res.LimitTime,
+		"searchItem":   res.SearchItem,
 		"sid":          res.Sid,
 	}
 	//dev3.4.1版本前试用用户 有使用次数限制

+ 9 - 11
src/jfw/modules/bigmember/src/service/analysis/util.go

@@ -74,7 +74,6 @@ func (this *SelectC) Base64Keys() (baseKey string) {
 	return
 }
 
-//
 func GetBase64KeyForPotential(userId, area, buyerClass, business_scope, entName, industry string) (signedStr string) {
 	var param = [][]string{
 		[]string{"userId", userId},
@@ -100,7 +99,6 @@ func GetBase64KeyForPotential(userId, area, buyerClass, business_scope, entName,
 	return
 }
 
-//
 func GetBase64Key(userId, pname, sid string) (signedStr string) {
 	var param = [][]string{
 		[]string{"userId", userId},
@@ -123,7 +121,6 @@ func GetBase64Key(userId, pname, sid string) (signedStr string) {
 	return
 }
 
-//
 func GetRedisBase64Key(pname, area, city, buyer string, buyerContent []string) (signedStr string) {
 	if len(buyerContent) > 0 {
 		sort.Slice(buyerContent, func(i, j int) bool {
@@ -192,14 +189,15 @@ func (this *SignStr) Swap(i, j int) {
 //投标决策分析-类似项目热点中标企业排序
 
 type DecWinnerInfo struct {
-	Key                string    `json:"key"`                //中标企业名称
-	Doc_count          float64   `json:"doc_count"`          //项目数量
-	Total_project      int       `json:"total_project"`      //项目金额
-	Buyer_similar_list BuyerSOOL `json:"buyer_similar_list"` //与采购单位类似项目合作历史
-	Buyer_other_list   BuyerSOOL `json:"buyer_other_list"`   //与采购单位其他项目合作历史
-	Capital            int64     `json:"capital"`            //中标企业注册资本
-	EntId              string    `json:"entId"`              //中标企业加密id
-	Max_jytime         int64     `json:"max_jytime"`         //类似项目中标时间
+	Key                string                 `json:"key"`                //中标企业名称
+	Doc_count          float64                `json:"doc_count"`          //项目数量
+	Total_project      int                    `json:"total_project"`      //项目金额
+	Buyer_similar_list BuyerSOOL              `json:"buyer_similar_list"` //与采购单位类似项目合作历史
+	Buyer_other_list   BuyerSOOL              `json:"buyer_other_list"`   //与采购单位其他项目合作历史
+	Capital            int64                  `json:"capital"`            //中标企业注册资本
+	EntId              string                 `json:"entId"`              //中标企业加密id
+	Max_jytime         int64                  `json:"max_jytime"`         //类似项目中标时间
+	LatestProject      map[string]interface{} `json:"latest_project"`     // 中标企业最近合作项目
 }
 
 type BuyerSOOL struct {

+ 91 - 0
src/jfw/modules/bigmember/src/util/util.go

@@ -1,7 +1,11 @@
 package util
 
 import (
+	"encoding/json"
+	"fmt"
+	"reflect"
 	"regexp"
+	"sort"
 
 	"app.yhyue.com/moapp/jybase/encrypt"
 )
@@ -21,3 +25,90 @@ func DecodeId(eid string) string {
 	}
 	return encrypt.DecodeArticleId2ByCheck(eid)[0]
 }
+
+// 排序 排序键必须为数字类型
+type SortBy struct {
+	Data    []map[string]interface{}
+	Sortkey string
+}
+
+func (a SortBy) Len() int { return len(a.Data) }
+
+func (a SortBy) Swap(i, j int) {
+	a.Data[i], a.Data[j] = a.Data[j], a.Data[i]
+}
+
+func (a SortBy) Less(i, j int) bool {
+	//return Float64(a.Data[i][a.Sortkey]) < Float64(a.Data[j][a.Sortkey])
+	m := a.Data[i][a.Sortkey]
+	n := a.Data[j][a.Sortkey]
+	w := reflect.ValueOf(m)
+	v := reflect.ValueOf(n)
+	switch v.Kind() {
+	case reflect.String:
+		return w.String() < v.String()
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return w.Int() < v.Int()
+	case reflect.Float64, reflect.Float32:
+		return w.Float() < v.Float()
+	default:
+		return fmt.Sprintf("%v", w) < fmt.Sprintf("%v", v)
+	}
+}
+
+// 根据指定字符排序
+//
+//	m := []map[string]int{
+//	   {"k": 2},
+//	   {"k": 1},
+//	   {"k": 3},
+//	}
+//
+// customer.SortData(&m, "k", true)
+// ture  倒序3, 2, 1
+// fmt.Println(m)
+func SortData(data interface{}, sortkey string, reverse bool) {
+	//func SortData(data interface{}, sortkey string, reverse bool) {
+	var db []map[string]interface{}
+	err := Bind(data, &db)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	stb := SortBy{db, sortkey}
+	if !reverse {
+		sort.Sort(stb)
+	} else {
+		sort.Sort(sort.Reverse(stb))
+	}
+	err = Bind(stb.Data, data)
+	if err != nil {
+		fmt.Println(err)
+	}
+
+}
+
+func Bind(data interface{}, ret interface{}) error {
+	v := reflect.ValueOf(ret)
+	if v.Kind() != reflect.Ptr {
+		return fmt.Errorf("ptr input ret needed as type as input type %s", v.Kind())
+	}
+	havdata := false
+	var bk interface{}
+	if v.Elem().Kind() == reflect.Slice {
+		t := reflect.Zero(reflect.TypeOf(v.Elem().Interface()))
+		bk = v.Elem().Interface()
+		v.Elem().Set(t)
+		havdata = true
+	}
+	_data, _ := json.MarshalIndent(data, "", "    ")
+	err := json.Unmarshal(_data, ret)
+	if err != nil {
+		fmt.Println(err)
+		if havdata {
+			v.Elem().Set(reflect.ValueOf(bk))
+		}
+		return err
+	}
+	return nil
+}

+ 15 - 0
src/jfw/modules/distribution/.idea/git_toolbox_prj.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GitToolBoxProjectSettings">
+    <option name="commitMessageIssueKeyValidationOverride">
+      <BoolValueOverride>
+        <option name="enabled" value="true" />
+      </BoolValueOverride>
+    </option>
+    <option name="commitMessageValidationEnabledOverride">
+      <BoolValueOverride>
+        <option name="enabled" value="true" />
+      </BoolValueOverride>
+    </option>
+  </component>
+</project>

+ 26 - 10
src/jfw/modules/publicapply/src/db.json

@@ -15,7 +15,7 @@
       "password": "123456"
     },
     "bidding": {
-      "address": "192.168.3.207:27001,192.168.3.206:27002",
+      "address": "192.168.3.206:27002",
       "size": 5,
       "dbName": "qfw_data",
       "collection": "bidding",
@@ -24,7 +24,7 @@
       "password": "jy@DevGroup"
     },
     "ent": {
-      "address": "192.168.3.207:27001,192.168.3.206:27002",
+      "address": "192.168.3.206:27002",
       "size": 5,
       "dbName": "mixdata",
       "replSet": "",
@@ -36,30 +36,38 @@
   },
   "elasticsearch": {
     "main": {
-      "address": "http://192.168.3.206:9800,http://192.168.3.206:9801",
+      "address": "http://192.168.3.241:9205,http://192.168.3.149:9200",
       "size": 30,
-	  "version": "v7",
-	  "userName": "",
-	  "password": ""
+      "version": "v7",
+      "userName":"",
+      "password":""
     }
   },
   "redis": {
     "main":{
-      "address": "other=192.168.3.206:1712,session=192.168.3.149:1713,newother=192.168.3.206:1712,poly=192.168.3.149:1713"
+      "address": "other=192.168.3.149:1712,session=192.168.3.149:1713,newother=192.168.3.149:1712,poly=192.168.3.149:1713"
     }
   },
   "mysql": {
     "main": {
       "dbName": "jianyu",
-      "address": "192.168.3.11:3366",
+      "address": "192.168.3.149:3306",
       "userName": "root",
       "passWord": "Topnet123",
       "maxOpenConns": 5,
       "maxIdleConns": 5
     },
+    "medical": {
+      "dBName": "medical_field_data",
+      "address": "192.168.3.14:4000",
+      "userName": "root",
+      "passWord": "=PDT49#80Z!RVv52_z",
+      "maxOpenConns": 5,
+      "maxIdleConns": 5
+    },
     "supplyInfo": {
       "dbName": "base_service",
-      "address": "192.168.3.11:3366",
+      "address": "192.168.3.149:3306",
       "userName": "root",
       "passWord": "Topnet123",
       "maxOpenConns": 5,
@@ -75,5 +83,13 @@
     }
   },
   "bdcollection":"bdcollection",
-  "bdlabel":"bdlabel"
+  "bdlabel":"bdlabel",
+  "base": {
+    "dBName": "base_service",
+    "address": "192.168.3.217:4000",
+    "userName": "root",
+    "passWord": "=PDT49#80Z!RVv52_z",
+    "maxOpenConns": 5,
+    "maxIdleConns": 5
+  }
 }

+ 2 - 2
src/jfw/modules/subscribepay/src/config.yaml

@@ -1,6 +1,6 @@
 etcd:
   hosts:
-  - 192.168.3.206:2379
+  - 192.168.3.149:2379
 userCenterKey: "usercenter.rpc" #用户中台rpc
 powerCheckCenterKey: "powercheck.rpc" #权益校验中台
-activityKey: "activity.rpc" #营销平台rpc
+activityKey: "activity.rpc" #营销平台rpc

+ 5 - 5
src/jfw/modules/subscribepay/src/service/orderListDetails.go

@@ -1024,11 +1024,11 @@ func deleteRepeat(slice []int) []int {
 	return slice_repeat
 }
 
-//获取订单列表sql语句拼接
-//userId 用户id
-//fromPage 来源地址
-//typ 类型
-//@return sql语句 countsql语句
+// 获取订单列表sql语句拼接
+// userId 用户id
+// fromPage 来源地址
+// typ 类型
+// @return sql语句 countsql语句
 func getOrderSql(userId, fromPage, typ string) (string, string) {
 	sql := fmt.Sprintf(`select id,order_code,order_channel,filter_publishtime,create_time,data_spec,filter_id,filter_keys,order_money,pay_money,data_count,order_status,pay_way,product_type,filter,pay_time,vip_starttime,vip_endtime,applybill_status,applybill_type,applybill_taxnum,applybill_company,vip_type,course_status,discount_price,d_relation_id,billingMode,is_backstage_order,return_status,expiration_time,buy_subject,buy_count from dataexport_order
 		where del_status=0 and audit_status=3 AND ((is_backstage_order =0 AND user_id ='%s')`, userId)

二进制
src/jfw/modules/subscribepay/src/web/staticres/res/dataexport/20201130152650_250672091720_bjINh.xlsx


二进制
src/jfw/modules/subscribepay/src/web/staticres/res/dataexport/20201130153115_250672151862_QBYIm.xlsx


+ 3 - 3
src/jfw/modules/wxtoken/src/config.json

@@ -1,9 +1,9 @@
 {
 	"wxs":[
 		{
-			"appid":"wx6bb62470ce51e432",
-			"appsecret":"b9374cd43f677a6792ff7b1a23301ac3"
+			"appid":"wx5b1c6e7cc4dac0e4",
+			"appsecret":"b026103ffebd2291b3edb7a269612112"
 		}
 	],
 	"redis":"wxtoken=192.168.3.206:1712"
-}
+}

+ 4 - 4
src/jfw/modules/wxtoken/src/main.go

@@ -1,14 +1,14 @@
 package main
 
 import (
+	util "app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/redis"
 	"encoding/json"
 	"errors"
 	"fmt"
 	"io/ioutil"
 	"log"
 	"net/http"
-	util "app.yhyue.com/moapp/jybase/common"
-	"app.yhyue.com/moapp/jybase/redis"
 	"strings"
 	"time"
 
@@ -155,7 +155,7 @@ func main() {
 func createAccessToken(appid string) {
 	lt := int64(0)
 	token := accessToken{"", time.Now(), &lt}
-	AllWxs[appid].TokenChan <- token
+	//	AllWxs[appid].TokenChan <- token
 	tokenKey := fmt.Sprintf("WxToken_%s", appid)
 	for {
 		ret, err := redis.GetNewBytes(RedisCode, tokenKey)
@@ -214,7 +214,7 @@ func createAccessToken(appid string) {
 	}
 }
 
-//刷新token
+// 刷新token
 func refreshAccessToken(appid string) {
 	redis.Del(RedisCode, fmt.Sprintf(WxTokenKey, appid))
 	<-AllWxs[appid].TokenChan

二进制
src/web/staticres/big-member/image/landpage_new/itemA_05.jpg


二进制
src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB1.png


二进制
src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB2.png


二进制
src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB3.png


二进制
src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB4.png


二进制
src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB5.png


二进制
src/web/staticres/big-member/image/landpage_new/toubiaoImg/itemB6.png


+ 5 - 5
src/web/staticres/big-member/js/chart_options.js

@@ -120,7 +120,7 @@ var chartOptions = {
                     top: 'middle',
                     style: {
                         fill: '#333',
-                        text: '类项目数量(个)',
+                        text: '类项目数量(个)',
                         font: '10px Microsoft YaHei'
                     }
                 }]
@@ -243,7 +243,7 @@ var chartOptions = {
             itemGap: 30,
         },
         series: [{
-            name: '类项目数量',
+            name: '类项目数量',
             type: 'heatmap',
             label: {
                 show: false
@@ -363,7 +363,7 @@ var chartOptions = {
         series: [
             {
                 type:'bar',
-                name:'类项目标书编制周期',
+                name:'类项目标书编制周期',
                 barWidth: 10,
                 barMaxWidth: 10,
                 itemStyle:{
@@ -425,7 +425,7 @@ var chartOptions = {
                         top: 'middle',
                         style: {
                             fill: '#333',
-                            text: '类项目标书编制周期',
+                            text: '类项目标书编制周期',
                             font: '11px Microsoft YaHei',
                             x: 8
                         }
@@ -789,7 +789,7 @@ var chartOptions = {
                 x:0,
                 y:1,
                 itemName: '行业',
-                value: "类项目规模", 
+                value: "类项目规模", 
             },
             labelLine: {
                 show:false

+ 13 - 13
src/web/staticres/big-member/js/contrast_trial.js

@@ -55,7 +55,7 @@ var CustomData = {
             sm: '利用招标大数据,结合项目知识工程,预测潜在新项目',
             merge: true,
             '预测采购项目': ['利用招标大数据,预测潜在项目的采购内容。', '2个'],
-            '类项目联系方式': ['提供类项目的联系人、联系方式等。', '2个'],
+            '类项目联系方式': ['提供类项目的联系人、联系方式等。', '2个'],
         },
         '中标企业预测': {
             sm: '通过大数据和AI技术,预测项目中标企业',
@@ -65,18 +65,18 @@ var CustomData = {
             '企业联系方式': ['提供企业的联系方式,一键可拨打联系人。', '2个'],
         },
         '投标决策分析': {
-            sm: '分析类项目,帮助企业决策是否投标或合作投标、以及投标报价金额等。',
-            '类项目动态': ['提供类项目的招标日期、招标截至日期、采购单位、代理机构、项目行业、金额等', '✅'],
-            '类项目筛选': ['通过项目行业、地区、采购内容、金额区间、采购单位类型筛选符合条件项目信息。', '✅'],
-            '类项目分析': ['通过大数据统计分析,提供近2-3年类项目数量、项目金额、涉及中标企业数量、涉及评标专家数量。', '✅'],
-            '类项目明细': ['提供类项目明细,包含项目的名称、采购方式、中标企业、评标专家、项目时间、预算、中标价、折扣率、中标候选人等。', '✅'],
-            '类项目采购历史': ['提供类项目的历史采购动态,项目名称、采购方式、时间等。', '✅'],
-            '类项目热点中标企业': ['根据类项目的历史中标数量、中标金额等综合评定企业竞争力,提供排名前十的企业。', '✅'],
-            '类项目标书编制周期发布': ['提供类项目的历史招标文件发放至投标截止时间(开标)时间间隔、项目数量,为投标人编制标书提供参考。', '✅'],
-            '类项目采购单位类型分布': ['提供采购规模排名前十的采购单位类型及规模占比、类项目规模、类项目数量、平均折扣率。', '✅'],
-            '类项目评标专家': ['通过大数据分析统计,提供类项目评标专家的频次排名。', '✅'],
-            '类项目区域分布': ['提供类项目的采购区域热度分布。', '✅'],
-            '类项目预算分布': ['提供类采购项目的预算金额分布。', '✅'],
+            sm: '分析类项目,帮助企业决策是否投标或合作投标、以及投标报价金额等。',
+            '类项目动态': ['提供类项目的招标日期、招标截至日期、采购单位、代理机构、项目行业、金额等', '✅'],
+            '类项目筛选': ['通过项目行业、地区、采购内容、金额区间、采购单位类型筛选符合条件项目信息。', '✅'],
+            '类项目分析': ['通过大数据统计分析,提供近2-3年类项目数量、项目金额、涉及中标企业数量、涉及评标专家数量。', '✅'],
+            '类项目明细': ['提供类项目明细,包含项目的名称、采购方式、中标企业、评标专家、项目时间、预算、中标价、折扣率、中标候选人等。', '✅'],
+            '类项目采购历史': ['提供类项目的历史采购动态,项目名称、采购方式、时间等。', '✅'],
+            '类项目热点中标企业': ['根据类项目的历史中标数量、中标金额等综合评定企业竞争力,提供排名前十的企业。', '✅'],
+            '类项目标书编制周期发布': ['提供类项目的历史招标文件发放至投标截止时间(开标)时间间隔、项目数量,为投标人编制标书提供参考。', '✅'],
+            '类项目采购单位类型分布': ['提供采购规模排名前十的采购单位类型及规模占比、类项目规模、类项目数量、平均折扣率。', '✅'],
+            '类项目评标专家': ['通过大数据分析统计,提供类项目评标专家的频次排名。', '✅'],
+            '类项目区域分布': ['提供类项目的采购区域热度分布。', '✅'],
+            '类项目预算分布': ['提供类采购项目的预算金额分布。', '✅'],
         }
     },
     '招标大数据服务': {

+ 13 - 13
src/web/staticres/big-member/js/meauContact.js

@@ -309,44 +309,44 @@ var TBJC = [
   {
     '投标决策分析':[
       {
-        two: '类项目明细',
+        two: '类项目明细',
         three: '采购单位历史项目信息明细',
         four: 'icon-close',
         five: 'icon-tick'
       },
       {
-        two: '类项目评标专家分析',
-        three: '通过大数据分析统计,提供类项目评标专家的频次排名。',
+        two: '类项目评标专家分析',
+        three: '通过大数据分析统计,提供类项目评标专家的频次排名。',
         four: 'icon-close',
         five: 'icon-tick'
       },
       {
-        two: '类项目热点中标企业',
-        three: '根据类项目的历史中标数量、中标金额等综合评定企业竞争力,提供排名前十的企业。',
+        two: '类项目热点中标企业',
+        three: '根据类项目的历史中标数量、中标金额等综合评定企业竞争力,提供排名前十的企业。',
         four: 'icon-close',
         five: 'icon-tick'
       },
       {
-        two: '类项目区域分布',
-        three: '提供类项目的采购区域热度分布情况统计图表。',
+        two: '类项目区域分布',
+        three: '提供类项目的采购区域热度分布情况统计图表。',
         four: 'icon-close',
         five: 'icon-tick'
       },
       {
-        two: '类项目预算分布',
-        three: '提供类采购项目的预算金额价格区间分布情况统计图表。',
+        two: '类项目预算分布',
+        three: '提供类采购项目的预算金额价格区间分布情况统计图表。',
         four: 'icon-close',
         five: 'icon-tick'
       },
       {
-        two: '类项目采购单位类型分布',
-        three: '提供类采购项目的预算金额价格区间分布情况统计图表。',
+        two: '类项目采购单位类型分布',
+        three: '提供类采购项目的预算金额价格区间分布情况统计图表。',
         four: 'icon-close',
         five: 'icon-tick'
       },
       {
-        two: '类项目标书编制周期',
-        three: '提供类项目采购单位的各行业分类占比情况统计图表。',
+        two: '类项目标书编制周期',
+        three: '提供类项目采购单位的各行业分类占比情况统计图表。',
         four: 'icon-close',
         five: 'icon-tick'
       }

+ 26 - 26
src/web/staticres/big-member/js/previewTable.js

@@ -59,7 +59,7 @@ var AllData = {
         '潜在项目预测推送': {
             sm: '利用招标大数据,预测潜在项目的采购内容',
             '预测采购项目': ['利用招标大数据,预测潜在项目的采购内容。','-','✅','✅'],
-            '类项目联系方式': ['提供类项目的联系人、联系方式等。','-','✅','✅'],
+            '类项目联系方式': ['提供类项目的联系人、联系方式等。','-','✅','✅'],
         },
         '中标企业预测': {
             sm: '通过大数据、AI技术预测项目中标企业。',
@@ -69,18 +69,18 @@ var AllData = {
             '企业联系方式': ['提供企业的联系方式,一键可拨打联系人。','-','200个','200个'],
         },
         '投标决策分析': {
-            sm: '分析类项目,帮助企业决策是否投标或合作投标、以及投标报价金额等。',
-            '类项目动态': ['提供类项目的招标日期、招标截至日期、采购单位、代理机构、项目行业、金额等','-','✅','✅'],
-            '类项目筛选': ['通过项目行业、地区、采购内容、金额区间、采购单位类型筛选符合条件项目信息。','-','✅','✅'],
-            '类项目分析': ['通过大数据统计分析,提供近2-3年类项目数量、项目金额、涉及中标企业数量、涉及评标专家数量。','-','✅','✅'],
-            '类项目明细': ['提供类项目明细,包含项目的名称、采购方式、中标企业、评标专家、项目时间、预算、中标价、折扣率、中标候选人等。','-','✅','✅'],
-            '类项目采购历史': ['提供类项目的历史采购动态,项目名称、采购方式、时间等。','-','✅','✅'],
-            '类项目热点中标企业': ['根据类项目的历史中标数量、中标金额等综合评定企业竞争力,提供排名前十的企业。','-','✅','✅'],
-            '类项目标书编制周期发布': ['提供类项目的历史招标文件发放至投标截止时间(开标)时间间隔、项目数量,为投标人编制标书提供参考。','-','✅','✅'],
-            '类项目采购单位类型分布': ['提供采购规模排名前十的采购单位类型及规模占比、类项目规模、类项目数量、平均折扣率。','-','✅','✅'],
-            '类项目评标专家': ['通过大数据分析统计,提供类项目评标专家的频次排名。','-','✅','✅'],
-            '类项目区域分布': ['提供类项目的采购区域热度分布。','-','✅','✅'],
-            '类项目预算分布': ['提供类采购项目的预算金额分布。','-','✅','✅'],
+            sm: '分析类项目,帮助企业决策是否投标或合作投标、以及投标报价金额等。',
+            '类项目动态': ['提供类项目的招标日期、招标截至日期、采购单位、代理机构、项目行业、金额等','-','✅','✅'],
+            '类项目筛选': ['通过项目行业、地区、采购内容、金额区间、采购单位类型筛选符合条件项目信息。','-','✅','✅'],
+            '类项目分析': ['通过大数据统计分析,提供近2-3年类项目数量、项目金额、涉及中标企业数量、涉及评标专家数量。','-','✅','✅'],
+            '类项目明细': ['提供类项目明细,包含项目的名称、采购方式、中标企业、评标专家、项目时间、预算、中标价、折扣率、中标候选人等。','-','✅','✅'],
+            '类项目采购历史': ['提供类项目的历史采购动态,项目名称、采购方式、时间等。','-','✅','✅'],
+            '类项目热点中标企业': ['根据类项目的历史中标数量、中标金额等综合评定企业竞争力,提供排名前十的企业。','-','✅','✅'],
+            '类项目标书编制周期发布': ['提供类项目的历史招标文件发放至投标截止时间(开标)时间间隔、项目数量,为投标人编制标书提供参考。','-','✅','✅'],
+            '类项目采购单位类型分布': ['提供采购规模排名前十的采购单位类型及规模占比、类项目规模、类项目数量、平均折扣率。','-','✅','✅'],
+            '类项目评标专家': ['通过大数据分析统计,提供类项目评标专家的频次排名。','-','✅','✅'],
+            '类项目区域分布': ['提供类项目的采购区域热度分布。','-','✅','✅'],
+            '类项目预算分布': ['提供类采购项目的预算金额分布。','-','✅','✅'],
         }
     },
     '招标大数据服务': {
@@ -243,7 +243,7 @@ var CustomData = {
       sm: '利用招标大数据,预测潜在项目的采购内容',
       merge: true,
       '预测采购项目': ['利用招标大数据,预测潜在项目的采购内容。','2个'],
-      '类项目联系方式': ['提供类项目的联系人、联系方式等。','2个'],
+      '类项目联系方式': ['提供类项目的联系人、联系方式等。','2个'],
     },
     '中标企业预测': {
       sm: '通过大数据、AI技术预测项目中标企业。',
@@ -253,18 +253,18 @@ var CustomData = {
       '企业联系方式': ['提供企业的联系方式,一键可拨打联系人。','2个'],
     },
     '投标决策分析': {
-      sm: '分析类项目,帮助企业决策是否投标或合作投标、以及投标报价金额等。',
-      '类项目动态': ['提供类项目的招标日期、招标截至日期、采购单位、代理机构、项目行业、金额等','✅'],
-      '类项目筛选': ['通过项目行业、地区、采购内容、金额区间、采购单位类型筛选符合条件项目信息。','✅'],
-      '类项目分析': ['通过大数据统计分析,提供近2-3年类项目数量、项目金额、涉及中标企业数量、涉及评标专家数量。','✅'],
-      '类项目明细': ['提供类项目明细,包含项目的名称、采购方式、中标企业、评标专家、项目时间、预算、中标价、折扣率、中标候选人等。','✅'],
-      '类项目采购历史': ['提供类项目的历史采购动态,项目名称、采购方式、时间等。','✅'],
-      '类项目热点中标企业': ['根据类项目的历史中标数量、中标金额等综合评定企业竞争力,提供排名前十的企业。','✅'],
-      '类项目标书编制周期发布': ['提供类项目的历史招标文件发放至投标截止时间(开标)时间间隔、项目数量,为投标人编制标书提供参考。','✅'],
-      '类项目采购单位类型分布': ['提供采购规模排名前十的采购单位类型及规模占比、类项目规模、类项目数量、平均折扣率。','✅'],
-      '类项目评标专家': ['通过大数据分析统计,提供类项目评标专家的频次排名。','✅'],
-      '类项目区域分布': ['提供类项目的采购区域热度分布。','✅'],
-      '类项目预算分布': ['提供类采购项目的预算金额分布。','✅'],
+      sm: '分析类项目,帮助企业决策是否投标或合作投标、以及投标报价金额等。',
+      '类项目动态': ['提供类项目的招标日期、招标截至日期、采购单位、代理机构、项目行业、金额等','✅'],
+      '类项目筛选': ['通过项目行业、地区、采购内容、金额区间、采购单位类型筛选符合条件项目信息。','✅'],
+      '类项目分析': ['通过大数据统计分析,提供近2-3年类项目数量、项目金额、涉及中标企业数量、涉及评标专家数量。','✅'],
+      '类项目明细': ['提供类项目明细,包含项目的名称、采购方式、中标企业、评标专家、项目时间、预算、中标价、折扣率、中标候选人等。','✅'],
+      '类项目采购历史': ['提供类项目的历史采购动态,项目名称、采购方式、时间等。','✅'],
+      '类项目热点中标企业': ['根据类项目的历史中标数量、中标金额等综合评定企业竞争力,提供排名前十的企业。','✅'],
+      '类项目标书编制周期发布': ['提供类项目的历史招标文件发放至投标截止时间(开标)时间间隔、项目数量,为投标人编制标书提供参考。','✅'],
+      '类项目采购单位类型分布': ['提供采购规模排名前十的采购单位类型及规模占比、类项目规模、类项目数量、平均折扣率。','✅'],
+      '类项目评标专家': ['通过大数据分析统计,提供类项目评标专家的频次排名。','✅'],
+      '类项目区域分布': ['提供类项目的采购区域热度分布。','✅'],
+      '类项目预算分布': ['提供类采购项目的预算金额分布。','✅'],
     }
   },
   '招标大数据服务': {

+ 209 - 0
src/web/staticres/common-module/analysis-filter/css/analysis-filter.css

@@ -0,0 +1,209 @@
+.analysis-filter .van-cell::after{
+  border: 0.5px solid rgba(0, 0, 0, 0.05);
+  left: .32rem;
+  right: .32rem;
+}
+/* .analysis-filter .time-cell.van-cell::after {
+  content: '';
+  border: 0.5px solid rgba(0, 0, 0, 0.05);
+  left: .32rem;
+  right: .32rem;
+} */
+
+.analysis-filter .van-cell{
+  padding: .24rem .32rem;
+  flex-direction: column;
+}
+.analysis-filter .van-popover__wrapper .van-cell::after{
+  content: '';
+  display: inline;
+}
+.analysis-filter .van-cell.van-cell--required::before {
+  left: .36rem;
+  font-size: .28rem;
+}
+.analysis-filter .van-cell .van-cell--required::before {
+  left: .36rem;
+  font-size: .28rem;
+}
+.analysis-filter .buyer-label{
+  padding-left: .18rem;
+}
+.analysis-filter .van-cell.van-cell--required .van-cell__title{
+  padding-left: .18rem;
+}
+.analysis-filter .van-icon.van-icon-arrow {
+  position: absolute;
+  right: .32rem;
+  top: .8rem;
+}
+.analysis-filter .van-cell__title.van-field__label {
+  font-size: .28rem;
+  color: #5F5E64;
+  line-height: .4rem;
+  width: 100%;
+}
+.analysis-filter .van-cell__value {
+  margin-top: .16rem;
+}
+.analysis-filter .van-cell__value ::-webkit-input-placeholder {
+  color: #C0C4CC;
+  font-size: .32rem;
+  line-height: .48rem;
+}
+.analysis-filter .van-field__error-message{
+  color: #FB483D;
+  font-size: .24rem;
+  line-height: .36rem;
+  margin-top: .08rem;
+}
+.analysis-filter .van-field__control{
+  font-size: .32rem;
+  white-space: pre-wrap;
+  word-wrap: break-word;
+}
+
+.analysis-filter .van-field__control::-webkit-scrollbar {
+  display: none;
+}
+
+.analysis-filter .van-cell.buyer-conetent .van-field__control{
+  padding: .12rem .9rem .12rem .24rem;
+  background: #FFFFFF;
+/* Line/#000000_10% */
+  border: 0.5px solid rgba(0, 0, 0, 0.1);
+  border-radius: 4px;
+  color: #171826;
+}
+
+.analysis-filter .van-cell.buyer-conetent .van-field__word-limit{
+  position: absolute;
+  right: 1.4rem;
+  top: .12rem;
+  color: #9B9CA3;
+  font-size: .22rem;
+  line-height: .4rem;
+}
+.analysis-filter .van-cell.buyer-conetent .addkeys{
+  padding: .12rem .24rem;
+  background: #2ABED1;
+  border-radius: 4px;
+  border: none;
+  color: #FFFFFF;
+  font-size: .26rem;
+}
+
+.select_time .van-cell{
+  padding: 0 .32rem;
+  height: 1.08rem;
+}
+.select_time .van-cell::after{
+  border-bottom: 0.5px solid rgba(0, 0, 0, 0.05);
+}
+.select_time .van-cell.van-dropdown-item__option{
+  font-size: .28rem;
+  color: #5F5E64;
+}
+.select_time .van-cell.activeColor{
+  color: #2ABED1;
+}
+.select_time .van-cell .select_active{
+  width: .48rem;
+  height: .48rem;
+}
+.select_time .van-icon::before {
+  font-size: .4rem;
+}
+
+.select_time .van-picker-column__item--selected {
+  background: rgba(42, 190, 209, 0.05);
+  color: #2ABED1;
+  height: .8rem;
+}
+
+.project-analysis-main{
+  min-height: .64rem;
+  max-height: 8rem;
+  overflow: scroll;
+}
+.project-analysis-main .list{
+  font-size: .32rem;
+}
+.analysis-filter .van-popover__wrapper{
+  width: 100%;
+}
+
+.analysis-filter .key-list {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  word-break: break-all;
+  margin-top: .16rem;
+}
+.analysis-filter .key-list .key-item{
+  width: fit-content;
+  display: flex;
+  align-items: center;
+  padding: .12rem .2rem;
+  background: #F5F6F7;
+  border-radius: 4px;
+}
+.analysis-filter .key-list .icon_close{
+  margin-left: .08rem;
+  width: .32rem;
+  height: .32rem;
+  background: url('../image/icon_close.png') no-repeat;
+  background-size: contain;
+}
+
+.analysis-filter .j-button-group{
+  padding: .26rem .32rem;
+}
+
+
+.icon-search{
+  width: .4rem;
+  height: .4rem;
+  margin-right: .16rem;
+}
+.r-list > li > a{
+  display: block;
+  padding: .24rem .32rem;
+}
+.l-title{
+  display: flex;
+  font-size: .28rem;
+  color: #171826;
+  line-height: .4rem;
+}
+.l-title > span{
+  flex: 1;
+}
+.l-info{
+  padding-top: .16rem;
+  padding-left: .56rem;
+}
+.l-info p{
+  color: #9B9CA3;
+  font-size: .24rem;
+  line-height: .36rem;
+}
+
+.van-popup.van-popover {
+  width: 92%;
+  left: 0.5rem;
+}
+
+.van-popover__arrow {
+  display: none;
+}
+.van-hairline--top-bottom::after, .van-hairline-unset--top-bottom::after {
+  border-width: 0px 0px 1px;
+}
+.select_time.select_area .van-hairline--top-bottom::after, .van-hairline-unset--top-bottom::after {
+  border-width: 0px;
+}
+
+.select-year-time{
+  padding-bottom: .48rem;
+}

二进制
src/web/staticres/common-module/analysis-filter/image/icon_close.png


二进制
src/web/staticres/common-module/analysis-filter/image/right.png


+ 482 - 0
src/web/staticres/common-module/analysis-filter/js/analysis-filter.js

@@ -0,0 +1,482 @@
+var analysisTemp = `
+<div class="analysis-filter">
+  <van-form @submit="onSubmit" class="j-container">
+    <van-cell-group inset>
+      <van-popover :show-arrow="false" :close-on-click-action="true" :close-on-click-outside="true" v-model="showPopover">
+        <template #reference>
+          <van-field
+            :value="filters.pname"
+            @input="setProName"
+            name="projectName"
+            label="项目名称"
+            rows="1"
+            autosize
+            type="textarea"
+            placeholder="请输入项目名称"
+            :rules="[{ required: false, message: '请输入项目名称' }]"
+          ></van-field>
+        </template>
+        <div class="project-analysis-main">
+          <ul class="r-list">
+              <li class="list" v-for="item in projectArr" :key="item.s_id">
+                  <a href="javascript:;" @click.prevent="onSelect(item, 'project')">
+                      <div class="l-title">
+                          <i class="j-icon base-icon icon-search"></i>
+                          <span>{{item.projectname}}</span>
+                      </div>
+                      <div class="l-info">
+                          <p class="van-ellipsis">采购单位:{{item.buyer}}</p>
+                          <p>采购时间:{{item.firsttime}}</p>
+                      </div>
+                  </a>
+              </li>
+          </ul>
+        </div>
+      </van-popover>
+      <van-popover :show-arrow="false" :close-on-click-action="true" :close-on-click-outside="true" v-model="showBuyerPopover">
+        <template #reference>
+          <van-field
+            required
+            @input="setBuyerName"
+            v-model="filters.buyer"
+            name="buyer"
+            label="采购单位"
+            rows="1"
+            autosize
+            type="textarea"
+            placeholder="请输入采购单位名称"
+            :rules="[{ required: true, message: '采购单位名称为必填项' }]"
+          ></van-field>
+        </template>
+        <div class="project-analysis-main">
+          <ul class="r-list">
+            <li class="list" v-for="item in buyerArr" :key="item.s_id">
+              <a href="javascript:;" @click.prevent="onSelect(item, 'buyer')">
+                  <div class="l-title">
+                    <span>{{ item.buyer }}</span>
+                  </div>
+              </a>
+            </li>
+          </ul>
+        </div>
+      </van-popover>
+      <van-field
+        autosize
+        label-class="van-cell--required"
+        @start-validate="startValidate"
+        class="buyer-conetent"
+        v-model="filters.keys"
+        name="buyerContent"
+        maxlength="15"
+        show-word-limit
+        placeholder="请输入采购内容"
+        :rules="buyerRules"
+      >
+        <template #label>
+          <div class="buyer-content">
+            <div class="buyer-label">采购内容</div>
+            <div class="key-list">
+              <div style="margin: .16rem .16rem 0 0" v-for="(item, index) in buyerContent" :key="index">
+                <div class="key-item" v-for="(key, i) in item.key" :key="i">
+                  <span v-html="key"></span>
+                  <div @click="deleteKey(key)" class="icon_close"></div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </template>
+        <template #button>
+          <button type="button" :disabled="filters.keys==''" class='addkeys' @click="addKeys" size="small">添加</button>
+        </template>
+      </van-field>
+      <van-field
+        required
+        @click="setOpenPopup('area')"
+        is-link
+        readonly
+        v-model="filters.area"
+        name="winner"
+        label="项目地区"
+        placeholder="请选择地区"
+        :rules="[{ required: true, message: '地区为必填项' }]"
+      ></van-field>
+      <van-field
+        is-link
+        class='time-cell'
+        readonly
+        @click="setOpenPopup('time')"
+        v-model="filters.limitTime"
+        name="winner"
+        label="同类项目成交时间"
+        placeholder="请选择时间"
+        :rules="[{ required: false, message: '请选择时间' }]"
+      ></van-field>
+    </van-cell-group>
+    <div class="j-footer">
+      <div class="j-button-group">
+        <button class="j-button-confirm" round block type="primary" native-type="submit">
+          开始分析
+        </button>
+      </div>
+    </div>
+  </van-form>
+  <van-popup
+    v-model="filtersPopup.area"
+    closeable
+    round
+    position="bottom"
+    close-icon="clear"
+    :lazy-render="false"
+    class="j-popup collection select_time select_area"
+    overlay-class="j-overlay"
+    :style="{ height: '46%' }"
+    get-container="body">
+    <div class="j-container report-popup">
+        <div class="popup-header header-title">请选择地区</div>
+        <div class="j-main">
+          <van-picker
+            ref="picker"
+            :show-toolbar="false"
+            :columns="columns"
+          ></van-picker>
+        </div>
+        <div class="j-footer">
+          <div class="j-button-group">
+            <button class="j-button-confirm van-picker__confirm" @click="onAreaConfirm">确认</button>
+          </div>
+        </div>
+    </div>
+  </van-popup>
+  <van-popup
+    v-model="filtersPopup.time"
+    closeable
+    round
+    position="bottom"
+    close-icon="clear"
+    class="j-popup collection select_time select-year-time"
+    :lazy-render="false"
+    overlay-class="j-overlay"
+    get-container="body">
+    <div class="j-container report-popup">
+        <div class="popup-header header-title">请选择时间</div>
+        <div class="j-main">
+          <van-cell center :class="{'activeColor': item.active}" @click="setSortRules(item)" :title="item.text" v-for="(item, index) in sortOption" :key="index">
+            <template #right-icon>
+              <img v-if="item.active" class="select_active" src="/common-module/analysis-filter/image/right.png" alt="">
+            </template>
+          </van-cell>
+        </div>
+    </div>
+  </van-popup>
+</div>
+`
+var analysisComponent = {
+  name: 'filter-content',
+  template: analysisTemp,
+  props: {
+    id: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      filters: {
+        pname: '',
+        buyer: '',
+        keys: '',
+        area: '',
+        limitTime: '近五年'
+      },
+      ajaxFilters: {
+        pname: '',
+        buyer: '',
+        keys: [],
+        area: '',
+        limitTime: 'fiveYear'
+      },
+      buyerContent: [],
+      filtersPopup: {
+        area: false,
+        time: false
+      },
+      buyerRules: [{ required: true, message: '采购内容为必填项' }],
+      columns: ChinaProvinceJson,
+      showPopover: false, // 项目联想弹窗
+      showBuyerPopover: false, // 采购单位联想弹窗
+      entering: '',
+      buyerArr: [],
+      projectArr: [],
+      sortOption: [
+        { text: '近五年', value: 'fiveYear', active: true },
+        { text: '近三年', value: 'threeYear', active: false },
+        { text: '近一年', value: 'oneYear', active: false }
+      ]
+    }
+  },
+  computed: {
+    setKeyRequired () {
+      return this.buyerContent.length > 0
+    }
+  },
+  watch: {
+    id: {
+      handler (newval) {
+        if(newval) {
+          this.entering = 'project'
+          const data = {
+            sourceinfoid: newval
+          }
+          this.getFiltersData(data)
+        }
+      },
+      immediate: true
+    },
+    buyerContent: {
+      handler (newval) {
+        const buyerInput = document.querySelector('.buyer-conetent')
+        if(buyerInput) {
+          const buyerInputValue = buyerInput.querySelector('.van-cell__value')
+          if(newval.length > 0) {
+            this.buyerRules = [{ required: false, validator: this.getKeysStatus,  message: '采购内容为必填项' }]
+          } else {
+            this.buyerRules = [{ required: true, validator: this.getKeysStatus, message: '采购内容为必填项' }]
+          }
+          if(newval.length >= 10) {
+            buyerInputValue.style.display = 'none'
+          } else {
+            buyerInputValue.style.display = 'block'
+          }
+        }
+      },
+      immediate: true
+    }
+  },
+  mounted () {
+    let analysisFilterData = sessionStorage.getItem('analysis-filter-data')
+    if(analysisFilterData) {
+      analysisFilterData = JSON.parse(analysisFilterData)
+      const { filters, buyerContent } = analysisFilterData
+      this.filters = filters,
+      this.setFilterParams(filters)
+      this.buyerContent = buyerContent
+      this.$nextTick(() => {
+        this.filters.pname = filters.pname
+      })
+    }
+  },
+  methods: {
+    getKeysStatus () {
+      if(this.buyerContent.length !== 0) {
+        return true
+      } else {
+        if(this.filters.keys !== '') {
+          return true
+        } else {
+          return false
+        }
+      }
+    },
+    startValidate (data) {
+      console.log(data)
+    },
+    onSubmit: function () {
+      this.addKeys()
+      this.$nextTick(() => {
+        const {pname, buyer, area} = this.filters
+        this.ajaxFilters.pname = pname
+        this.ajaxFilters.buyer = buyer
+        this.ajaxFilters.area = area
+        this.ajaxFilters.keys = this.buyerContent
+        const params = {
+          filters: this.filters,
+          buyerContent: this.buyerContent
+        }
+        sessionStorage.setItem('analysis-filter-data', JSON.stringify(params))
+        this.$emit('click', this.ajaxFilters)
+      })
+    },
+    setProName (data) {
+      this.filters.pname = data
+      this.entering = 'project'
+      this.getProjectList(data)
+    },
+    setBuyerName (data) {
+      this.entering = 'buyer'
+      this.getProjectList(data)
+    },
+    // 选择项目
+    onSelect (data, type) {
+      // 查询筛选条件
+      if(type === 'project') {
+        this.showPopover = false
+        this.getFiltersData(data)
+      } else if(type === 'buyer') {
+        this.showBuyerPopover = false
+        this.filters.buyer = data.buyer
+      }
+      this.entering = type
+    },
+    // 项目名称联想
+    getProjectList: utils.debounce(function(){
+      var that = this;
+      let params = {
+        pName: ''
+      }
+      if(this.entering === 'project') {
+        params.pName = this.filters.pname
+      } else if (this.entering === 'buyer') {
+        params.pName = this.filters.buyer
+        params.sType = '1'
+      }
+      if (params.pName !== '' && params.pName.length > 2) {
+        $.ajax({
+          type:'POST',
+          url:'/bigmember/analysis/projectName',
+          data: params,
+          success:function(res) {
+            console.log(res)
+            if(res.error_code == 0 && res.data && res.data.length > 0) {
+              if(params.sType) {
+                that.showBuyerPopover = true
+                that.buyerArr = res.data
+              } else {
+                that.showPopover = true
+                that.projectArr = res.data
+              }
+            }else{
+              if(params.sType) {
+                that.showBuyerPopover = false
+                that.buyerArr = []
+              } else {
+                that.showPopover = false
+                that.projectArr = []
+              }
+            }
+          },
+          error:function(err) {
+            console.log(err)
+          }
+        })
+      } else {
+          this.projectArr = []
+      }
+    }, 500),
+    // 获取筛选条件
+    getFiltersData (data) {
+      $.ajax({
+        type:'POST',
+        url:'/bigmember/analysis/projectInfo',
+        data:{
+          ptid: data.s_id,
+          sourceinfoid: data.sourceinfoid,
+          D: 'detail'
+        },
+        success:function(res) {
+          if(res && res.error_code === 0 && res.data) {
+            this.setFilterParams(res.data)
+            if(res.data.s_subscopeclass) {
+              if(res.data.s_subscopeclass.indexOf('_') > -1) {
+                  res.data.s_subscopeclass = res.data.s_subscopeclass.substring(0,res.data.s_subscopeclass.indexOf('_'))
+              }
+            }
+            this.$emit('action', res.data)
+          }
+        }.bind(this),
+        error:function(err) {
+          console.log(err)
+        }
+      })
+    },
+    setFilterParams (data) {
+      if(data.id) {
+        this.ajaxFilters.pid = data.id
+        this.filters.pid = data.id
+      }
+      if(data.infoid) {
+        this.ajaxFilters.sid = data.infoid
+        this.filters.sid = data.infoid
+      }
+      // 项目名称
+      if(data.projectname || data.pname) {
+        this.filters.pname = data.projectname || data.pname
+      } else {
+        this.filters.pname = ''
+      }
+      // 地区
+      if(data.area && JSON.stringify(data.area) !== '{}') {
+        const picker = this.$refs.picker;
+        this.filters.area = data.area
+        ChinaProvinceJson.forEach(p => {
+          if(p.text.indexOf(data.area) !== -1) {
+            picker.setValues([p.text])
+          }
+        })
+      } else {
+        this.filters.area = ''
+      }
+      // 采购单位
+      if(data.buyer) {
+        this.filters.buyer = data.buyer
+      }
+      // 采购内容
+      if(data.buyerContent && data.buyerContent.length > 0) {
+        this.buyerContent = data.buyerContent
+      } else {
+        this.buyerContent = []
+      }
+      // 时间
+      if(data.limitTime) {
+        this.sortOption.forEach(option => {
+          option.active = false
+          if(data.limitTime === option.text) {
+            option.active = true
+          }
+        })
+      }
+    },
+    // 添加关键词
+    addKeys () {
+      if(this.filters.keys !== '') {
+        const keys = {
+          key: [this.filters.keys],
+          matchway: 1
+        }
+        this.buyerContent.push(keys)
+        this.filters.keys = ''
+      }
+    },
+    // 删除关键词
+    deleteKey (data) {
+      this.buyerContent.forEach((v, index) => {
+        v.key.forEach((m, i) => {
+          if(data === m) {
+            this.buyerContent.splice(index, 1)
+          }
+        })
+      })
+    },
+    // 选择时间
+    setSortRules: function (data) {
+      this.sortOption.forEach(option => {
+        option.active = false
+      })
+      data.active = true
+      this.filters.limitTime = data.text
+      this.ajaxFilters.limitTime = data.value
+      // 关闭菜单
+      this.filtersPopup.time = false
+    },
+    // 选择地区
+    onAreaConfirm: function () {
+      const picker = this.$refs.picker;
+      const selectedValue = picker.getValues()
+      this.filters.area = selectedValue[0].value
+      this.filtersPopup.area = false
+    },
+    // 打开弹出框
+    setOpenPopup: function(data) {
+      this.filtersPopup[data] = true
+    }
+  }
+}

+ 5 - 5
src/web/staticres/common-module/collection/js/chart_options.js

@@ -120,7 +120,7 @@ var chartOptions = {
                     top: 'middle',
                     style: {
                         fill: '#333',
-                        text: '类项目数量(个)',
+                        text: '类项目数量(个)',
                         font: '10px Microsoft YaHei'
                     }
                 }]
@@ -243,7 +243,7 @@ var chartOptions = {
             itemGap: 30,
         },
         series: [{
-            name: '类项目数量',
+            name: '类项目数量',
             type: 'heatmap',
             label: {
                 show: false
@@ -363,7 +363,7 @@ var chartOptions = {
         series: [
             {
                 type:'bar',
-                name:'类项目标书编制周期',
+                name:'类项目标书编制周期',
                 barWidth: 10,
                 barMaxWidth: 10,
                 itemStyle:{
@@ -425,7 +425,7 @@ var chartOptions = {
                         top: 'middle',
                         style: {
                             fill: '#333',
-                            text: '类项目标书编制周期',
+                            text: '类项目标书编制周期',
                             font: '11px Microsoft YaHei',
                             x: 8
                         }
@@ -790,7 +790,7 @@ var chartOptions = {
                 x:0,
                 y:1,
                 itemName: '行业',
-                value: "类项目规模", 
+                value: "类项目规模", 
             },
             labelLine: {
                 show:false

二进制
src/web/staticres/common-module/pc-dialog/image/data-supermarket-buy.png


二进制
src/web/staticres/common-module/pc-dialog/image/data-supermarket-contact.png


+ 72 - 12
src/web/staticres/common-module/pc-dialog/js/leave-info-dialog.js

@@ -11,18 +11,18 @@ var temp = `
             <div class="basic clearfix">
               <div class="form-title">基本信息</div>
               <div class="form-main clearfix">
-                <div class="short-control fl">
+                <div class="short-control fl" v-if="moduleShow.name">
                   <el-form-item label="姓名 :" prop="name">
                     <el-input v-model.trim="form.name"  class="item-input" placeholder="请输入姓名" @focus="nameFocus" required>
                     </el-input>
                   </el-form-item>
                 </div>
-                <div class="short-control fr">
+                <div class="short-control fr" v-if="moduleShow.mail">
                   <el-form-item label="邮箱 :" prop="mail">
                     <el-input v-model.trim="form.mail"  class="item-input" placeholder="请输入邮箱" @focus="mailFocus"></el-input>
                   </el-form-item>
                 </div>
-                <div class="short-control fl">
+                <div class="short-control fl" v-if="moduleShow.phone">
                   <el-form-item label="手机号 :" prop="phone">
                     <el-input v-model.trim="form.phone" maxlength="11" @input="inputPhone"  class="item-input" placeholder="请输入准确的手机号" @focus="phoneFocus"></el-input>
                   </el-form-item>
@@ -39,7 +39,7 @@ var temp = `
             <div class="company clearfix">
               <div class="form-title">公司信息</div>
               <div class="form-main">
-                <div class="long-control" style="position: relative;">
+                <div class="long-control" style="position: relative;" v-if="moduleShow.companyName">
                   <el-form-item label="公司名称 :" prop="companyName">
                     <el-input
                     v-model.trim="form.companyName"
@@ -54,7 +54,7 @@ var temp = `
                     <div class="company-list" v-for="item in companyList" :key="item" @click="selectCompany(item)" v-html="item"></div>
                   </div>
                 </div>
-                <div class="long-control" >
+                <div class="long-control" v-if="moduleShow.companyType">
                   <el-form-item label="公司类型 :" class="company-type" prop="companyType">
                     <el-checkbox-group v-model="form.companyType">
                       <el-checkbox label="投标企业"></el-checkbox>
@@ -67,7 +67,7 @@ var temp = `
                     </el-checkbox-group>
                   </el-form-item>
                 </div>
-                <div class="short-control fl">
+                <div class="short-control fl" v-if="moduleShow.job">
                   <el-form-item label="职位 :" prop="job">
                     <el-select v-model="form.job" placeholder="请选择职位"  class="item-input" clearable>
                       <el-option v-for="item in jobData" :key="item.value" :label="item.label" :value="item.value">
@@ -249,6 +249,13 @@ var vm = new Vue({
         }
       }
     }
+    var validBranch = function(rule,value,callback) {
+      if(value === '') {
+        return callback(new Error('请选择部门'));
+      } else {
+        callback();
+      }
+    }
     return {
       dialogTitle: '为给您匹配精准的推荐信息,请完善个人信息',
       jobData: jobData, // 职位数据
@@ -324,7 +331,8 @@ var vm = new Vue({
           {
             required: true,
             trigger: 'blur',
-            message: '请选择部门'
+            validator: validBranch,
+            message: ''
           }
         ],
       },
@@ -334,7 +342,18 @@ var vm = new Vue({
       showSuccess: false, // 显示提交成功弹框
       showExport: false,
       isForce: false, // 是否强制
-      source: '' // 来源模块
+      source: '', // 来源模块
+      interest: '', // 感兴趣内容
+      moduleShow: {
+        name: true,
+        phone: true,
+        mail: true,
+        code: false,
+        companyName: true,
+        companyType: true,
+        job: true,
+        branch: false
+      }
     }
   },
   computed: {
@@ -376,6 +395,30 @@ var vm = new Vue({
     $(document).off('click')
   },
   methods: {
+    getModules: function () {
+      var source = this.source
+      switch (source) {
+        case 'pc_supermarket_Noresults_customization':
+        case 'pc_market_ApplicationScenario': 
+        case 'pc_supermarket_details_customization': 
+        case 'pc_supermarket_details_buy': {
+          this.hideModule(['mail'])
+          break;
+        }
+        default:
+          this.hideModule()
+          break;
+      }
+    },
+    hideModule: function (keys) {
+      if (!keys) return
+      var hideType = keys
+      for (var k in this.moduleShow) {
+        if (hideType.indexOf(k) !== -1) {
+          this.moduleShow[k] = false
+        }
+      }
+    },
     changeTop: function () {
       this.$nextTick(function () {
         var dialogDom = $('#collectUserInfoDialog .dialog-container')
@@ -468,12 +511,13 @@ var vm = new Vue({
       })
     },
     // 是否留资
-    isNeedSubmit: function(source, callback, dom) {
+    isNeedSubmit: function(source, callback, interest) {
       if (!loginflag) {
         openLoginDig()
         return
       }
       this.source = source
+      this.interest = interest
       this.logAjax(source)
       var _this = this
       $.ajax({
@@ -486,6 +530,7 @@ var vm = new Vue({
           // 判断当前信息否在其他页面留资  如果全部留资 直接弹窗提交成功
           var checkKeys = ['name', 'phone', 'company', 'mail', 'branch', 'position', 'companyType']
           var result = checkRequiredKeys(checkKeys, res.info)
+          res.info.interest = interest
           if (result) {
             callback && callback()
             _this.formAjax(_this.source, res.info)
@@ -525,11 +570,24 @@ var vm = new Vue({
     // 自定义弹窗头部
     isSelfHeader: function(){
       var imgUrl = '/common-module/pc-dialog/image/structed-title.png'
-      if (this.source.indexOf('custom_export') > -1 || this.source.indexOf('custom_data') > -1) {
+      var custom_export = this.source.indexOf('custom_export') > -1
+      var custom_data = this.source.indexOf('custom_data') > -1
+      var api_interface = this.source.indexOf('api_interface') > -1
+      // 数据超市source
+      var marketNoResult = this.source.indexOf('pc_supermarket_Noresults_customization') > -1 // 数据超市列表无数据-申请定制
+      var marketApplicationScenario = this.source.indexOf('pc_market_ApplicationScenario') > -1 // 数据市场落地页-大数据服务应用场景-立即咨询
+      var marketBuy = this.source.indexOf('pc_supermarket_details_buy') > -1 // 数据超市详情页-申请购买
+      var marketDetailCustom = this.source.indexOf('pc_supermarket_details_customization') > -1 // 数据超市详情页-申请定制
+      if (custom_export || custom_data || marketNoResult || marketDetailCustom) {
         imgUrl =  '/common-module/pc-dialog/image/leave-title-custom.png'
-      } else if (this.source.indexOf('api_interface') > -1) {
+      } else if (api_interface) {
         imgUrl =  '/common-module/pc-dialog/image/leave-title-api.png'
+      } else if (marketApplicationScenario) {
+        imgUrl =  '/common-module/pc-dialog/image/data-supermarket-contact.png'
+      } else if (marketBuy) {
+        imgUrl =  '/common-module/pc-dialog/image/data-supermarket-buy.png'
       }
+      this.getModules()
       this.$nextTick(function(){
         $('#collectUserInfoDialog .dialog-header').css('background-image', 'url(' + imgUrl + ')')
       })
@@ -558,11 +616,13 @@ var vm = new Vue({
         position: this.form.job == '其他' ?  this.form.job + '/' + this.form.otherJob : this.form.job,
         code: this.form.code,
         agree: true, // 原来留资模块的同意协议字段,,,默认传一个true 方便后端处理
-        branch: this.form.branch.indexOf('总裁') > -1 || this.form.branch.indexOf('总经理') > -1 || !this.form.job ? '' : this.form.branch
+        branch: this.form.branch.indexOf('总裁') > -1 || this.form.branch.indexOf('总经理') > -1 || !this.form.job ? '' : this.form.branch,
+        // interest: this.interest 
       }
       if (info) {
         params = info
         params.source = source
+        params.interest = info.interest // 感兴趣内容
       }
       var _this = this
       $.ajax({

+ 3 - 3
src/web/staticres/common-module/perfect-info/js/perfect-info.js

@@ -151,9 +151,9 @@ var tipMap = {
   app_analysis_ProjectDetails: '请完善个人信息,我们将尽快与您联系,为您量身定制报告,做市场复盘数据支持。',
 
   // 数据超市列表-申请数据定制
-  app_DataSupermarket_Customization: '专业数据团队,支持私有化部署。请完善个人信息,获取定制化数据解决方案',
-  wx_DataSupermarket_Customization: '专业数据团队,支持私有化部署。请完善个人信息,获取定制化数据解决方案',
-  h5_DataSupermarket_Customization: '专业数据团队,支持私有化部署。请完善个人信息,获取定制化数据解决方案',
+  app_DataSupermarket_Customization: '专业数据团队,支持私有化部署。请完善个人信息,获取定制化数据解决方案',
+  wx_DataSupermarket_Customization: '专业数据团队,支持私有化部署。请完善个人信息,获取定制化数据解决方案',
+  h5_DataSupermarket_Customization: '专业数据团队,支持私有化部署。请完善个人信息,获取定制化数据解决方案',
   // 数据超市详情-申请购买
   app_supermarket_details_buy: '请留下联系方式,我们会尽快让数据经理与您联系,为您提供高效可靠的数据服务。',
   wx_supermarket_details_buy: '请留下联系方式,我们会尽快让数据经理与您联系,为您提供高效可靠的数据服务。',

+ 109 - 0
src/web/staticres/common-module/public/js/china-province-data.js

@@ -0,0 +1,109 @@
+var ChinaProvinceJson = [{
+  "text": "北京市",
+  "value": "北京"
+}, {
+  "text": "天津市",
+  "value": "天津"
+}, {
+  "text": "河北省",
+  "value": "河北"
+}, {
+  "text": "山西省",
+  "value": "山西"
+}, {
+  "text": "内蒙古自治区",
+  "value": "内蒙古自治区"
+}, {
+  "text": "辽宁省",
+  "value": "辽宁"
+}, {
+  "text": "吉林省",
+  "value": "吉林"
+}, {
+  "text": "黑龙江省",
+  "value": "黑龙江"
+}, {
+  "text": "上海市",
+  "value": "上海"
+}, {
+  "text": "江苏省",
+  "value": "江苏"
+}, {
+  "text": "浙江省",
+  "value": "浙江"
+}, {
+  "text": "安徽省",
+  "value": "安徽"
+}, {
+  "text": "福建省",
+  "value": "福建"
+}, {
+  "text": "江西省",
+  "value": "江西"
+}, {
+  "text": "山东省",
+  "value": "山东"
+}, {
+  "text": "河南省",
+  "value": "河南"
+}, {
+  "text": "湖北省",
+  "value": "湖北"
+}, {
+  "text": "湖南省",
+  "value": "湖南"
+}, {
+  "text": "广东省",
+  "value": "广东"
+}, {
+  "text": "海南省",
+  "value": "海南"
+}, {
+  "text": "广西壮族自治区",
+  "value": "广西壮族自治区"
+}, {
+  "text": "甘肃省",
+  "value": "甘肃"
+}, {
+  "text": "陕西省",
+  "value": "陕西"
+}, {
+  "text": "新疆维吾尔自治区",
+  "value": "新疆维吾尔自治区"
+}, {
+  "text": "青海省",
+  "value": "青海"
+}, {
+  "text": "宁夏回族自治区",
+  "value": "宁夏回族自治区"
+}, {
+  "text": "重庆市",
+  "value": "重庆"
+}, {
+  "text": "四川省",
+  "value": "四川"
+}, {
+  "text": "贵州省",
+  "value": "贵州"
+}, {
+  "text": "云南省",
+  "value": "云南"
+}, {
+  "text": "西藏自治区",
+  "value": "西藏自治区"
+}, {
+  "text": "台湾省",
+  "value": "台湾"
+}, {
+  "text": "澳门特别行政区",
+  "value": "澳门特别行政区"
+}, {
+  "text": "香港特别行政区",
+  "value": "香港特别行政区"
+}, {
+  "text": "钓鱼岛",
+  "value": "钓鱼岛"
+}, {
+  "text": " 海外",
+  "value": " 海外"
+}]

+ 456 - 0
src/web/staticres/common-module/viewer/viewer.css

@@ -0,0 +1,456 @@
+/*!
+ * Viewer.js v1.10.4
+ * https://fengyuanchen.github.io/viewerjs
+ *
+ * Copyright 2015-present Chen Fengyuan
+ * Released under the MIT license
+ *
+ * Date: 2022-02-13T08:39:57.620Z
+ */
+
+.viewer-zoom-in::before, .viewer-zoom-out::before, .viewer-one-to-one::before, .viewer-reset::before, .viewer-prev::before, .viewer-play::before, .viewer-next::before, .viewer-rotate-left::before, .viewer-rotate-right::before, .viewer-flip-horizontal::before, .viewer-flip-vertical::before, .viewer-fullscreen::before, .viewer-fullscreen-exit::before, .viewer-close::before {
+    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAAUCAYAAABWOyJDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAQPSURBVHic7Zs/iFxVFMa/0U2UaJGksUgnIVhYxVhpjDbZCBmLdAYECxsRFBTUamcXUiSNncgKQbSxsxH8gzAP3FU2jY0kKKJNiiiIghFlccnP4p3nPCdv3p9778vsLOcHB2bfveeb7955c3jvvNkBIMdxnD64a94GHMfZu3iBcRynN7zAOI7TG15gHCeeNUkr8zaxG2lbYDYsdgMbktBsP03jdQwljSXdtBhLOmtjowC9Mg9L+knSlcD8TNKpSA9lBpK2JF2VdDSR5n5J64m0qli399hNFMUlpshQii5jbXTbHGviB0nLNeNDSd9VO4A2UdB2fp+x0eCnaXxWXGA2X0au/3HgN9P4LFCjIANOJdrLr0zzZ+BEpNYDwKbpnQMeAw4m8HjQtM6Z9qa917zPQwFr3M5KgA6J5rTJCdFZJj9/lyvGhsDvwFNVuV2MhhjrK6b9bFiE+j1r87eBl4HDwCF7/U/k+ofAX5b/EXBv5JoLMuILzf3Ap6Z3EzgdqHMCuF7hcQf4HDgeoHnccncqdK/TvSDWffFXI/exICY/xZyqc6XLWF1UFZna4gJ7q8BsRvgd2/xXpo6P+D9dfT7PpECtA3cnWPM0GXGFZh/wgWltA+cDNC7X+AP4GzjZQe+k5dRxuYPeiuXU7e1qwLpDz7dFjXKRaSwuMLvAlG8zZlG+YmiK1HoFqT7wP2z+4Q45TfEGcMt01xLoNZEBTwRqD4BLpnMLeC1A41UmVxsXgXeBayV/Wx20rpTyrpnWRft7p6O/FdqzGrDukPNtkaMoMo3FBdBSQMOnYBCReyf05s126fU9ytfX98+mY54Kxnp7S9K3kj6U9KYdG0h6UdLbkh7poFXMfUnSOyVvL0h6VtIXHbS6nOP+s/Zm9mvyXW1uuC9ohZ72E9uDmXWLJOB1GxsH+DxPftsB8B6wlGDN02TAkxG6+4D3TWsbeC5CS8CDFce+AW500LhhOW2020TRjK3b21HEmgti9m0RonxbdMZeVzV+/4tF3cBpP7E9mKHNL5q8h5g0eYsCMQz0epq8gQrwMXAgcs0FGXGFRcB9wCemF9PkbYqM/Bas7fxLwNeJPdTdpo4itQti8lPMqTpXuozVRVXPpbHI3KkNTB1NfkL81j2mvhDp91HgV9MKuRIqrykj3WPq4rHyL+axj8/qGPmTqi6F9YDlHOvJU6oYcTsh/TYSzWmTE6JT19CtLTJt32D6CmHe0eQn1O8z5AXgT4sx4Vcu0/EQecMydB8z0hUWkTd2t4CrwNEePqMBcAR4mrBbwyXLPWJa8zrXmmLEhNBmfpkuY2102xxrih+pb+ieAb6vGhuA97UcJ5KR8gZ77K+99xxeYBzH6Q3/Z0fHcXrDC4zjOL3hBcZxnN74F+zlvXFWXF9PAAAAAElFTkSuQmCC");
+    background-repeat: no-repeat;
+    background-size: 280px;
+    color: transparent;
+    display: block;
+    font-size: 0;
+    height: 20px;
+    line-height: 0;
+    width: 20px;
+  }
+
+.viewer-zoom-in::before {
+  background-position: 0 0;
+  content: "Zoom In";
+}
+
+.viewer-zoom-out::before {
+  background-position: -20px 0;
+  content: "Zoom Out";
+}
+
+.viewer-one-to-one::before {
+  background-position: -40px 0;
+  content: "One to One";
+}
+
+.viewer-reset::before {
+  background-position: -60px 0;
+  content: "Reset";
+}
+
+.viewer-prev::before {
+  background-position: -80px 0;
+  content: "Previous";
+}
+
+.viewer-play::before {
+  background-position: -100px 0;
+  content: "Play";
+}
+
+.viewer-next::before {
+  background-position: -120px 0;
+  content: "Next";
+}
+
+.viewer-rotate-left::before {
+  background-position: -140px 0;
+  content: "Rotate Left";
+}
+
+.viewer-rotate-right::before {
+  background-position: -160px 0;
+  content: "Rotate Right";
+}
+
+.viewer-flip-horizontal::before {
+  background-position: -180px 0;
+  content: "Flip Horizontal";
+}
+
+.viewer-flip-vertical::before {
+  background-position: -200px 0;
+  content: "Flip Vertical";
+}
+
+.viewer-fullscreen::before {
+  background-position: -220px 0;
+  content: "Enter Full Screen";
+}
+
+.viewer-fullscreen-exit::before {
+  background-position: -240px 0;
+  content: "Exit Full Screen";
+}
+
+.viewer-close::before {
+  background-position: -260px 0;
+  content: "Close";
+}
+
+.viewer-container {
+  bottom: 0;
+  direction: ltr;
+  font-size: 0;
+  left: 0;
+  line-height: 0;
+  overflow: hidden;
+  position: absolute;
+  right: 0;
+  -webkit-tap-highlight-color: transparent;
+  top: 0;
+  -ms-touch-action: none;
+      touch-action: none;
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none
+}
+
+.viewer-container::-moz-selection, .viewer-container *::-moz-selection {
+    background-color: transparent;
+  }
+
+.viewer-container::selection,
+  .viewer-container *::selection {
+    background-color: transparent;
+  }
+
+.viewer-container:focus {
+    outline: 0;
+  }
+
+.viewer-container img {
+    display: block;
+    height: auto;
+    max-height: none !important;
+    max-width: none !important;
+    min-height: 0 !important;
+    min-width: 0 !important;
+    width: 100%;
+  }
+
+.viewer-canvas {
+  bottom: 0;
+  left: 0;
+  overflow: hidden;
+  position: absolute;
+  right: 0;
+  top: 0
+}
+
+.viewer-canvas > img {
+    height: auto;
+    margin: 15px auto;
+    max-width: 90% !important;
+    width: auto;
+  }
+
+.viewer-footer {
+  bottom: 0;
+  left: 0;
+  overflow: hidden;
+  position: absolute;
+  right: 0;
+  text-align: center;
+}
+
+.viewer-navbar {
+  background-color: rgba(0, 0, 0, 50%);
+  overflow: hidden;
+}
+
+.viewer-list {
+  box-sizing: content-box;
+  height: 50px;
+  margin: 0;
+  overflow: hidden;
+  padding: 1px 0
+}
+
+.viewer-list > li {
+    color: transparent;
+    cursor: pointer;
+    float: left;
+    font-size: 0;
+    height: 50px;
+    line-height: 0;
+    opacity: 0.5;
+    overflow: hidden;
+    transition: opacity 0.15s;
+    width: 30px
+  }
+
+.viewer-list > li:focus,
+    .viewer-list > li:hover {
+      opacity: 0.75;
+    }
+
+.viewer-list > li:focus {
+      outline: 0;
+    }
+
+.viewer-list > li + li {
+      margin-left: 1px;
+    }
+
+.viewer-list > .viewer-loading {
+    position: relative
+  }
+
+.viewer-list > .viewer-loading::after {
+      border-width: 2px;
+      height: 20px;
+      margin-left: -10px;
+      margin-top: -10px;
+      width: 20px;
+    }
+
+.viewer-list > .viewer-active,
+  .viewer-list > .viewer-active:focus,
+  .viewer-list > .viewer-active:hover {
+    opacity: 1;
+  }
+
+.viewer-player {
+  background-color: #000;
+  bottom: 0;
+  cursor: none;
+  display: none;
+  left: 0;
+  position: absolute;
+  right: 0;
+  top: 0;
+  z-index: 1
+}
+
+.viewer-player > img {
+    left: 0;
+    position: absolute;
+    top: 0;
+  }
+
+.viewer-toolbar > ul {
+    display: inline-block;
+    margin: 0 auto 5px;
+    overflow: hidden;
+    padding: 6px 3px
+  }
+
+.viewer-toolbar > ul > li {
+      background-color: rgba(0, 0, 0, 50%);
+      border-radius: 50%;
+      cursor: pointer;
+      float: left;
+      height: 24px;
+      overflow: hidden;
+      transition: background-color 0.15s;
+      width: 24px
+    }
+
+.viewer-toolbar > ul > li:focus,
+      .viewer-toolbar > ul > li:hover {
+        background-color: rgba(0, 0, 0, 80%);
+      }
+
+.viewer-toolbar > ul > li:focus {
+        box-shadow: 0 0 3px #fff;
+        outline: 0;
+        position: relative;
+        z-index: 1;
+      }
+
+.viewer-toolbar > ul > li::before {
+        margin: 2px;
+      }
+
+.viewer-toolbar > ul > li + li {
+        margin-left: 1px;
+      }
+
+.viewer-toolbar > ul > .viewer-small {
+      height: 18px;
+      margin-bottom: 3px;
+      margin-top: 3px;
+      width: 18px
+    }
+
+.viewer-toolbar > ul > .viewer-small::before {
+        margin: -1px;
+      }
+
+.viewer-toolbar > ul > .viewer-large {
+      height: 30px;
+      margin-bottom: -3px;
+      margin-top: -3px;
+      width: 30px
+    }
+
+.viewer-toolbar > ul > .viewer-large::before {
+        margin: 5px;
+      }
+
+.viewer-tooltip {
+  background-color: rgba(0, 0, 0, 80%);
+  border-radius: 10px;
+  color: #fff;
+  display: none;
+  font-size: 12px;
+  height: 20px;
+  left: 50%;
+  line-height: 20px;
+  margin-left: -25px;
+  margin-top: -10px;
+  position: absolute;
+  text-align: center;
+  top: 50%;
+  width: 50px;
+}
+
+.viewer-title {
+  color: #ccc;
+  display: inline-block;
+  font-size: 12px;
+  line-height: 1.2;
+  margin: 0 5% 5px;
+  max-width: 90%;
+  opacity: 0.8;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  transition: opacity 0.15s;
+  white-space: nowrap
+}
+
+.viewer-title:hover {
+    opacity: 1;
+  }
+
+.viewer-button {
+  background-color: rgba(0, 0, 0, 50%);
+  border-radius: 50%;
+  cursor: pointer;
+  height: 80px;
+  overflow: hidden;
+  position: absolute;
+  right: -40px;
+  top: -40px;
+  transition: background-color 0.15s;
+  width: 80px
+}
+
+.viewer-button:focus,
+  .viewer-button:hover {
+    background-color: rgba(0, 0, 0, 80%);
+  }
+
+.viewer-button:focus {
+    box-shadow: 0 0 3px #fff;
+    outline: 0;
+  }
+
+.viewer-button::before {
+    bottom: 15px;
+    left: 15px;
+    position: absolute;
+  }
+
+.viewer-fixed {
+  position: fixed;
+}
+
+.viewer-open {
+  overflow: hidden;
+}
+
+.viewer-show {
+  display: block;
+}
+
+.viewer-hide {
+  display: none;
+}
+
+.viewer-backdrop {
+  background-color: rgba(0, 0, 0, 50%);
+}
+
+.viewer-invisible {
+  visibility: hidden;
+}
+
+.viewer-move {
+  cursor: move;
+  cursor: -webkit-grab;
+  cursor: grab;
+}
+
+.viewer-fade {
+  opacity: 0;
+}
+
+.viewer-in {
+  opacity: 1;
+}
+
+.viewer-transition {
+  transition: all 0.3s;
+}
+
+@-webkit-keyframes viewer-spinner {
+  0% {
+    transform: rotate(0deg);
+  }
+
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+@keyframes viewer-spinner {
+  0% {
+    transform: rotate(0deg);
+  }
+
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+.viewer-loading::after {
+    -webkit-animation: viewer-spinner 1s linear infinite;
+            animation: viewer-spinner 1s linear infinite;
+    border: 4px solid rgba(255, 255, 255, 10%);
+    border-left-color: rgba(255, 255, 255, 50%);
+    border-radius: 50%;
+    content: "";
+    display: inline-block;
+    height: 40px;
+    left: 50%;
+    margin-left: -20px;
+    margin-top: -20px;
+    position: absolute;
+    top: 50%;
+    width: 40px;
+    z-index: 1;
+  }
+
+@media (max-width: 767px) {
+  .viewer-hide-xs-down {
+    display: none;
+  }
+}
+
+@media (max-width: 991px) {
+  .viewer-hide-sm-down {
+    display: none;
+  }
+}
+
+@media (max-width: 1199px) {
+  .viewer-hide-md-down {
+    display: none;
+  }
+}

+ 3597 - 0
src/web/staticres/common-module/viewer/viewer.js

@@ -0,0 +1,3597 @@
+/*!
+ * Viewer.js v1.10.5
+ * https://fengyuanchen.github.io/viewerjs
+ *
+ * Copyright 2015-present Chen Fengyuan
+ * Released under the MIT license
+ *
+ * Date: 2022-04-05T08:21:02.491Z
+ */
+
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+  typeof define === 'function' && define.amd ? define(factory) :
+  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Viewer = factory());
+})(this, (function () { 'use strict';
+
+  function ownKeys(object, enumerableOnly) {
+    var keys = Object.keys(object);
+
+    if (Object.getOwnPropertySymbols) {
+      var symbols = Object.getOwnPropertySymbols(object);
+      enumerableOnly && (symbols = symbols.filter(function (sym) {
+        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
+      })), keys.push.apply(keys, symbols);
+    }
+
+    return keys;
+  }
+
+  function _objectSpread2(target) {
+    for (var i = 1; i < arguments.length; i++) {
+      var source = null != arguments[i] ? arguments[i] : {};
+      i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
+        _defineProperty(target, key, source[key]);
+      }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
+        Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
+      });
+    }
+
+    return target;
+  }
+
+  function _typeof(obj) {
+    "@babel/helpers - typeof";
+
+    return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
+      return typeof obj;
+    } : function (obj) {
+      return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+    }, _typeof(obj);
+  }
+
+  function _classCallCheck(instance, Constructor) {
+    if (!(instance instanceof Constructor)) {
+      throw new TypeError("Cannot call a class as a function");
+    }
+  }
+
+  function _defineProperties(target, props) {
+    for (var i = 0; i < props.length; i++) {
+      var descriptor = props[i];
+      descriptor.enumerable = descriptor.enumerable || false;
+      descriptor.configurable = true;
+      if ("value" in descriptor) descriptor.writable = true;
+      Object.defineProperty(target, descriptor.key, descriptor);
+    }
+  }
+
+  function _createClass(Constructor, protoProps, staticProps) {
+    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+    if (staticProps) _defineProperties(Constructor, staticProps);
+    Object.defineProperty(Constructor, "prototype", {
+      writable: false
+    });
+    return Constructor;
+  }
+
+  function _defineProperty(obj, key, value) {
+    if (key in obj) {
+      Object.defineProperty(obj, key, {
+        value: value,
+        enumerable: true,
+        configurable: true,
+        writable: true
+      });
+    } else {
+      obj[key] = value;
+    }
+
+    return obj;
+  }
+
+  var DEFAULTS = {
+    /**
+     * Enable a modal backdrop, specify `static` for a backdrop
+     * which doesn't close the modal on click.
+     * @type {boolean}
+     */
+    backdrop: true,
+
+    /**
+     * Show the button on the top-right of the viewer.
+     * @type {boolean}
+     */
+    button: true,
+
+    /**
+     * Show the navbar.
+     * @type {boolean | number}
+     */
+    navbar: true,
+
+    /**
+     * Specify the visibility and the content of the title.
+     * @type {boolean | number | Function | Array}
+     */
+    title: true,
+
+    /**
+     * Show the toolbar.
+     * @type {boolean | number | Object}
+     */
+    toolbar: true,
+
+    /**
+     * Custom class name(s) to add to the viewer's root element.
+     * @type {string}
+     */
+    className: '',
+
+    /**
+     * Define where to put the viewer in modal mode.
+     * @type {string | Element}
+     */
+    container: 'body',
+
+    /**
+     * Filter the images for viewing. Return true if the image is viewable.
+     * @type {Function}
+     */
+    filter: null,
+
+    /**
+     * Enable to request fullscreen when play.
+     * {@link https://developer.mozilla.org/en-US/docs/Web/API/FullscreenOptions}
+     * @type {boolean|FullscreenOptions}
+     */
+    fullscreen: true,
+
+    /**
+     * Define the extra attributes to inherit from the original image.
+     * @type {Array}
+     */
+    inheritedAttributes: ['crossOrigin', 'decoding', 'isMap', 'loading', 'referrerPolicy', 'sizes', 'srcset', 'useMap'],
+
+    /**
+     * Define the initial index of image for viewing.
+     * @type {number}
+     */
+    initialViewIndex: 0,
+
+    /**
+     * Enable inline mode.
+     * @type {boolean}
+     */
+    inline: false,
+
+    /**
+     * The amount of time to delay between automatically cycling an image when playing.
+     * @type {number}
+     */
+    interval: 5000,
+
+    /**
+     * Enable keyboard support.
+     * @type {boolean}
+     */
+    keyboard: true,
+
+    /**
+     * Focus the viewer when initialized.
+     * @type {boolean}
+     */
+    focus: true,
+
+    /**
+     * Indicate if show a loading spinner when load image or not.
+     * @type {boolean}
+     */
+    loading: true,
+
+    /**
+     * Indicate if enable loop viewing or not.
+     * @type {boolean}
+     */
+    loop: true,
+
+    /**
+     * Min width of the viewer in inline mode.
+     * @type {number}
+     */
+    minWidth: 200,
+
+    /**
+     * Min height of the viewer in inline mode.
+     * @type {number}
+     */
+    minHeight: 100,
+
+    /**
+     * Enable to move the image.
+     * @type {boolean}
+     */
+    movable: true,
+
+    /**
+     * Enable to rotate the image.
+     * @type {boolean}
+     */
+    rotatable: true,
+
+    /**
+     * Enable to scale the image.
+     * @type {boolean}
+     */
+    scalable: true,
+
+    /**
+     * Enable to zoom the image.
+     * @type {boolean}
+     */
+    zoomable: true,
+
+    /**
+     * Enable to zoom the current image by dragging on the touch screen.
+     * @type {boolean}
+     */
+    zoomOnTouch: true,
+
+    /**
+     * Enable to zoom the image by wheeling mouse.
+     * @type {boolean}
+     */
+    zoomOnWheel: true,
+
+    /**
+     * Enable to slide to the next or previous image by swiping on the touch screen.
+     * @type {boolean}
+     */
+    slideOnTouch: true,
+
+    /**
+     * Indicate if toggle the image size between its natural size
+     * and initial size when double click on the image or not.
+     * @type {boolean}
+     */
+    toggleOnDblclick: true,
+
+    /**
+     * Show the tooltip with image ratio (percentage) when zoom in or zoom out.
+     * @type {boolean}
+     */
+    tooltip: true,
+
+    /**
+     * Enable CSS3 Transition for some special elements.
+     * @type {boolean}
+     */
+    transition: true,
+
+    /**
+     * Define the CSS `z-index` value of viewer in modal mode.
+     * @type {number}
+     */
+    zIndex: 2015,
+
+    /**
+     * Define the CSS `z-index` value of viewer in inline mode.
+     * @type {number}
+     */
+    zIndexInline: 0,
+
+    /**
+     * Define the ratio when zoom the image by wheeling mouse.
+     * @type {number}
+     */
+    zoomRatio: 0.1,
+
+    /**
+     * Define the min ratio of the image when zoom out.
+     * @type {number}
+     */
+    minZoomRatio: 0.01,
+
+    /**
+     * Define the max ratio of the image when zoom in.
+     * @type {number}
+     */
+    maxZoomRatio: 100,
+
+    /**
+     * Define where to get the original image URL for viewing.
+     * @type {string | Function}
+     */
+    url: 'src',
+
+    /**
+     * Event shortcuts.
+     * @type {Function}
+     */
+    ready: null,
+    show: null,
+    shown: null,
+    hide: null,
+    hidden: null,
+    view: null,
+    viewed: null,
+    move: null,
+    moved: null,
+    rotate: null,
+    rotated: null,
+    scale: null,
+    scaled: null,
+    zoom: null,
+    zoomed: null,
+    play: null,
+    stop: null
+  };
+
+  var TEMPLATE = '<div class="viewer-container" tabindex="-1" touch-action="none">' + '<div class="viewer-canvas"></div>' + '<div class="viewer-footer">' + '<div class="viewer-title"></div>' + '<div class="viewer-toolbar"></div>' + '<div class="viewer-navbar">' + '<ul class="viewer-list" role="navigation"></ul>' + '</div>' + '</div>' + '<div class="viewer-tooltip" role="alert" aria-hidden="true"></div>' + '<div class="viewer-button" data-viewer-action="mix" role="button"></div>' + '<div class="viewer-player"></div>' + '</div>';
+
+  var IS_BROWSER = typeof window !== 'undefined' && typeof window.document !== 'undefined';
+  var WINDOW = IS_BROWSER ? window : {};
+  var IS_TOUCH_DEVICE = IS_BROWSER && WINDOW.document.documentElement ? 'ontouchstart' in WINDOW.document.documentElement : false;
+  var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;
+  var NAMESPACE = 'viewer'; // Actions
+
+  var ACTION_MOVE = 'move';
+  var ACTION_SWITCH = 'switch';
+  var ACTION_ZOOM = 'zoom'; // Classes
+
+  var CLASS_ACTIVE = "".concat(NAMESPACE, "-active");
+  var CLASS_CLOSE = "".concat(NAMESPACE, "-close");
+  var CLASS_FADE = "".concat(NAMESPACE, "-fade");
+  var CLASS_FIXED = "".concat(NAMESPACE, "-fixed");
+  var CLASS_FULLSCREEN = "".concat(NAMESPACE, "-fullscreen");
+  var CLASS_FULLSCREEN_EXIT = "".concat(NAMESPACE, "-fullscreen-exit");
+  var CLASS_HIDE = "".concat(NAMESPACE, "-hide");
+  var CLASS_HIDE_MD_DOWN = "".concat(NAMESPACE, "-hide-md-down");
+  var CLASS_HIDE_SM_DOWN = "".concat(NAMESPACE, "-hide-sm-down");
+  var CLASS_HIDE_XS_DOWN = "".concat(NAMESPACE, "-hide-xs-down");
+  var CLASS_IN = "".concat(NAMESPACE, "-in");
+  var CLASS_INVISIBLE = "".concat(NAMESPACE, "-invisible");
+  var CLASS_LOADING = "".concat(NAMESPACE, "-loading");
+  var CLASS_MOVE = "".concat(NAMESPACE, "-move");
+  var CLASS_OPEN = "".concat(NAMESPACE, "-open");
+  var CLASS_SHOW = "".concat(NAMESPACE, "-show");
+  var CLASS_TRANSITION = "".concat(NAMESPACE, "-transition"); // Native events
+
+  var EVENT_CLICK = 'click';
+  var EVENT_DBLCLICK = 'dblclick';
+  var EVENT_DRAG_START = 'dragstart';
+  var EVENT_FOCUSIN = 'focusin';
+  var EVENT_KEY_DOWN = 'keydown';
+  var EVENT_LOAD = 'load';
+  var EVENT_ERROR = 'error';
+  var EVENT_TOUCH_END = IS_TOUCH_DEVICE ? 'touchend touchcancel' : 'mouseup';
+  var EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? 'touchmove' : 'mousemove';
+  var EVENT_TOUCH_START = IS_TOUCH_DEVICE ? 'touchstart' : 'mousedown';
+  var EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? 'pointerdown' : EVENT_TOUCH_START;
+  var EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? 'pointermove' : EVENT_TOUCH_MOVE;
+  var EVENT_POINTER_UP = HAS_POINTER_EVENT ? 'pointerup pointercancel' : EVENT_TOUCH_END;
+  var EVENT_RESIZE = 'resize';
+  var EVENT_TRANSITION_END = 'transitionend';
+  var EVENT_WHEEL = 'wheel'; // Custom events
+
+  var EVENT_READY = 'ready';
+  var EVENT_SHOW = 'show';
+  var EVENT_SHOWN = 'shown';
+  var EVENT_HIDE = 'hide';
+  var EVENT_HIDDEN = 'hidden';
+  var EVENT_VIEW = 'view';
+  var EVENT_VIEWED = 'viewed';
+  var EVENT_MOVE = 'move';
+  var EVENT_MOVED = 'moved';
+  var EVENT_ROTATE = 'rotate';
+  var EVENT_ROTATED = 'rotated';
+  var EVENT_SCALE = 'scale';
+  var EVENT_SCALED = 'scaled';
+  var EVENT_ZOOM = 'zoom';
+  var EVENT_ZOOMED = 'zoomed';
+  var EVENT_PLAY = 'play';
+  var EVENT_STOP = 'stop'; // Data keys
+
+  var DATA_ACTION = "".concat(NAMESPACE, "Action"); // RegExps
+
+  var REGEXP_SPACES = /\s\s*/; // Misc
+
+  var BUTTONS = ['zoom-in', 'zoom-out', 'one-to-one', 'reset', 'prev', 'play', 'next', 'rotate-left', 'rotate-right', 'flip-horizontal', 'flip-vertical'];
+
+  /**
+   * Check if the given value is a string.
+   * @param {*} value - The value to check.
+   * @returns {boolean} Returns `true` if the given value is a string, else `false`.
+   */
+
+  function isString(value) {
+    return typeof value === 'string';
+  }
+  /**
+   * Check if the given value is not a number.
+   */
+
+  var isNaN = Number.isNaN || WINDOW.isNaN;
+  /**
+   * Check if the given value is a number.
+   * @param {*} value - The value to check.
+   * @returns {boolean} Returns `true` if the given value is a number, else `false`.
+   */
+
+  function isNumber(value) {
+    return typeof value === 'number' && !isNaN(value);
+  }
+  /**
+   * Check if the given value is undefined.
+   * @param {*} value - The value to check.
+   * @returns {boolean} Returns `true` if the given value is undefined, else `false`.
+   */
+
+  function isUndefined(value) {
+    return typeof value === 'undefined';
+  }
+  /**
+   * Check if the given value is an object.
+   * @param {*} value - The value to check.
+   * @returns {boolean} Returns `true` if the given value is an object, else `false`.
+   */
+
+  function isObject(value) {
+    return _typeof(value) === 'object' && value !== null;
+  }
+  var hasOwnProperty = Object.prototype.hasOwnProperty;
+  /**
+   * Check if the given value is a plain object.
+   * @param {*} value - The value to check.
+   * @returns {boolean} Returns `true` if the given value is a plain object, else `false`.
+   */
+
+  function isPlainObject(value) {
+    if (!isObject(value)) {
+      return false;
+    }
+
+    try {
+      var _constructor = value.constructor;
+      var prototype = _constructor.prototype;
+      return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf');
+    } catch (error) {
+      return false;
+    }
+  }
+  /**
+   * Check if the given value is a function.
+   * @param {*} value - The value to check.
+   * @returns {boolean} Returns `true` if the given value is a function, else `false`.
+   */
+
+  function isFunction(value) {
+    return typeof value === 'function';
+  }
+  /**
+   * Iterate the given data.
+   * @param {*} data - The data to iterate.
+   * @param {Function} callback - The process function for each element.
+   * @returns {*} The original data.
+   */
+
+  function forEach(data, callback) {
+    if (data && isFunction(callback)) {
+      if (Array.isArray(data) || isNumber(data.length)
+      /* array-like */
+      ) {
+        var length = data.length;
+        var i;
+
+        for (i = 0; i < length; i += 1) {
+          if (callback.call(data, data[i], i, data) === false) {
+            break;
+          }
+        }
+      } else if (isObject(data)) {
+        Object.keys(data).forEach(function (key) {
+          callback.call(data, data[key], key, data);
+        });
+      }
+    }
+
+    return data;
+  }
+  /**
+   * Extend the given object.
+   * @param {*} obj - The object to be extended.
+   * @param {*} args - The rest objects which will be merged to the first object.
+   * @returns {Object} The extended object.
+   */
+
+  var assign = Object.assign || function assign(obj) {
+    for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+      args[_key - 1] = arguments[_key];
+    }
+
+    if (isObject(obj) && args.length > 0) {
+      args.forEach(function (arg) {
+        if (isObject(arg)) {
+          Object.keys(arg).forEach(function (key) {
+            obj[key] = arg[key];
+          });
+        }
+      });
+    }
+
+    return obj;
+  };
+  var REGEXP_SUFFIX = /^(?:width|height|left|top|marginLeft|marginTop)$/;
+  /**
+   * Apply styles to the given element.
+   * @param {Element} element - The target element.
+   * @param {Object} styles - The styles for applying.
+   */
+
+  function setStyle(element, styles) {
+    var style = element.style;
+    forEach(styles, function (value, property) {
+      if (REGEXP_SUFFIX.test(property) && isNumber(value)) {
+        value += 'px';
+      }
+
+      style[property] = value;
+    });
+  }
+  /**
+   * Escape a string for using in HTML.
+   * @param {String} value - The string to escape.
+   * @returns {String} Returns the escaped string.
+   */
+
+  function escapeHTMLEntities(value) {
+    return isString(value) ? value.replace(/&(?!amp;|quot;|#39;|lt;|gt;)/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;') : value;
+  }
+  /**
+   * Check if the given element has a special class.
+   * @param {Element} element - The element to check.
+   * @param {string} value - The class to search.
+   * @returns {boolean} Returns `true` if the special class was found.
+   */
+
+  function hasClass(element, value) {
+    if (!element || !value) {
+      return false;
+    }
+
+    return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1;
+  }
+  /**
+   * Add classes to the given element.
+   * @param {Element} element - The target element.
+   * @param {string} value - The classes to be added.
+   */
+
+  function addClass(element, value) {
+    if (!element || !value) {
+      return;
+    }
+
+    if (isNumber(element.length)) {
+      forEach(element, function (elem) {
+        addClass(elem, value);
+      });
+      return;
+    }
+
+    if (element.classList) {
+      element.classList.add(value);
+      return;
+    }
+
+    var className = element.className.trim();
+
+    if (!className) {
+      element.className = value;
+    } else if (className.indexOf(value) < 0) {
+      element.className = "".concat(className, " ").concat(value);
+    }
+  }
+  /**
+   * Remove classes from the given element.
+   * @param {Element} element - The target element.
+   * @param {string} value - The classes to be removed.
+   */
+
+  function removeClass(element, value) {
+    if (!element || !value) {
+      return;
+    }
+
+    if (isNumber(element.length)) {
+      forEach(element, function (elem) {
+        removeClass(elem, value);
+      });
+      return;
+    }
+
+    if (element.classList) {
+      element.classList.remove(value);
+      return;
+    }
+
+    if (element.className.indexOf(value) >= 0) {
+      element.className = element.className.replace(value, '');
+    }
+  }
+  /**
+   * Add or remove classes from the given element.
+   * @param {Element} element - The target element.
+   * @param {string} value - The classes to be toggled.
+   * @param {boolean} added - Add only.
+   */
+
+  function toggleClass(element, value, added) {
+    if (!value) {
+      return;
+    }
+
+    if (isNumber(element.length)) {
+      forEach(element, function (elem) {
+        toggleClass(elem, value, added);
+      });
+      return;
+    } // IE10-11 doesn't support the second parameter of `classList.toggle`
+
+
+    if (added) {
+      addClass(element, value);
+    } else {
+      removeClass(element, value);
+    }
+  }
+  var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g;
+  /**
+   * Transform the given string from camelCase to kebab-case
+   * @param {string} value - The value to transform.
+   * @returns {string} The transformed value.
+   */
+
+  function hyphenate(value) {
+    return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase();
+  }
+  /**
+   * Get data from the given element.
+   * @param {Element} element - The target element.
+   * @param {string} name - The data key to get.
+   * @returns {string} The data value.
+   */
+
+  function getData(element, name) {
+    if (isObject(element[name])) {
+      return element[name];
+    }
+
+    if (element.dataset) {
+      return element.dataset[name];
+    }
+
+    return element.getAttribute("data-".concat(hyphenate(name)));
+  }
+  /**
+   * Set data to the given element.
+   * @param {Element} element - The target element.
+   * @param {string} name - The data key to set.
+   * @param {string} data - The data value.
+   */
+
+  function setData(element, name, data) {
+    if (isObject(data)) {
+      element[name] = data;
+    } else if (element.dataset) {
+      element.dataset[name] = data;
+    } else {
+      element.setAttribute("data-".concat(hyphenate(name)), data);
+    }
+  }
+
+  var onceSupported = function () {
+    var supported = false;
+
+    if (IS_BROWSER) {
+      var once = false;
+
+      var listener = function listener() {};
+
+      var options = Object.defineProperty({}, 'once', {
+        get: function get() {
+          supported = true;
+          return once;
+        },
+
+        /**
+         * This setter can fix a `TypeError` in strict mode
+         * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only}
+         * @param {boolean} value - The value to set
+         */
+        set: function set(value) {
+          once = value;
+        }
+      });
+      WINDOW.addEventListener('test', listener, options);
+      WINDOW.removeEventListener('test', listener, options);
+    }
+
+    return supported;
+  }();
+  /**
+   * Remove event listener from the target element.
+   * @param {Element} element - The event target.
+   * @param {string} type - The event type(s).
+   * @param {Function} listener - The event listener.
+   * @param {Object} options - The event options.
+   */
+
+
+  function removeListener(element, type, listener) {
+    var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+    var handler = listener;
+    type.trim().split(REGEXP_SPACES).forEach(function (event) {
+      if (!onceSupported) {
+        var listeners = element.listeners;
+
+        if (listeners && listeners[event] && listeners[event][listener]) {
+          handler = listeners[event][listener];
+          delete listeners[event][listener];
+
+          if (Object.keys(listeners[event]).length === 0) {
+            delete listeners[event];
+          }
+
+          if (Object.keys(listeners).length === 0) {
+            delete element.listeners;
+          }
+        }
+      }
+
+      element.removeEventListener(event, handler, options);
+    });
+  }
+  /**
+   * Add event listener to the target element.
+   * @param {Element} element - The event target.
+   * @param {string} type - The event type(s).
+   * @param {Function} listener - The event listener.
+   * @param {Object} options - The event options.
+   */
+
+  function addListener(element, type, listener) {
+    var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+    var _handler = listener;
+    type.trim().split(REGEXP_SPACES).forEach(function (event) {
+      if (options.once && !onceSupported) {
+        var _element$listeners = element.listeners,
+            listeners = _element$listeners === void 0 ? {} : _element$listeners;
+
+        _handler = function handler() {
+          delete listeners[event][listener];
+          element.removeEventListener(event, _handler, options);
+
+          for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+            args[_key2] = arguments[_key2];
+          }
+
+          listener.apply(element, args);
+        };
+
+        if (!listeners[event]) {
+          listeners[event] = {};
+        }
+
+        if (listeners[event][listener]) {
+          element.removeEventListener(event, listeners[event][listener], options);
+        }
+
+        listeners[event][listener] = _handler;
+        element.listeners = listeners;
+      }
+
+      element.addEventListener(event, _handler, options);
+    });
+  }
+  /**
+   * Dispatch event on the target element.
+   * @param {Element} element - The event target.
+   * @param {string} type - The event type(s).
+   * @param {Object} data - The additional event data.
+   * @param {Object} options - The additional event options.
+   * @returns {boolean} Indicate if the event is default prevented or not.
+   */
+
+  function dispatchEvent(element, type, data, options) {
+    var event; // Event and CustomEvent on IE9-11 are global objects, not constructors
+
+    if (isFunction(Event) && isFunction(CustomEvent)) {
+      event = new CustomEvent(type, _objectSpread2({
+        bubbles: true,
+        cancelable: true,
+        detail: data
+      }, options));
+    } else {
+      event = document.createEvent('CustomEvent');
+      event.initCustomEvent(type, true, true, data);
+    }
+
+    return element.dispatchEvent(event);
+  }
+  /**
+   * Get the offset base on the document.
+   * @param {Element} element - The target element.
+   * @returns {Object} The offset data.
+   */
+
+  function getOffset(element) {
+    var box = element.getBoundingClientRect();
+    return {
+      left: box.left + (window.pageXOffset - document.documentElement.clientLeft),
+      top: box.top + (window.pageYOffset - document.documentElement.clientTop)
+    };
+  }
+  /**
+   * Get transforms base on the given object.
+   * @param {Object} obj - The target object.
+   * @returns {string} A string contains transform values.
+   */
+
+  function getTransforms(_ref) {
+    var rotate = _ref.rotate,
+        scaleX = _ref.scaleX,
+        scaleY = _ref.scaleY,
+        translateX = _ref.translateX,
+        translateY = _ref.translateY;
+    var values = [];
+
+    if (isNumber(translateX) && translateX !== 0) {
+      values.push("translateX(".concat(translateX, "px)"));
+    }
+
+    if (isNumber(translateY) && translateY !== 0) {
+      values.push("translateY(".concat(translateY, "px)"));
+    } // Rotate should come first before scale to match orientation transform
+
+
+    if (isNumber(rotate) && rotate !== 0) {
+      values.push("rotate(".concat(rotate, "deg)"));
+    }
+
+    if (isNumber(scaleX) && scaleX !== 1) {
+      values.push("scaleX(".concat(scaleX, ")"));
+    }
+
+    if (isNumber(scaleY) && scaleY !== 1) {
+      values.push("scaleY(".concat(scaleY, ")"));
+    }
+
+    var transform = values.length ? values.join(' ') : 'none';
+    return {
+      WebkitTransform: transform,
+      msTransform: transform,
+      transform: transform
+    };
+  }
+  /**
+   * Get an image name from an image url.
+   * @param {string} url - The target url.
+   * @example
+   * // picture.jpg
+   * getImageNameFromURL('https://domain.com/path/to/picture.jpg?size=1280×960')
+   * @returns {string} A string contains the image name.
+   */
+
+  function getImageNameFromURL(url) {
+    return isString(url) ? decodeURIComponent(url.replace(/^.*\//, '').replace(/[?&#].*$/, '')) : '';
+  }
+  var IS_SAFARI = WINDOW.navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(WINDOW.navigator.userAgent);
+  /**
+   * Get an image's natural sizes.
+   * @param {string} image - The target image.
+   * @param {Object} options - The viewer options.
+   * @param {Function} callback - The callback function.
+   * @returns {HTMLImageElement} The new image.
+   */
+
+  function getImageNaturalSizes(image, options, callback) {
+    var newImage = document.createElement('img'); // Modern browsers (except Safari)
+
+    if (image.naturalWidth && !IS_SAFARI) {
+      callback(image.naturalWidth, image.naturalHeight);
+      return newImage;
+    }
+
+    var body = document.body || document.documentElement;
+
+    newImage.onload = function () {
+      callback(newImage.width, newImage.height);
+
+      if (!IS_SAFARI) {
+        body.removeChild(newImage);
+      }
+    };
+
+    forEach(options.inheritedAttributes, function (name) {
+      var value = image.getAttribute(name);
+
+      if (value !== null) {
+        newImage.setAttribute(name, value);
+      }
+    });
+    newImage.src = image.src; // iOS Safari will convert the image automatically
+    // with its orientation once append it into DOM
+
+    if (!IS_SAFARI) {
+      newImage.style.cssText = 'left:0;' + 'max-height:none!important;' + 'max-width:none!important;' + 'min-height:0!important;' + 'min-width:0!important;' + 'opacity:0;' + 'position:absolute;' + 'top:0;' + 'z-index:-1;';
+      body.appendChild(newImage);
+    }
+
+    return newImage;
+  }
+  /**
+   * Get the related class name of a responsive type number.
+   * @param {string} type - The responsive type.
+   * @returns {string} The related class name.
+   */
+
+  function getResponsiveClass(type) {
+    switch (type) {
+      case 2:
+        return CLASS_HIDE_XS_DOWN;
+
+      case 3:
+        return CLASS_HIDE_SM_DOWN;
+
+      case 4:
+        return CLASS_HIDE_MD_DOWN;
+
+      default:
+        return '';
+    }
+  }
+  /**
+   * Get the max ratio of a group of pointers.
+   * @param {string} pointers - The target pointers.
+   * @returns {number} The result ratio.
+   */
+
+  function getMaxZoomRatio(pointers) {
+    var pointers2 = _objectSpread2({}, pointers);
+
+    var ratios = [];
+    forEach(pointers, function (pointer, pointerId) {
+      delete pointers2[pointerId];
+      forEach(pointers2, function (pointer2) {
+        var x1 = Math.abs(pointer.startX - pointer2.startX);
+        var y1 = Math.abs(pointer.startY - pointer2.startY);
+        var x2 = Math.abs(pointer.endX - pointer2.endX);
+        var y2 = Math.abs(pointer.endY - pointer2.endY);
+        var z1 = Math.sqrt(x1 * x1 + y1 * y1);
+        var z2 = Math.sqrt(x2 * x2 + y2 * y2);
+        var ratio = (z2 - z1) / z1;
+        ratios.push(ratio);
+      });
+    });
+    ratios.sort(function (a, b) {
+      return Math.abs(a) < Math.abs(b);
+    });
+    return ratios[0];
+  }
+  /**
+   * Get a pointer from an event object.
+   * @param {Object} event - The target event object.
+   * @param {boolean} endOnly - Indicates if only returns the end point coordinate or not.
+   * @returns {Object} The result pointer contains start and/or end point coordinates.
+   */
+
+  function getPointer(_ref2, endOnly) {
+    var pageX = _ref2.pageX,
+        pageY = _ref2.pageY;
+    var end = {
+      endX: pageX,
+      endY: pageY
+    };
+    return endOnly ? end : _objectSpread2({
+      timeStamp: Date.now(),
+      startX: pageX,
+      startY: pageY
+    }, end);
+  }
+  /**
+   * Get the center point coordinate of a group of pointers.
+   * @param {Object} pointers - The target pointers.
+   * @returns {Object} The center point coordinate.
+   */
+
+  function getPointersCenter(pointers) {
+    var pageX = 0;
+    var pageY = 0;
+    var count = 0;
+    forEach(pointers, function (_ref3) {
+      var startX = _ref3.startX,
+          startY = _ref3.startY;
+      pageX += startX;
+      pageY += startY;
+      count += 1;
+    });
+    pageX /= count;
+    pageY /= count;
+    return {
+      pageX: pageX,
+      pageY: pageY
+    };
+  }
+
+  var render = {
+    render: function render() {
+      this.initContainer();
+      this.initViewer();
+      this.initList();
+      this.renderViewer();
+    },
+    initBody: function initBody() {
+      var ownerDocument = this.element.ownerDocument;
+      var body = ownerDocument.body || ownerDocument.documentElement;
+      this.body = body;
+      this.scrollbarWidth = window.innerWidth - ownerDocument.documentElement.clientWidth;
+      this.initialBodyPaddingRight = body.style.paddingRight;
+      this.initialBodyComputedPaddingRight = window.getComputedStyle(body).paddingRight;
+    },
+    initContainer: function initContainer() {
+      this.containerData = {
+        width: window.innerWidth,
+        height: window.innerHeight
+      };
+    },
+    initViewer: function initViewer() {
+      var options = this.options,
+          parent = this.parent;
+      var viewerData;
+
+      if (options.inline) {
+        viewerData = {
+          width: Math.max(parent.offsetWidth, options.minWidth),
+          height: Math.max(parent.offsetHeight, options.minHeight)
+        };
+        this.parentData = viewerData;
+      }
+
+      if (this.fulled || !viewerData) {
+        viewerData = this.containerData;
+      }
+
+      this.viewerData = assign({}, viewerData);
+    },
+    renderViewer: function renderViewer() {
+      if (this.options.inline && !this.fulled) {
+        setStyle(this.viewer, this.viewerData);
+      }
+    },
+    initList: function initList() {
+      var _this = this;
+
+      var element = this.element,
+          options = this.options,
+          list = this.list;
+      var items = []; // initList may be called in this.update, so should keep idempotent
+
+      list.innerHTML = '';
+      forEach(this.images, function (image, index) {
+        var src = image.src;
+        var alt = image.alt || getImageNameFromURL(src);
+
+        var url = _this.getImageURL(image);
+
+        if (src || url) {
+          var item = document.createElement('li');
+          var img = document.createElement('img');
+          forEach(options.inheritedAttributes, function (name) {
+            var value = image.getAttribute(name);
+
+            if (value !== null) {
+              img.setAttribute(name, value);
+            }
+          });
+          img.src = src || url;
+          img.alt = alt;
+          img.setAttribute('data-original-url', url || src);
+          item.setAttribute('data-index', index);
+          item.setAttribute('data-viewer-action', 'view');
+          item.setAttribute('role', 'button');
+
+          if (options.keyboard) {
+            item.setAttribute('tabindex', 0);
+          }
+
+          item.appendChild(img);
+          list.appendChild(item);
+          items.push(item);
+        }
+      });
+      this.items = items;
+      forEach(items, function (item) {
+        var image = item.firstElementChild;
+        var onLoad;
+        var onError;
+        setData(image, 'filled', true);
+
+        if (options.loading) {
+          addClass(item, CLASS_LOADING);
+        }
+
+        addListener(image, EVENT_LOAD, onLoad = function onLoad(event) {
+          removeListener(image, EVENT_ERROR, onError);
+
+          if (options.loading) {
+            removeClass(item, CLASS_LOADING);
+          }
+
+          _this.loadImage(event);
+        }, {
+          once: true
+        });
+        addListener(image, EVENT_ERROR, onError = function onError() {
+          removeListener(image, EVENT_LOAD, onLoad);
+
+          if (options.loading) {
+            removeClass(item, CLASS_LOADING);
+          }
+        }, {
+          once: true
+        });
+      });
+
+      if (options.transition) {
+        addListener(element, EVENT_VIEWED, function () {
+          addClass(list, CLASS_TRANSITION);
+        }, {
+          once: true
+        });
+      }
+    },
+    renderList: function renderList() {
+      var index = this.index;
+      var item = this.items[index];
+
+      if (!item) {
+        return;
+      }
+
+      var next = item.nextElementSibling;
+      var gutter = parseInt(window.getComputedStyle(next || item).marginLeft, 10);
+      var offsetWidth = item.offsetWidth;
+      var outerWidth = offsetWidth + gutter; // Place the active item in the center of the screen
+
+      setStyle(this.list, assign({
+        width: outerWidth * this.length - gutter
+      }, getTransforms({
+        translateX: (this.viewerData.width - offsetWidth) / 2 - outerWidth * index
+      })));
+    },
+    resetList: function resetList() {
+      var list = this.list;
+      list.innerHTML = '';
+      removeClass(list, CLASS_TRANSITION);
+      setStyle(list, getTransforms({
+        translateX: 0
+      }));
+    },
+    initImage: function initImage(done) {
+      var _this2 = this;
+
+      var options = this.options,
+          image = this.image,
+          viewerData = this.viewerData;
+      var footerHeight = this.footer.offsetHeight;
+      var viewerWidth = viewerData.width;
+      var viewerHeight = Math.max(viewerData.height - footerHeight, footerHeight);
+      var oldImageData = this.imageData || {};
+      var sizingImage;
+      this.imageInitializing = {
+        abort: function abort() {
+          sizingImage.onload = null;
+        }
+      };
+      sizingImage = getImageNaturalSizes(image, options, function (naturalWidth, naturalHeight) {
+        var aspectRatio = naturalWidth / naturalHeight;
+        var width = viewerWidth;
+        var height = viewerHeight;
+        _this2.imageInitializing = false;
+
+        if (viewerHeight * aspectRatio > viewerWidth) {
+          height = viewerWidth / aspectRatio;
+        } else {
+          width = viewerHeight * aspectRatio;
+        }
+
+        width = Math.min(width * 0.9, naturalWidth);
+        height = Math.min(height * 0.9, naturalHeight);
+        var left = (viewerWidth - width) / 2;
+        var top = (viewerHeight - height) / 2;
+        var imageData = {
+          left: left,
+          top: top,
+          x: left,
+          y: top,
+          width: width,
+          height: height,
+          oldRatio: 1,
+          ratio: width / naturalWidth,
+          aspectRatio: aspectRatio,
+          naturalWidth: naturalWidth,
+          naturalHeight: naturalHeight
+        };
+        var initialImageData = assign({}, imageData);
+
+        if (options.rotatable) {
+          imageData.rotate = oldImageData.rotate || 0;
+          initialImageData.rotate = 0;
+        }
+
+        if (options.scalable) {
+          imageData.scaleX = oldImageData.scaleX || 1;
+          imageData.scaleY = oldImageData.scaleY || 1;
+          initialImageData.scaleX = 1;
+          initialImageData.scaleY = 1;
+        }
+
+        _this2.imageData = imageData;
+        _this2.initialImageData = initialImageData;
+
+        if (done) {
+          done();
+        }
+      });
+    },
+    renderImage: function renderImage(done) {
+      var _this3 = this;
+
+      var image = this.image,
+          imageData = this.imageData;
+      setStyle(image, assign({
+        width: imageData.width,
+        height: imageData.height,
+        // XXX: Not to use translateX/Y to avoid image shaking when zooming
+        marginLeft: imageData.x,
+        marginTop: imageData.y
+      }, getTransforms(imageData)));
+
+      if (done) {
+        if ((this.viewing || this.moving || this.rotating || this.scaling || this.zooming) && this.options.transition && hasClass(image, CLASS_TRANSITION)) {
+          var onTransitionEnd = function onTransitionEnd() {
+            _this3.imageRendering = false;
+            done();
+          };
+
+          this.imageRendering = {
+            abort: function abort() {
+              removeListener(image, EVENT_TRANSITION_END, onTransitionEnd);
+            }
+          };
+          addListener(image, EVENT_TRANSITION_END, onTransitionEnd, {
+            once: true
+          });
+        } else {
+          done();
+        }
+      }
+    },
+    resetImage: function resetImage() {
+      // this.image only defined after viewed
+      if (this.viewing || this.viewed) {
+        var image = this.image;
+
+        if (this.viewing) {
+          this.viewing.abort();
+        }
+
+        image.parentNode.removeChild(image);
+        this.image = null;
+      }
+    }
+  };
+
+  var events = {
+    bind: function bind() {
+      var options = this.options,
+          viewer = this.viewer,
+          canvas = this.canvas;
+      var document = this.element.ownerDocument;
+      addListener(viewer, EVENT_CLICK, this.onClick = this.click.bind(this));
+      addListener(viewer, EVENT_DRAG_START, this.onDragStart = this.dragstart.bind(this));
+      addListener(canvas, EVENT_POINTER_DOWN, this.onPointerDown = this.pointerdown.bind(this));
+      addListener(document, EVENT_POINTER_MOVE, this.onPointerMove = this.pointermove.bind(this));
+      addListener(document, EVENT_POINTER_UP, this.onPointerUp = this.pointerup.bind(this));
+      addListener(document, EVENT_KEY_DOWN, this.onKeyDown = this.keydown.bind(this));
+      addListener(window, EVENT_RESIZE, this.onResize = this.resize.bind(this));
+
+      if (options.zoomable && options.zoomOnWheel) {
+        addListener(viewer, EVENT_WHEEL, this.onWheel = this.wheel.bind(this), {
+          passive: false,
+          capture: true
+        });
+      }
+
+      if (options.toggleOnDblclick) {
+        addListener(canvas, EVENT_DBLCLICK, this.onDblclick = this.dblclick.bind(this));
+      }
+    },
+    unbind: function unbind() {
+      var options = this.options,
+          viewer = this.viewer,
+          canvas = this.canvas;
+      var document = this.element.ownerDocument;
+      removeListener(viewer, EVENT_CLICK, this.onClick);
+      removeListener(viewer, EVENT_DRAG_START, this.onDragStart);
+      removeListener(canvas, EVENT_POINTER_DOWN, this.onPointerDown);
+      removeListener(document, EVENT_POINTER_MOVE, this.onPointerMove);
+      removeListener(document, EVENT_POINTER_UP, this.onPointerUp);
+      removeListener(document, EVENT_KEY_DOWN, this.onKeyDown);
+      removeListener(window, EVENT_RESIZE, this.onResize);
+
+      if (options.zoomable && options.zoomOnWheel) {
+        removeListener(viewer, EVENT_WHEEL, this.onWheel, {
+          passive: false,
+          capture: true
+        });
+      }
+
+      if (options.toggleOnDblclick) {
+        removeListener(canvas, EVENT_DBLCLICK, this.onDblclick);
+      }
+    }
+  };
+
+  var handlers = {
+    click: function click(event) {
+      var options = this.options,
+          imageData = this.imageData;
+      var target = event.target;
+      var action = getData(target, DATA_ACTION);
+
+      if (!action && target.localName === 'img' && target.parentElement.localName === 'li') {
+        target = target.parentElement;
+        action = getData(target, DATA_ACTION);
+      } // Cancel the emulated click when the native click event was triggered.
+
+
+      if (IS_TOUCH_DEVICE && event.isTrusted && target === this.canvas) {
+        clearTimeout(this.clickCanvasTimeout);
+      }
+
+      switch (action) {
+        case 'mix':
+          if (this.played) {
+            this.stop();
+          } else if (options.inline) {
+            if (this.fulled) {
+              this.exit();
+            } else {
+              this.full();
+            }
+          } else {
+            this.hide();
+          }
+
+          break;
+
+        case 'hide':
+          this.hide();
+          break;
+
+        case 'view':
+          this.view(getData(target, 'index'));
+          break;
+
+        case 'zoom-in':
+          this.zoom(0.1, true);
+          break;
+
+        case 'zoom-out':
+          this.zoom(-0.1, true);
+          break;
+
+        case 'one-to-one':
+          this.toggle();
+          break;
+
+        case 'reset':
+          this.reset();
+          break;
+
+        case 'prev':
+          this.prev(options.loop);
+          break;
+
+        case 'play':
+          this.play(options.fullscreen);
+          break;
+
+        case 'next':
+          this.next(options.loop);
+          break;
+
+        case 'rotate-left':
+          this.rotate(-90);
+          break;
+
+        case 'rotate-right':
+          this.rotate(90);
+          break;
+
+        case 'flip-horizontal':
+          this.scaleX(-imageData.scaleX || -1);
+          break;
+
+        case 'flip-vertical':
+          this.scaleY(-imageData.scaleY || -1);
+          break;
+
+        default:
+          if (this.played) {
+            this.stop();
+          }
+
+      }
+    },
+    dblclick: function dblclick(event) {
+      event.preventDefault();
+
+      if (this.viewed && event.target === this.image) {
+        // Cancel the emulated double click when the native dblclick event was triggered.
+        if (IS_TOUCH_DEVICE && event.isTrusted) {
+          clearTimeout(this.doubleClickImageTimeout);
+        } // XXX: No pageX/Y properties in custom event, fallback to the original event.
+
+
+        this.toggle(event.isTrusted ? event : event.detail && event.detail.originalEvent);
+      }
+    },
+    load: function load() {
+      var _this = this;
+
+      if (this.timeout) {
+        clearTimeout(this.timeout);
+        this.timeout = false;
+      }
+
+      var element = this.element,
+          options = this.options,
+          image = this.image,
+          index = this.index,
+          viewerData = this.viewerData;
+      removeClass(image, CLASS_INVISIBLE);
+
+      if (options.loading) {
+        removeClass(this.canvas, CLASS_LOADING);
+      }
+
+      image.style.cssText = 'height:0;' + "margin-left:".concat(viewerData.width / 2, "px;") + "margin-top:".concat(viewerData.height / 2, "px;") + 'max-width:none!important;' + 'position:relative;' + 'width:0;';
+      this.initImage(function () {
+        toggleClass(image, CLASS_MOVE, options.movable);
+        toggleClass(image, CLASS_TRANSITION, options.transition);
+
+        _this.renderImage(function () {
+          _this.viewed = true;
+          _this.viewing = false;
+
+          if (isFunction(options.viewed)) {
+            addListener(element, EVENT_VIEWED, options.viewed, {
+              once: true
+            });
+          }
+
+          dispatchEvent(element, EVENT_VIEWED, {
+            originalImage: _this.images[index],
+            index: index,
+            image: image
+          }, {
+            cancelable: false
+          });
+        });
+      });
+    },
+    loadImage: function loadImage(event) {
+      var image = event.target;
+      var parent = image.parentNode;
+      var parentWidth = parent.offsetWidth || 30;
+      var parentHeight = parent.offsetHeight || 50;
+      var filled = !!getData(image, 'filled');
+      getImageNaturalSizes(image, this.options, function (naturalWidth, naturalHeight) {
+        var aspectRatio = naturalWidth / naturalHeight;
+        var width = parentWidth;
+        var height = parentHeight;
+
+        if (parentHeight * aspectRatio > parentWidth) {
+          if (filled) {
+            width = parentHeight * aspectRatio;
+          } else {
+            height = parentWidth / aspectRatio;
+          }
+        } else if (filled) {
+          height = parentWidth / aspectRatio;
+        } else {
+          width = parentHeight * aspectRatio;
+        }
+
+        setStyle(image, assign({
+          width: width,
+          height: height
+        }, getTransforms({
+          translateX: (parentWidth - width) / 2,
+          translateY: (parentHeight - height) / 2
+        })));
+      });
+    },
+    keydown: function keydown(event) {
+      var options = this.options;
+
+      if (!options.keyboard) {
+        return;
+      }
+
+      var keyCode = event.keyCode || event.which || event.charCode;
+
+      switch (keyCode) {
+        // Enter
+        case 13:
+          if (this.viewer.contains(event.target)) {
+            this.click(event);
+          }
+
+          break;
+      }
+
+      if (!this.fulled) {
+        return;
+      }
+
+      switch (keyCode) {
+        // Escape
+        case 27:
+          if (this.played) {
+            this.stop();
+          } else if (options.inline) {
+            if (this.fulled) {
+              this.exit();
+            }
+          } else {
+            this.hide();
+          }
+
+          break;
+        // Space
+
+        case 32:
+          if (this.played) {
+            this.stop();
+          }
+
+          break;
+        // ArrowLeft
+
+        case 37:
+          this.prev(options.loop);
+          break;
+        // ArrowUp
+
+        case 38:
+          // Prevent scroll on Firefox
+          event.preventDefault(); // Zoom in
+
+          this.zoom(options.zoomRatio, true);
+          break;
+        // ArrowRight
+
+        case 39:
+          this.next(options.loop);
+          break;
+        // ArrowDown
+
+        case 40:
+          // Prevent scroll on Firefox
+          event.preventDefault(); // Zoom out
+
+          this.zoom(-options.zoomRatio, true);
+          break;
+        // Ctrl + 0
+
+        case 48: // Fall through
+        // Ctrl + 1
+        // eslint-disable-next-line no-fallthrough
+
+        case 49:
+          if (event.ctrlKey) {
+            event.preventDefault();
+            this.toggle();
+          }
+
+          break;
+      }
+    },
+    dragstart: function dragstart(event) {
+      if (event.target.localName === 'img') {
+        event.preventDefault();
+      }
+    },
+    pointerdown: function pointerdown(event) {
+      var options = this.options,
+          pointers = this.pointers;
+      var buttons = event.buttons,
+          button = event.button;
+
+      if (!this.viewed || this.showing || this.viewing || this.hiding // Handle mouse event and pointer event and ignore touch event
+      || (event.type === 'mousedown' || event.type === 'pointerdown' && event.pointerType === 'mouse') && ( // No primary button (Usually the left button)
+      isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 // Open context menu
+      || event.ctrlKey)) {
+        return;
+      } // Prevent default behaviours as page zooming in touch devices.
+
+
+      event.preventDefault();
+
+      if (event.changedTouches) {
+        forEach(event.changedTouches, function (touch) {
+          pointers[touch.identifier] = getPointer(touch);
+        });
+      } else {
+        pointers[event.pointerId || 0] = getPointer(event);
+      }
+
+      var action = options.movable ? ACTION_MOVE : false;
+
+      if (options.zoomOnTouch && options.zoomable && Object.keys(pointers).length > 1) {
+        action = ACTION_ZOOM;
+      } else if (options.slideOnTouch && (event.pointerType === 'touch' || event.type === 'touchstart') && this.isSwitchable()) {
+        action = ACTION_SWITCH;
+      }
+
+      if (options.transition && (action === ACTION_MOVE || action === ACTION_ZOOM)) {
+        removeClass(this.image, CLASS_TRANSITION);
+      }
+
+      this.action = action;
+    },
+    pointermove: function pointermove(event) {
+      var pointers = this.pointers,
+          action = this.action;
+
+      if (!this.viewed || !action) {
+        return;
+      }
+
+      event.preventDefault();
+
+      if (event.changedTouches) {
+        forEach(event.changedTouches, function (touch) {
+          assign(pointers[touch.identifier] || {}, getPointer(touch, true));
+        });
+      } else {
+        assign(pointers[event.pointerId || 0] || {}, getPointer(event, true));
+      }
+
+      this.change(event);
+    },
+    pointerup: function pointerup(event) {
+      var _this2 = this;
+
+      var options = this.options,
+          action = this.action,
+          pointers = this.pointers;
+      var pointer;
+
+      if (event.changedTouches) {
+        forEach(event.changedTouches, function (touch) {
+          pointer = pointers[touch.identifier];
+          delete pointers[touch.identifier];
+        });
+      } else {
+        pointer = pointers[event.pointerId || 0];
+        delete pointers[event.pointerId || 0];
+      }
+
+      if (!action) {
+        return;
+      }
+
+      event.preventDefault();
+
+      if (options.transition && (action === ACTION_MOVE || action === ACTION_ZOOM)) {
+        addClass(this.image, CLASS_TRANSITION);
+      }
+
+      this.action = false; // Emulate click and double click in touch devices to support backdrop and image zooming (#210).
+
+      if (IS_TOUCH_DEVICE && action !== ACTION_ZOOM && pointer && Date.now() - pointer.timeStamp < 500) {
+        clearTimeout(this.clickCanvasTimeout);
+        clearTimeout(this.doubleClickImageTimeout);
+
+        if (options.toggleOnDblclick && this.viewed && event.target === this.image) {
+          if (this.imageClicked) {
+            this.imageClicked = false; // This timeout will be cleared later when a native dblclick event is triggering
+
+            this.doubleClickImageTimeout = setTimeout(function () {
+              dispatchEvent(_this2.image, EVENT_DBLCLICK, {
+                originalEvent: event
+              });
+            }, 50);
+          } else {
+            this.imageClicked = true; // The default timing of a double click in Windows is 500 ms
+
+            this.doubleClickImageTimeout = setTimeout(function () {
+              _this2.imageClicked = false;
+            }, 500);
+          }
+        } else {
+          this.imageClicked = false;
+
+          if (options.backdrop && options.backdrop !== 'static' && event.target === this.canvas) {
+            // This timeout will be cleared later when a native click event is triggering
+            this.clickCanvasTimeout = setTimeout(function () {
+              dispatchEvent(_this2.canvas, EVENT_CLICK, {
+                originalEvent: event
+              });
+            }, 50);
+          }
+        }
+      }
+    },
+    resize: function resize() {
+      var _this3 = this;
+
+      if (!this.isShown || this.hiding) {
+        return;
+      }
+
+      if (this.fulled) {
+        this.close();
+        this.initBody();
+        this.open();
+      }
+
+      this.initContainer();
+      this.initViewer();
+      this.renderViewer();
+      this.renderList();
+
+      if (this.viewed) {
+        this.initImage(function () {
+          _this3.renderImage();
+        });
+      }
+
+      if (this.played) {
+        if (this.options.fullscreen && this.fulled && !(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
+          this.stop();
+          return;
+        }
+
+        forEach(this.player.getElementsByTagName('img'), function (image) {
+          addListener(image, EVENT_LOAD, _this3.loadImage.bind(_this3), {
+            once: true
+          });
+          dispatchEvent(image, EVENT_LOAD);
+        });
+      }
+    },
+    wheel: function wheel(event) {
+      var _this4 = this;
+
+      if (!this.viewed) {
+        return;
+      }
+
+      event.preventDefault(); // Limit wheel speed to prevent zoom too fast
+
+      if (this.wheeling) {
+        return;
+      }
+
+      this.wheeling = true;
+      setTimeout(function () {
+        _this4.wheeling = false;
+      }, 50);
+      var ratio = Number(this.options.zoomRatio) || 0.1;
+      var delta = 1;
+
+      if (event.deltaY) {
+        delta = event.deltaY > 0 ? 1 : -1;
+      } else if (event.wheelDelta) {
+        delta = -event.wheelDelta / 120;
+      } else if (event.detail) {
+        delta = event.detail > 0 ? 1 : -1;
+      }
+
+      this.zoom(-delta * ratio, true, event);
+    }
+  };
+
+  var methods = {
+    /** Show the viewer (only available in modal mode)
+     * @param {boolean} [immediate=false] - Indicates if show the viewer immediately or not.
+     * @returns {Viewer} this
+     */
+    show: function show() {
+      var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
+      var element = this.element,
+          options = this.options;
+
+      if (options.inline || this.showing || this.isShown || this.showing) {
+        return this;
+      }
+
+      if (!this.ready) {
+        this.build();
+
+        if (this.ready) {
+          this.show(immediate);
+        }
+
+        return this;
+      }
+
+      if (isFunction(options.show)) {
+        addListener(element, EVENT_SHOW, options.show, {
+          once: true
+        });
+      }
+
+      if (dispatchEvent(element, EVENT_SHOW) === false || !this.ready) {
+        return this;
+      }
+
+      if (this.hiding) {
+        this.transitioning.abort();
+      }
+
+      this.showing = true;
+      this.open();
+      var viewer = this.viewer;
+      removeClass(viewer, CLASS_HIDE);
+      viewer.setAttribute('role', 'dialog');
+      viewer.setAttribute('aria-labelledby', this.title.id);
+      viewer.setAttribute('aria-modal', true);
+      viewer.removeAttribute('aria-hidden');
+
+      if (options.transition && !immediate) {
+        var shown = this.shown.bind(this);
+        this.transitioning = {
+          abort: function abort() {
+            removeListener(viewer, EVENT_TRANSITION_END, shown);
+            removeClass(viewer, CLASS_IN);
+          }
+        };
+        addClass(viewer, CLASS_TRANSITION); // Force reflow to enable CSS3 transition
+
+        viewer.initialOffsetWidth = viewer.offsetWidth;
+        addListener(viewer, EVENT_TRANSITION_END, shown, {
+          once: true
+        });
+        addClass(viewer, CLASS_IN);
+      } else {
+        addClass(viewer, CLASS_IN);
+        this.shown();
+      }
+
+      return this;
+    },
+
+    /**
+     * Hide the viewer (only available in modal mode)
+     * @param {boolean} [immediate=false] - Indicates if hide the viewer immediately or not.
+     * @returns {Viewer} this
+     */
+    hide: function hide() {
+      var _this = this;
+
+      var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
+      var element = this.element,
+          options = this.options;
+
+      if (options.inline || this.hiding || !(this.isShown || this.showing)) {
+        return this;
+      }
+
+      if (isFunction(options.hide)) {
+        addListener(element, EVENT_HIDE, options.hide, {
+          once: true
+        });
+      }
+
+      if (dispatchEvent(element, EVENT_HIDE) === false) {
+        return this;
+      }
+
+      if (this.showing) {
+        this.transitioning.abort();
+      }
+
+      this.hiding = true;
+
+      if (this.played) {
+        this.stop();
+      } else if (this.viewing) {
+        this.viewing.abort();
+      }
+
+      var viewer = this.viewer,
+          image = this.image;
+
+      var hideImmediately = function hideImmediately() {
+        removeClass(viewer, CLASS_IN);
+
+        _this.hidden();
+      };
+
+      if (options.transition && !immediate) {
+        var onViewerTransitionEnd = function onViewerTransitionEnd(event) {
+          // Ignore all propagating `transitionend` events (#275).
+          if (event && event.target === viewer) {
+            removeListener(viewer, EVENT_TRANSITION_END, onViewerTransitionEnd);
+
+            _this.hidden();
+          }
+        };
+
+        var onImageTransitionEnd = function onImageTransitionEnd() {
+          // In case of show the viewer by `viewer.show(true)` previously (#407).
+          if (hasClass(viewer, CLASS_TRANSITION)) {
+            addListener(viewer, EVENT_TRANSITION_END, onViewerTransitionEnd);
+            removeClass(viewer, CLASS_IN);
+          } else {
+            hideImmediately();
+          }
+        };
+
+        this.transitioning = {
+          abort: function abort() {
+            if (_this.viewed && hasClass(image, CLASS_TRANSITION)) {
+              removeListener(image, EVENT_TRANSITION_END, onImageTransitionEnd);
+            } else if (hasClass(viewer, CLASS_TRANSITION)) {
+              removeListener(viewer, EVENT_TRANSITION_END, onViewerTransitionEnd);
+            }
+          }
+        }; // In case of hiding the viewer when holding on the image (#255),
+        // note that the `CLASS_TRANSITION` class will be removed on pointer down.
+
+        if (this.viewed && hasClass(image, CLASS_TRANSITION)) {
+          addListener(image, EVENT_TRANSITION_END, onImageTransitionEnd, {
+            once: true
+          });
+          this.zoomTo(0, false, null, true);
+        } else {
+          onImageTransitionEnd();
+        }
+      } else {
+        hideImmediately();
+      }
+
+      return this;
+    },
+
+    /**
+     * View one of the images with image's index
+     * @param {number} index - The index of the image to view.
+     * @returns {Viewer} this
+     */
+    view: function view() {
+      var _this2 = this;
+
+      var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.initialViewIndex;
+      index = Number(index) || 0;
+
+      if (this.hiding || this.played || index < 0 || index >= this.length || this.viewed && index === this.index) {
+        return this;
+      }
+
+      if (!this.isShown) {
+        this.index = index;
+        return this.show();
+      }
+
+      if (this.viewing) {
+        this.viewing.abort();
+      }
+
+      var element = this.element,
+          options = this.options,
+          title = this.title,
+          canvas = this.canvas;
+      var item = this.items[index];
+      var img = item.querySelector('img');
+      var url = getData(img, 'originalUrl');
+      var alt = img.getAttribute('alt');
+      var image = document.createElement('img');
+      forEach(options.inheritedAttributes, function (name) {
+        var value = img.getAttribute(name);
+
+        if (value !== null) {
+          image.setAttribute(name, value);
+        }
+      });
+      image.src = url;
+      image.alt = alt;
+
+      if (isFunction(options.view)) {
+        addListener(element, EVENT_VIEW, options.view, {
+          once: true
+        });
+      }
+
+      if (dispatchEvent(element, EVENT_VIEW, {
+        originalImage: this.images[index],
+        index: index,
+        image: image
+      }) === false || !this.isShown || this.hiding || this.played) {
+        return this;
+      }
+
+      var activeItem = this.items[this.index];
+
+      if (activeItem) {
+        removeClass(activeItem, CLASS_ACTIVE);
+        activeItem.removeAttribute('aria-selected');
+      }
+
+      addClass(item, CLASS_ACTIVE);
+      item.setAttribute('aria-selected', true);
+
+      if (options.focus) {
+        item.focus();
+      }
+
+      this.image = image;
+      this.viewed = false;
+      this.index = index;
+      this.imageData = {};
+      addClass(image, CLASS_INVISIBLE);
+
+      if (options.loading) {
+        addClass(canvas, CLASS_LOADING);
+      }
+
+      canvas.innerHTML = '';
+      canvas.appendChild(image); // Center current item
+
+      this.renderList(); // Clear title
+
+      title.innerHTML = ''; // Generate title after viewed
+
+      var onViewed = function onViewed() {
+        var imageData = _this2.imageData;
+        var render = Array.isArray(options.title) ? options.title[1] : options.title;
+        title.innerHTML = escapeHTMLEntities(isFunction(render) ? render.call(_this2, image, imageData) : "".concat(alt, " (").concat(imageData.naturalWidth, " \xD7 ").concat(imageData.naturalHeight, ")"));
+      };
+
+      var onLoad;
+      var onError;
+      addListener(element, EVENT_VIEWED, onViewed, {
+        once: true
+      });
+      this.viewing = {
+        abort: function abort() {
+          removeListener(element, EVENT_VIEWED, onViewed);
+
+          if (image.complete) {
+            if (_this2.imageRendering) {
+              _this2.imageRendering.abort();
+            } else if (_this2.imageInitializing) {
+              _this2.imageInitializing.abort();
+            }
+          } else {
+            // Cancel download to save bandwidth.
+            image.src = '';
+            removeListener(image, EVENT_LOAD, onLoad);
+
+            if (_this2.timeout) {
+              clearTimeout(_this2.timeout);
+            }
+          }
+        }
+      };
+
+      if (image.complete) {
+        this.load();
+      } else {
+        addListener(image, EVENT_LOAD, onLoad = function onLoad() {
+          removeListener(image, EVENT_ERROR, onError);
+
+          _this2.load();
+        }, {
+          once: true
+        });
+        addListener(image, EVENT_ERROR, onError = function onError() {
+          removeListener(image, EVENT_LOAD, onLoad);
+
+          if (_this2.timeout) {
+            clearTimeout(_this2.timeout);
+            _this2.timeout = false;
+          }
+
+          removeClass(image, CLASS_INVISIBLE);
+
+          if (options.loading) {
+            removeClass(_this2.canvas, CLASS_LOADING);
+          }
+        }, {
+          once: true
+        });
+
+        if (this.timeout) {
+          clearTimeout(this.timeout);
+        } // Make the image visible if it fails to load within 1s
+
+
+        this.timeout = setTimeout(function () {
+          removeClass(image, CLASS_INVISIBLE);
+          _this2.timeout = false;
+        }, 1000);
+      }
+
+      return this;
+    },
+
+    /**
+     * View the previous image
+     * @param {boolean} [loop=false] - Indicate if view the last one
+     * when it is the first one at present.
+     * @returns {Viewer} this
+     */
+    prev: function prev() {
+      var loop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
+      var index = this.index - 1;
+
+      if (index < 0) {
+        index = loop ? this.length - 1 : 0;
+      }
+
+      this.view(index);
+      return this;
+    },
+
+    /**
+     * View the next image
+     * @param {boolean} [loop=false] - Indicate if view the first one
+     * when it is the last one at present.
+     * @returns {Viewer} this
+     */
+    next: function next() {
+      var loop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
+      var maxIndex = this.length - 1;
+      var index = this.index + 1;
+
+      if (index > maxIndex) {
+        index = loop ? 0 : maxIndex;
+      }
+
+      this.view(index);
+      return this;
+    },
+
+    /**
+     * Move the image with relative offsets.
+     * @param {number} x - The moving distance in the horizontal direction.
+     * @param {number} [y=x] The moving distance in the vertical direction.
+     * @returns {Viewer} this
+     */
+    move: function move(x) {
+      var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
+      var imageData = this.imageData;
+      this.moveTo(isUndefined(x) ? x : imageData.x + Number(x), isUndefined(y) ? y : imageData.y + Number(y));
+      return this;
+    },
+
+    /**
+     * Move the image to an absolute point.
+     * @param {number} x - The new position in the horizontal direction.
+     * @param {number} [y=x] - The new position in the vertical direction.
+     * @param {Event} [_originalEvent=null] - The original event if any.
+     * @returns {Viewer} this
+     */
+    moveTo: function moveTo(x) {
+      var _this3 = this;
+
+      var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
+
+      var _originalEvent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
+
+      var element = this.element,
+          options = this.options,
+          imageData = this.imageData;
+      x = Number(x);
+      y = Number(y);
+
+      if (this.viewed && !this.played && options.movable) {
+        var oldX = imageData.x;
+        var oldY = imageData.y;
+        var changed = false;
+
+        if (isNumber(x)) {
+          changed = true;
+        } else {
+          x = oldX;
+        }
+
+        if (isNumber(y)) {
+          changed = true;
+        } else {
+          y = oldY;
+        }
+
+        if (changed) {
+          if (isFunction(options.move)) {
+            addListener(element, EVENT_MOVE, options.move, {
+              once: true
+            });
+          }
+
+          if (dispatchEvent(element, EVENT_MOVE, {
+            x: x,
+            y: y,
+            oldX: oldX,
+            oldY: oldY,
+            originalEvent: _originalEvent
+          }) === false) {
+            return this;
+          }
+
+          imageData.x = x;
+          imageData.y = y;
+          imageData.left = x;
+          imageData.top = y;
+          this.moving = true;
+          this.renderImage(function () {
+            _this3.moving = false;
+
+            if (isFunction(options.moved)) {
+              addListener(element, EVENT_MOVED, options.moved, {
+                once: true
+              });
+            }
+
+            dispatchEvent(element, EVENT_MOVED, {
+              x: x,
+              y: y,
+              oldX: oldX,
+              oldY: oldY,
+              originalEvent: _originalEvent
+            }, {
+              cancelable: false
+            });
+          });
+        }
+      }
+
+      return this;
+    },
+
+    /**
+     * Rotate the image with a relative degree.
+     * @param {number} degree - The rotate degree.
+     * @returns {Viewer} this
+     */
+    rotate: function rotate(degree) {
+      this.rotateTo((this.imageData.rotate || 0) + Number(degree));
+      return this;
+    },
+
+    /**
+     * Rotate the image to an absolute degree.
+     * @param {number} degree - The rotate degree.
+     * @returns {Viewer} this
+     */
+    rotateTo: function rotateTo(degree) {
+      var _this4 = this;
+
+      var element = this.element,
+          options = this.options,
+          imageData = this.imageData;
+      degree = Number(degree);
+
+      if (isNumber(degree) && this.viewed && !this.played && options.rotatable) {
+        var oldDegree = imageData.rotate;
+
+        if (isFunction(options.rotate)) {
+          addListener(element, EVENT_ROTATE, options.rotate, {
+            once: true
+          });
+        }
+
+        if (dispatchEvent(element, EVENT_ROTATE, {
+          degree: degree,
+          oldDegree: oldDegree
+        }) === false) {
+          return this;
+        }
+
+        imageData.rotate = degree;
+        this.rotating = true;
+        this.renderImage(function () {
+          _this4.rotating = false;
+
+          if (isFunction(options.rotated)) {
+            addListener(element, EVENT_ROTATED, options.rotated, {
+              once: true
+            });
+          }
+
+          dispatchEvent(element, EVENT_ROTATED, {
+            degree: degree,
+            oldDegree: oldDegree
+          }, {
+            cancelable: false
+          });
+        });
+      }
+
+      return this;
+    },
+
+    /**
+     * Scale the image on the x-axis.
+     * @param {number} scaleX - The scale ratio on the x-axis.
+     * @returns {Viewer} this
+     */
+    scaleX: function scaleX(_scaleX) {
+      this.scale(_scaleX, this.imageData.scaleY);
+      return this;
+    },
+
+    /**
+     * Scale the image on the y-axis.
+     * @param {number} scaleY - The scale ratio on the y-axis.
+     * @returns {Viewer} this
+     */
+    scaleY: function scaleY(_scaleY) {
+      this.scale(this.imageData.scaleX, _scaleY);
+      return this;
+    },
+
+    /**
+     * Scale the image.
+     * @param {number} scaleX - The scale ratio on the x-axis.
+     * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis.
+     * @returns {Viewer} this
+     */
+    scale: function scale(scaleX) {
+      var _this5 = this;
+
+      var scaleY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scaleX;
+      var element = this.element,
+          options = this.options,
+          imageData = this.imageData;
+      scaleX = Number(scaleX);
+      scaleY = Number(scaleY);
+
+      if (this.viewed && !this.played && options.scalable) {
+        var oldScaleX = imageData.scaleX;
+        var oldScaleY = imageData.scaleY;
+        var changed = false;
+
+        if (isNumber(scaleX)) {
+          changed = true;
+        } else {
+          scaleX = oldScaleX;
+        }
+
+        if (isNumber(scaleY)) {
+          changed = true;
+        } else {
+          scaleY = oldScaleY;
+        }
+
+        if (changed) {
+          if (isFunction(options.scale)) {
+            addListener(element, EVENT_SCALE, options.scale, {
+              once: true
+            });
+          }
+
+          if (dispatchEvent(element, EVENT_SCALE, {
+            scaleX: scaleX,
+            scaleY: scaleY,
+            oldScaleX: oldScaleX,
+            oldScaleY: oldScaleY
+          }) === false) {
+            return this;
+          }
+
+          imageData.scaleX = scaleX;
+          imageData.scaleY = scaleY;
+          this.scaling = true;
+          this.renderImage(function () {
+            _this5.scaling = false;
+
+            if (isFunction(options.scaled)) {
+              addListener(element, EVENT_SCALED, options.scaled, {
+                once: true
+              });
+            }
+
+            dispatchEvent(element, EVENT_SCALED, {
+              scaleX: scaleX,
+              scaleY: scaleY,
+              oldScaleX: oldScaleX,
+              oldScaleY: oldScaleY
+            }, {
+              cancelable: false
+            });
+          });
+        }
+      }
+
+      return this;
+    },
+
+    /**
+     * Zoom the image with a relative ratio.
+     * @param {number} ratio - The target ratio.
+     * @param {boolean} [hasTooltip=false] - Indicates if it has a tooltip or not.
+     * @param {Event} [_originalEvent=null] - The original event if any.
+     * @returns {Viewer} this
+     */
+    zoom: function zoom(ratio) {
+      var hasTooltip = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+
+      var _originalEvent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
+
+      var imageData = this.imageData;
+      ratio = Number(ratio);
+
+      if (ratio < 0) {
+        ratio = 1 / (1 - ratio);
+      } else {
+        ratio = 1 + ratio;
+      }
+
+      this.zoomTo(imageData.width * ratio / imageData.naturalWidth, hasTooltip, _originalEvent);
+      return this;
+    },
+
+    /**
+     * Zoom the image to an absolute ratio.
+     * @param {number} ratio - The target ratio.
+     * @param {boolean} [hasTooltip=false] - Indicates if it has a tooltip or not.
+     * @param {Event} [_originalEvent=null] - The original event if any.
+     * @param {Event} [_zoomable=false] - Indicates if the current zoom is available or not.
+     * @returns {Viewer} this
+     */
+    zoomTo: function zoomTo(ratio) {
+      var _this6 = this;
+
+      var hasTooltip = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+
+      var _originalEvent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
+
+      var _zoomable = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
+
+      var element = this.element,
+          options = this.options,
+          pointers = this.pointers,
+          imageData = this.imageData;
+      var x = imageData.x,
+          y = imageData.y,
+          width = imageData.width,
+          height = imageData.height,
+          naturalWidth = imageData.naturalWidth,
+          naturalHeight = imageData.naturalHeight;
+      ratio = Math.max(0, ratio);
+
+      if (isNumber(ratio) && this.viewed && !this.played && (_zoomable || options.zoomable)) {
+        if (!_zoomable) {
+          var minZoomRatio = Math.max(0.01, options.minZoomRatio);
+          var maxZoomRatio = Math.min(100, options.maxZoomRatio);
+          ratio = Math.min(Math.max(ratio, minZoomRatio), maxZoomRatio);
+        }
+
+        if (_originalEvent) {
+          switch (_originalEvent.type) {
+            case 'wheel':
+              if (options.zoomRatio >= 0.055 && ratio > 0.95 && ratio < 1.05) {
+                ratio = 1;
+              }
+
+              break;
+
+            case 'pointermove':
+            case 'touchmove':
+            case 'mousemove':
+              if (ratio > 0.99 && ratio < 1.01) {
+                ratio = 1;
+              }
+
+              break;
+          }
+        }
+
+        var newWidth = naturalWidth * ratio;
+        var newHeight = naturalHeight * ratio;
+        var offsetWidth = newWidth - width;
+        var offsetHeight = newHeight - height;
+        var oldRatio = imageData.ratio;
+
+        if (isFunction(options.zoom)) {
+          addListener(element, EVENT_ZOOM, options.zoom, {
+            once: true
+          });
+        }
+
+        if (dispatchEvent(element, EVENT_ZOOM, {
+          ratio: ratio,
+          oldRatio: oldRatio,
+          originalEvent: _originalEvent
+        }) === false) {
+          return this;
+        }
+
+        this.zooming = true;
+
+        if (_originalEvent) {
+          var offset = getOffset(this.viewer);
+          var center = pointers && Object.keys(pointers).length > 0 ? getPointersCenter(pointers) : {
+            pageX: _originalEvent.pageX,
+            pageY: _originalEvent.pageY
+          }; // Zoom from the triggering point of the event
+
+          imageData.x -= offsetWidth * ((center.pageX - offset.left - x) / width);
+          imageData.y -= offsetHeight * ((center.pageY - offset.top - y) / height);
+        } else {
+          // Zoom from the center of the image
+          imageData.x -= offsetWidth / 2;
+          imageData.y -= offsetHeight / 2;
+        }
+
+        imageData.left = imageData.x;
+        imageData.top = imageData.y;
+        imageData.width = newWidth;
+        imageData.height = newHeight;
+        imageData.oldRatio = oldRatio;
+        imageData.ratio = ratio;
+        this.renderImage(function () {
+          _this6.zooming = false;
+
+          if (isFunction(options.zoomed)) {
+            addListener(element, EVENT_ZOOMED, options.zoomed, {
+              once: true
+            });
+          }
+
+          dispatchEvent(element, EVENT_ZOOMED, {
+            ratio: ratio,
+            oldRatio: oldRatio,
+            originalEvent: _originalEvent
+          }, {
+            cancelable: false
+          });
+        });
+
+        if (hasTooltip) {
+          this.tooltip();
+        }
+      }
+
+      return this;
+    },
+
+    /**
+     * Play the images
+     * @param {boolean|FullscreenOptions} [fullscreen=false] - Indicate if request fullscreen or not.
+     * @returns {Viewer} this
+     */
+    play: function play() {
+      var _this7 = this;
+
+      var fullscreen = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
+
+      if (!this.isShown || this.played) {
+        return this;
+      }
+
+      var element = this.element,
+          options = this.options;
+
+      if (isFunction(options.play)) {
+        addListener(element, EVENT_PLAY, options.play, {
+          once: true
+        });
+      }
+
+      if (dispatchEvent(element, EVENT_PLAY) === false) {
+        return this;
+      }
+
+      var player = this.player;
+      var onLoad = this.loadImage.bind(this);
+      var list = [];
+      var total = 0;
+      var index = 0;
+      this.played = true;
+      this.onLoadWhenPlay = onLoad;
+
+      if (fullscreen) {
+        this.requestFullscreen(fullscreen);
+      }
+
+      addClass(player, CLASS_SHOW);
+      forEach(this.items, function (item, i) {
+        var img = item.querySelector('img');
+        var image = document.createElement('img');
+        image.src = getData(img, 'originalUrl');
+        image.alt = img.getAttribute('alt');
+        image.referrerPolicy = img.referrerPolicy;
+        total += 1;
+        addClass(image, CLASS_FADE);
+        toggleClass(image, CLASS_TRANSITION, options.transition);
+
+        if (hasClass(item, CLASS_ACTIVE)) {
+          addClass(image, CLASS_IN);
+          index = i;
+        }
+
+        list.push(image);
+        addListener(image, EVENT_LOAD, onLoad, {
+          once: true
+        });
+        player.appendChild(image);
+      });
+
+      if (isNumber(options.interval) && options.interval > 0) {
+        var play = function play() {
+          _this7.playing = setTimeout(function () {
+            removeClass(list[index], CLASS_IN);
+            index += 1;
+            index = index < total ? index : 0;
+            addClass(list[index], CLASS_IN);
+            play();
+          }, options.interval);
+        };
+
+        if (total > 1) {
+          play();
+        }
+      }
+
+      return this;
+    },
+    // Stop play
+    stop: function stop() {
+      var _this8 = this;
+
+      if (!this.played) {
+        return this;
+      }
+
+      var element = this.element,
+          options = this.options;
+
+      if (isFunction(options.stop)) {
+        addListener(element, EVENT_STOP, options.stop, {
+          once: true
+        });
+      }
+
+      if (dispatchEvent(element, EVENT_STOP) === false) {
+        return this;
+      }
+
+      var player = this.player;
+      this.played = false;
+      clearTimeout(this.playing);
+      forEach(player.getElementsByTagName('img'), function (image) {
+        removeListener(image, EVENT_LOAD, _this8.onLoadWhenPlay);
+      });
+      removeClass(player, CLASS_SHOW);
+      player.innerHTML = '';
+      this.exitFullscreen();
+      return this;
+    },
+    // Enter modal mode (only available in inline mode)
+    full: function full() {
+      var _this9 = this;
+
+      var options = this.options,
+          viewer = this.viewer,
+          image = this.image,
+          list = this.list;
+
+      if (!this.isShown || this.played || this.fulled || !options.inline) {
+        return this;
+      }
+
+      this.fulled = true;
+      this.open();
+      addClass(this.button, CLASS_FULLSCREEN_EXIT);
+
+      if (options.transition) {
+        removeClass(list, CLASS_TRANSITION);
+
+        if (this.viewed) {
+          removeClass(image, CLASS_TRANSITION);
+        }
+      }
+
+      addClass(viewer, CLASS_FIXED);
+      viewer.setAttribute('role', 'dialog');
+      viewer.setAttribute('aria-labelledby', this.title.id);
+      viewer.setAttribute('aria-modal', true);
+      viewer.removeAttribute('style');
+      setStyle(viewer, {
+        zIndex: options.zIndex
+      });
+
+      if (options.focus) {
+        this.enforceFocus();
+      }
+
+      this.initContainer();
+      this.viewerData = assign({}, this.containerData);
+      this.renderList();
+
+      if (this.viewed) {
+        this.initImage(function () {
+          _this9.renderImage(function () {
+            if (options.transition) {
+              setTimeout(function () {
+                addClass(image, CLASS_TRANSITION);
+                addClass(list, CLASS_TRANSITION);
+              }, 0);
+            }
+          });
+        });
+      }
+
+      return this;
+    },
+    // Exit modal mode (only available in inline mode)
+    exit: function exit() {
+      var _this10 = this;
+
+      var options = this.options,
+          viewer = this.viewer,
+          image = this.image,
+          list = this.list;
+
+      if (!this.isShown || this.played || !this.fulled || !options.inline) {
+        return this;
+      }
+
+      this.fulled = false;
+      this.close();
+      removeClass(this.button, CLASS_FULLSCREEN_EXIT);
+
+      if (options.transition) {
+        removeClass(list, CLASS_TRANSITION);
+
+        if (this.viewed) {
+          removeClass(image, CLASS_TRANSITION);
+        }
+      }
+
+      if (options.focus) {
+        this.clearEnforceFocus();
+      }
+
+      viewer.removeAttribute('role');
+      viewer.removeAttribute('aria-labelledby');
+      viewer.removeAttribute('aria-modal');
+      removeClass(viewer, CLASS_FIXED);
+      setStyle(viewer, {
+        zIndex: options.zIndexInline
+      });
+      this.viewerData = assign({}, this.parentData);
+      this.renderViewer();
+      this.renderList();
+
+      if (this.viewed) {
+        this.initImage(function () {
+          _this10.renderImage(function () {
+            if (options.transition) {
+              setTimeout(function () {
+                addClass(image, CLASS_TRANSITION);
+                addClass(list, CLASS_TRANSITION);
+              }, 0);
+            }
+          });
+        });
+      }
+
+      return this;
+    },
+    // Show the current ratio of the image with percentage
+    tooltip: function tooltip() {
+      var _this11 = this;
+
+      var options = this.options,
+          tooltipBox = this.tooltipBox,
+          imageData = this.imageData;
+
+      if (!this.viewed || this.played || !options.tooltip) {
+        return this;
+      }
+
+      tooltipBox.textContent = "".concat(Math.round(imageData.ratio * 100), "%");
+
+      if (!this.tooltipping) {
+        if (options.transition) {
+          if (this.fading) {
+            dispatchEvent(tooltipBox, EVENT_TRANSITION_END);
+          }
+
+          addClass(tooltipBox, CLASS_SHOW);
+          addClass(tooltipBox, CLASS_FADE);
+          addClass(tooltipBox, CLASS_TRANSITION);
+          tooltipBox.removeAttribute('aria-hidden'); // Force reflow to enable CSS3 transition
+
+          tooltipBox.initialOffsetWidth = tooltipBox.offsetWidth;
+          addClass(tooltipBox, CLASS_IN);
+        } else {
+          addClass(tooltipBox, CLASS_SHOW);
+          tooltipBox.removeAttribute('aria-hidden');
+        }
+      } else {
+        clearTimeout(this.tooltipping);
+      }
+
+      this.tooltipping = setTimeout(function () {
+        if (options.transition) {
+          addListener(tooltipBox, EVENT_TRANSITION_END, function () {
+            removeClass(tooltipBox, CLASS_SHOW);
+            removeClass(tooltipBox, CLASS_FADE);
+            removeClass(tooltipBox, CLASS_TRANSITION);
+            tooltipBox.setAttribute('aria-hidden', true);
+            _this11.fading = false;
+          }, {
+            once: true
+          });
+          removeClass(tooltipBox, CLASS_IN);
+          _this11.fading = true;
+        } else {
+          removeClass(tooltipBox, CLASS_SHOW);
+          tooltipBox.setAttribute('aria-hidden', true);
+        }
+
+        _this11.tooltipping = false;
+      }, 1000);
+      return this;
+    },
+
+    /**
+     * Toggle the image size between its current size and natural size
+     * @param {Event} [_originalEvent=null] - The original event if any.
+     * @returns {Viewer} this
+     */
+    toggle: function toggle() {
+      var _originalEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
+
+      if (this.imageData.ratio === 1) {
+        this.zoomTo(this.imageData.oldRatio, true, _originalEvent);
+      } else {
+        this.zoomTo(1, true, _originalEvent);
+      }
+
+      return this;
+    },
+    // Reset the image to its initial state
+    reset: function reset() {
+      if (this.viewed && !this.played) {
+        this.imageData = assign({}, this.initialImageData);
+        this.renderImage();
+      }
+
+      return this;
+    },
+    // Update viewer when images changed
+    update: function update() {
+      var _this12 = this;
+
+      var element = this.element,
+          options = this.options,
+          isImg = this.isImg; // Destroy viewer if the target image was deleted
+
+      if (isImg && !element.parentNode) {
+        return this.destroy();
+      }
+
+      var images = [];
+      forEach(isImg ? [element] : element.querySelectorAll('img'), function (image) {
+        if (isFunction(options.filter)) {
+          if (options.filter.call(_this12, image)) {
+            images.push(image);
+          }
+        } else if (_this12.getImageURL(image)) {
+          images.push(image);
+        }
+      });
+
+      if (!images.length) {
+        return this;
+      }
+
+      this.images = images;
+      this.length = images.length;
+
+      if (this.ready) {
+        var changedIndexes = [];
+        forEach(this.items, function (item, i) {
+          var img = item.querySelector('img');
+          var image = images[i];
+
+          if (image && img) {
+            if (image.src !== img.src // Title changed (#408)
+            || image.alt !== img.alt) {
+              changedIndexes.push(i);
+            }
+          } else {
+            changedIndexes.push(i);
+          }
+        });
+        setStyle(this.list, {
+          width: 'auto'
+        });
+        this.initList();
+
+        if (this.isShown) {
+          if (this.length) {
+            if (this.viewed) {
+              var changedIndex = changedIndexes.indexOf(this.index);
+
+              if (changedIndex >= 0) {
+                this.viewed = false;
+                this.view(Math.max(Math.min(this.index - changedIndex, this.length - 1), 0));
+              } else {
+                var activeItem = this.items[this.index]; // Reactivate the current viewing item after reset the list.
+
+                addClass(activeItem, CLASS_ACTIVE);
+                activeItem.setAttribute('aria-selected', true);
+              }
+            }
+          } else {
+            this.image = null;
+            this.viewed = false;
+            this.index = 0;
+            this.imageData = {};
+            this.canvas.innerHTML = '';
+            this.title.innerHTML = '';
+          }
+        }
+      } else {
+        this.build();
+      }
+
+      return this;
+    },
+    // Destroy the viewer
+    destroy: function destroy() {
+      var element = this.element,
+          options = this.options;
+
+      if (!element[NAMESPACE]) {
+        return this;
+      }
+
+      this.destroyed = true;
+
+      if (this.ready) {
+        if (this.played) {
+          this.stop();
+        }
+
+        if (options.inline) {
+          if (this.fulled) {
+            this.exit();
+          }
+
+          this.unbind();
+        } else if (this.isShown) {
+          if (this.viewing) {
+            if (this.imageRendering) {
+              this.imageRendering.abort();
+            } else if (this.imageInitializing) {
+              this.imageInitializing.abort();
+            }
+          }
+
+          if (this.hiding) {
+            this.transitioning.abort();
+          }
+
+          this.hidden();
+        } else if (this.showing) {
+          this.transitioning.abort();
+          this.hidden();
+        }
+
+        this.ready = false;
+        this.viewer.parentNode.removeChild(this.viewer);
+      } else if (options.inline) {
+        if (this.delaying) {
+          this.delaying.abort();
+        } else if (this.initializing) {
+          this.initializing.abort();
+        }
+      }
+
+      if (!options.inline) {
+        removeListener(element, EVENT_CLICK, this.onStart);
+      }
+
+      element[NAMESPACE] = undefined;
+      return this;
+    }
+  };
+
+  var others = {
+    getImageURL: function getImageURL(image) {
+      var url = this.options.url;
+
+      if (isString(url)) {
+        url = image.getAttribute(url);
+      } else if (isFunction(url)) {
+        url = url.call(this, image);
+      } else {
+        url = '';
+      }
+
+      return url;
+    },
+    enforceFocus: function enforceFocus() {
+      var _this = this;
+
+      this.clearEnforceFocus();
+      addListener(document, EVENT_FOCUSIN, this.onFocusin = function (event) {
+        var viewer = _this.viewer;
+        var target = event.target;
+
+        if (target === document || target === viewer || viewer.contains(target)) {
+          return;
+        }
+
+        while (target) {
+          // Avoid conflicts with other modals (#474, #540)
+          if (target.getAttribute('tabindex') !== null || target.getAttribute('aria-modal') === 'true') {
+            return;
+          }
+
+          target = target.parentElement;
+        }
+
+        viewer.focus();
+      });
+    },
+    clearEnforceFocus: function clearEnforceFocus() {
+      if (this.onFocusin) {
+        removeListener(document, EVENT_FOCUSIN, this.onFocusin);
+        this.onFocusin = null;
+      }
+    },
+    open: function open() {
+      var body = this.body;
+      addClass(body, CLASS_OPEN);
+      body.style.paddingRight = "".concat(this.scrollbarWidth + (parseFloat(this.initialBodyComputedPaddingRight) || 0), "px");
+    },
+    close: function close() {
+      var body = this.body;
+      removeClass(body, CLASS_OPEN);
+      body.style.paddingRight = this.initialBodyPaddingRight;
+    },
+    shown: function shown() {
+      var element = this.element,
+          options = this.options,
+          viewer = this.viewer;
+      this.fulled = true;
+      this.isShown = true;
+      this.render();
+      this.bind();
+      this.showing = false;
+
+      if (options.focus) {
+        viewer.focus();
+        this.enforceFocus();
+      }
+
+      if (isFunction(options.shown)) {
+        addListener(element, EVENT_SHOWN, options.shown, {
+          once: true
+        });
+      }
+
+      if (dispatchEvent(element, EVENT_SHOWN) === false) {
+        return;
+      }
+
+      if (this.ready && this.isShown && !this.hiding) {
+        this.view(this.index);
+      }
+    },
+    hidden: function hidden() {
+      var element = this.element,
+          options = this.options,
+          viewer = this.viewer;
+
+      if (options.fucus) {
+        this.clearEnforceFocus();
+      }
+
+      this.fulled = false;
+      this.viewed = false;
+      this.isShown = false;
+      this.close();
+      this.unbind();
+      addClass(viewer, CLASS_HIDE);
+      viewer.removeAttribute('role');
+      viewer.removeAttribute('aria-labelledby');
+      viewer.removeAttribute('aria-modal');
+      viewer.setAttribute('aria-hidden', true);
+      this.resetList();
+      this.resetImage();
+      this.hiding = false;
+
+      if (!this.destroyed) {
+        if (isFunction(options.hidden)) {
+          addListener(element, EVENT_HIDDEN, options.hidden, {
+            once: true
+          });
+        }
+
+        dispatchEvent(element, EVENT_HIDDEN, null, {
+          cancelable: false
+        });
+      }
+    },
+    requestFullscreen: function requestFullscreen(options) {
+      var document = this.element.ownerDocument;
+
+      if (this.fulled && !(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
+        var documentElement = document.documentElement; // Element.requestFullscreen()
+
+        if (documentElement.requestFullscreen) {
+          // Avoid TypeError when convert `options` to dictionary
+          if (isPlainObject(options)) {
+            documentElement.requestFullscreen(options);
+          } else {
+            documentElement.requestFullscreen();
+          }
+        } else if (documentElement.webkitRequestFullscreen) {
+          documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
+        } else if (documentElement.mozRequestFullScreen) {
+          documentElement.mozRequestFullScreen();
+        } else if (documentElement.msRequestFullscreen) {
+          documentElement.msRequestFullscreen();
+        }
+      }
+    },
+    exitFullscreen: function exitFullscreen() {
+      var document = this.element.ownerDocument;
+
+      if (this.fulled && (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
+        // Document.exitFullscreen()
+        if (document.exitFullscreen) {
+          document.exitFullscreen();
+        } else if (document.webkitExitFullscreen) {
+          document.webkitExitFullscreen();
+        } else if (document.mozCancelFullScreen) {
+          document.mozCancelFullScreen();
+        } else if (document.msExitFullscreen) {
+          document.msExitFullscreen();
+        }
+      }
+    },
+    change: function change(event) {
+      var options = this.options,
+          pointers = this.pointers;
+      var pointer = pointers[Object.keys(pointers)[0]]; // In the case of the `pointers` object is empty (#421)
+
+      if (!pointer) {
+        return;
+      }
+
+      var offsetX = pointer.endX - pointer.startX;
+      var offsetY = pointer.endY - pointer.startY;
+
+      switch (this.action) {
+        // Move the current image
+        case ACTION_MOVE:
+          this.move(offsetX, offsetY, event);
+          break;
+        // Zoom the current image
+
+        case ACTION_ZOOM:
+          this.zoom(getMaxZoomRatio(pointers), false, event);
+          break;
+
+        case ACTION_SWITCH:
+          {
+            this.action = 'switched';
+            var absoluteOffsetX = Math.abs(offsetX);
+
+            if (absoluteOffsetX > 1 && absoluteOffsetX > Math.abs(offsetY)) {
+              // Empty `pointers` as `touchend` event will not be fired after swiped in iOS browsers.
+              this.pointers = {};
+
+              if (offsetX > 1) {
+                this.prev(options.loop);
+              } else if (offsetX < -1) {
+                this.next(options.loop);
+              }
+            }
+
+            break;
+          }
+      } // Override
+
+
+      forEach(pointers, function (p) {
+        p.startX = p.endX;
+        p.startY = p.endY;
+      });
+    },
+    isSwitchable: function isSwitchable() {
+      var imageData = this.imageData,
+          viewerData = this.viewerData;
+      return this.length > 1 && imageData.x >= 0 && imageData.y >= 0 && imageData.width <= viewerData.width && imageData.height <= viewerData.height;
+    }
+  };
+
+  var AnotherViewer = WINDOW.Viewer;
+
+  var getUniqueID = function (id) {
+    return function () {
+      id += 1;
+      return id;
+    };
+  }(-1);
+
+  var Viewer = /*#__PURE__*/function () {
+    /**
+     * Create a new Viewer.
+     * @param {Element} element - The target element for viewing.
+     * @param {Object} [options={}] - The configuration options.
+     */
+    function Viewer(element) {
+      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+
+      _classCallCheck(this, Viewer);
+
+      if (!element || element.nodeType !== 1) {
+        throw new Error('The first argument is required and must be an element.');
+      }
+
+      this.element = element;
+      this.options = assign({}, DEFAULTS, isPlainObject(options) && options);
+      this.action = false;
+      this.fading = false;
+      this.fulled = false;
+      this.hiding = false;
+      this.imageClicked = false;
+      this.imageData = {};
+      this.index = this.options.initialViewIndex;
+      this.isImg = false;
+      this.isShown = false;
+      this.length = 0;
+      this.moving = false;
+      this.played = false;
+      this.playing = false;
+      this.pointers = {};
+      this.ready = false;
+      this.rotating = false;
+      this.scaling = false;
+      this.showing = false;
+      this.timeout = false;
+      this.tooltipping = false;
+      this.viewed = false;
+      this.viewing = false;
+      this.wheeling = false;
+      this.zooming = false;
+      this.id = getUniqueID();
+      this.init();
+    }
+
+    _createClass(Viewer, [{
+      key: "init",
+      value: function init() {
+        var _this = this;
+
+        var element = this.element,
+            options = this.options;
+
+        if (element[NAMESPACE]) {
+          return;
+        }
+
+        element[NAMESPACE] = this; // The `focus` option requires the `keyboard` option set to `true`.
+
+        if (options.focus && !options.keyboard) {
+          options.focus = false;
+        }
+
+        var isImg = element.localName === 'img';
+        var images = [];
+        forEach(isImg ? [element] : element.querySelectorAll('img'), function (image) {
+          if (isFunction(options.filter)) {
+            if (options.filter.call(_this, image)) {
+              images.push(image);
+            }
+          } else if (_this.getImageURL(image)) {
+            images.push(image);
+          }
+        });
+        this.isImg = isImg;
+        this.length = images.length;
+        this.images = images;
+        this.initBody(); // Override `transition` option if it is not supported
+
+        if (isUndefined(document.createElement(NAMESPACE).style.transition)) {
+          options.transition = false;
+        }
+
+        if (options.inline) {
+          var count = 0;
+
+          var progress = function progress() {
+            count += 1;
+
+            if (count === _this.length) {
+              var timeout;
+              _this.initializing = false;
+              _this.delaying = {
+                abort: function abort() {
+                  clearTimeout(timeout);
+                }
+              }; // build asynchronously to keep `this.viewer` is accessible in `ready` event handler.
+
+              timeout = setTimeout(function () {
+                _this.delaying = false;
+
+                _this.build();
+              }, 0);
+            }
+          };
+
+          this.initializing = {
+            abort: function abort() {
+              forEach(images, function (image) {
+                if (!image.complete) {
+                  removeListener(image, EVENT_LOAD, progress);
+                  removeListener(image, EVENT_ERROR, progress);
+                }
+              });
+            }
+          };
+          forEach(images, function (image) {
+            if (image.complete) {
+              progress();
+            } else {
+              var onLoad;
+              var onError;
+              addListener(image, EVENT_LOAD, onLoad = function onLoad() {
+                removeListener(image, EVENT_ERROR, onError);
+                progress();
+              }, {
+                once: true
+              });
+              addListener(image, EVENT_ERROR, onError = function onError() {
+                removeListener(image, EVENT_LOAD, onLoad);
+                progress();
+              }, {
+                once: true
+              });
+            }
+          });
+        } else {
+          addListener(element, EVENT_CLICK, this.onStart = function (_ref) {
+            var target = _ref.target;
+
+            if (target.localName === 'img' && (!isFunction(options.filter) || options.filter.call(_this, target))) {
+              _this.view(_this.images.indexOf(target));
+            }
+          });
+        }
+      }
+    }, {
+      key: "build",
+      value: function build() {
+        if (this.ready) {
+          return;
+        }
+
+        var element = this.element,
+            options = this.options;
+        var parent = element.parentNode;
+        var template = document.createElement('div');
+        template.innerHTML = TEMPLATE;
+        var viewer = template.querySelector(".".concat(NAMESPACE, "-container"));
+        var title = viewer.querySelector(".".concat(NAMESPACE, "-title"));
+        var toolbar = viewer.querySelector(".".concat(NAMESPACE, "-toolbar"));
+        var navbar = viewer.querySelector(".".concat(NAMESPACE, "-navbar"));
+        var button = viewer.querySelector(".".concat(NAMESPACE, "-button"));
+        var canvas = viewer.querySelector(".".concat(NAMESPACE, "-canvas"));
+        this.parent = parent;
+        this.viewer = viewer;
+        this.title = title;
+        this.toolbar = toolbar;
+        this.navbar = navbar;
+        this.button = button;
+        this.canvas = canvas;
+        this.footer = viewer.querySelector(".".concat(NAMESPACE, "-footer"));
+        this.tooltipBox = viewer.querySelector(".".concat(NAMESPACE, "-tooltip"));
+        this.player = viewer.querySelector(".".concat(NAMESPACE, "-player"));
+        this.list = viewer.querySelector(".".concat(NAMESPACE, "-list"));
+        viewer.id = "".concat(NAMESPACE).concat(this.id);
+        title.id = "".concat(NAMESPACE, "Title").concat(this.id);
+        addClass(title, !options.title ? CLASS_HIDE : getResponsiveClass(Array.isArray(options.title) ? options.title[0] : options.title));
+        addClass(navbar, !options.navbar ? CLASS_HIDE : getResponsiveClass(options.navbar));
+        toggleClass(button, CLASS_HIDE, !options.button);
+
+        if (options.keyboard) {
+          button.setAttribute('tabindex', 0);
+        }
+
+        if (options.backdrop) {
+          addClass(viewer, "".concat(NAMESPACE, "-backdrop"));
+
+          if (!options.inline && options.backdrop !== 'static') {
+            setData(canvas, DATA_ACTION, 'hide');
+          }
+        }
+
+        if (isString(options.className) && options.className) {
+          // In case there are multiple class names
+          options.className.split(REGEXP_SPACES).forEach(function (className) {
+            addClass(viewer, className);
+          });
+        }
+
+        if (options.toolbar) {
+          var list = document.createElement('ul');
+          var custom = isPlainObject(options.toolbar);
+          var zoomButtons = BUTTONS.slice(0, 3);
+          var rotateButtons = BUTTONS.slice(7, 9);
+          var scaleButtons = BUTTONS.slice(9);
+
+          if (!custom) {
+            addClass(toolbar, getResponsiveClass(options.toolbar));
+          }
+
+          forEach(custom ? options.toolbar : BUTTONS, function (value, index) {
+            var deep = custom && isPlainObject(value);
+            var name = custom ? hyphenate(index) : value;
+            var show = deep && !isUndefined(value.show) ? value.show : value;
+
+            if (!show || !options.zoomable && zoomButtons.indexOf(name) !== -1 || !options.rotatable && rotateButtons.indexOf(name) !== -1 || !options.scalable && scaleButtons.indexOf(name) !== -1) {
+              return;
+            }
+
+            var size = deep && !isUndefined(value.size) ? value.size : value;
+            var click = deep && !isUndefined(value.click) ? value.click : value;
+            var item = document.createElement('li');
+
+            if (options.keyboard) {
+              item.setAttribute('tabindex', 0);
+            }
+
+            item.setAttribute('role', 'button');
+            addClass(item, "".concat(NAMESPACE, "-").concat(name));
+
+            if (!isFunction(click)) {
+              setData(item, DATA_ACTION, name);
+            }
+
+            if (isNumber(show)) {
+              addClass(item, getResponsiveClass(show));
+            }
+
+            if (['small', 'large'].indexOf(size) !== -1) {
+              addClass(item, "".concat(NAMESPACE, "-").concat(size));
+            } else if (name === 'play') {
+              addClass(item, "".concat(NAMESPACE, "-large"));
+            }
+
+            if (isFunction(click)) {
+              addListener(item, EVENT_CLICK, click);
+            }
+
+            list.appendChild(item);
+          });
+          toolbar.appendChild(list);
+        } else {
+          addClass(toolbar, CLASS_HIDE);
+        }
+
+        if (!options.rotatable) {
+          var rotates = toolbar.querySelectorAll('li[class*="rotate"]');
+          addClass(rotates, CLASS_INVISIBLE);
+          forEach(rotates, function (rotate) {
+            toolbar.appendChild(rotate);
+          });
+        }
+
+        if (options.inline) {
+          addClass(button, CLASS_FULLSCREEN);
+          setStyle(viewer, {
+            zIndex: options.zIndexInline
+          });
+
+          if (window.getComputedStyle(parent).position === 'static') {
+            setStyle(parent, {
+              position: 'relative'
+            });
+          }
+
+          parent.insertBefore(viewer, element.nextSibling);
+        } else {
+          addClass(button, CLASS_CLOSE);
+          addClass(viewer, CLASS_FIXED);
+          addClass(viewer, CLASS_FADE);
+          addClass(viewer, CLASS_HIDE);
+          setStyle(viewer, {
+            zIndex: options.zIndex
+          });
+          var container = options.container;
+
+          if (isString(container)) {
+            container = element.ownerDocument.querySelector(container);
+          }
+
+          if (!container) {
+            container = this.body;
+          }
+
+          container.appendChild(viewer);
+        }
+
+        if (options.inline) {
+          this.render();
+          this.bind();
+          this.isShown = true;
+        }
+
+        this.ready = true;
+
+        if (isFunction(options.ready)) {
+          addListener(element, EVENT_READY, options.ready, {
+            once: true
+          });
+        }
+
+        if (dispatchEvent(element, EVENT_READY) === false) {
+          this.ready = false;
+          return;
+        }
+
+        if (this.ready && options.inline) {
+          this.view(this.index);
+        }
+      }
+      /**
+       * Get the no conflict viewer class.
+       * @returns {Viewer} The viewer class.
+       */
+
+    }], [{
+      key: "noConflict",
+      value: function noConflict() {
+        window.Viewer = AnotherViewer;
+        return Viewer;
+      }
+      /**
+       * Change the default options.
+       * @param {Object} options - The new default options.
+       */
+
+    }, {
+      key: "setDefaults",
+      value: function setDefaults(options) {
+        assign(DEFAULTS, isPlainObject(options) && options);
+      }
+    }]);
+
+    return Viewer;
+  }();
+
+  assign(Viewer.prototype, render, events, handlers, methods, others);
+
+  return Viewer;
+
+}));

+ 458 - 0
src/web/staticres/css/dataSmt/dataMart.css

@@ -0,0 +1,458 @@
+.dataMart {
+  padding-top: 72px;
+
+}
+
+.dataMart .header {
+  position: relative;
+  width: 100%;
+}
+
+.dataMart .header img {
+  width: 100%;
+}
+
+/* 搜索 */
+.jy-dataMart-search {
+  position: absolute;
+  width: 1200px;
+  left: 50%;
+  transform: translateX(-50%);
+  bottom: -33px;
+  background: transparent;
+  z-index: 1;
+}
+
+.jy-dataMart-search .form-search {
+  position: relative;
+  display: flex;
+  align-items: center;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.jy-dataMart-search .search {
+  width: 960px;
+  position: relative;
+  text-align: center;
+  position: relative;
+  margin: 0 auto;
+}
+
+.jy-dataMart-search .ser {
+  width: 888px;
+  height: 52px;
+  padding: 0 24px;
+  border: 1px solid #2ABED1;
+  border-radius: 8px 0 0 8px;
+  color: #1d1d1d;
+  box-sizing: border-box;
+  font-size: 14px;
+}
+
+.jy-dataMart-search .btn {
+  width: 72px;
+  height: 52px;
+  border-radius: 0 8px 8px 0;
+  border: none;
+  background: #2CB7CA url(/images/dataSmt/search.png) center center no-repeat;
+  background-size: 24px 24px;
+  cursor: pointer;
+}
+
+.jy-dataMart-search .ser::-webkit-input-placeholder {
+  color: #999;
+  font-size: 14px;
+}
+
+.jy-dataMart-search .ser::-moz-placeholder {
+  color: #999;
+  font-size: 14px;
+}
+
+.jy-dataMart-search .ser:-ms-input-placeholder {
+  color: #999;
+  font-size: 14px;
+}
+
+.jy-dataMart-search .ser::-ms-input-placeholder {
+  color: #999;
+  font-size: 14px;
+}
+
+.jy-dataMart-search .ser::placeholder {
+  color: #999;
+  font-size: 14px;
+}
+
+.dataMart .hotkeywords {
+  width: 960px;
+  display: flex;
+  margin: auto;
+  margin-top: 41px;
+}
+
+.dataMart .hotkeywords p {
+  font-size: 14px;
+  line-height: 22px;
+  color: #686868;
+  display: flex;
+  align-items: center;
+}
+
+.dataMart .hotkeywords p img {
+  width: 16px;
+  margin-right: 8px;
+}
+
+.dataMart .hotkeywords .content {
+  margin-left: 16px;
+}
+
+.dataMart .hotkeywords .content a {
+  margin-right: 32px;
+  line-height: 22px;
+  font-size: 14px;
+  color: #686868;
+}
+.dataMart .hotkeywords .content a:hover {
+  text-decoration: none;
+}
+.dataMart .middle {
+  margin-top: 78px;
+
+}
+
+.dataMart .tabs_box {
+  width: 1200px;
+  margin: auto;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.dataMart .tabs_box h1 {
+  font-size: 22px;
+  line-height: 32px;
+  color: #1D1D1D;
+}
+
+.dataMart .tabs_box div {
+  width: 952px;
+  display: flex;
+  justify-content: space-between;
+}
+
+.dataMart .tabs_box div a {
+  font-size: 14px;
+  line-height: 20px;
+  color: #1D1D1D;
+  padding: 8px 20px;
+  border-radius: 8px;
+  box-sizing: border-box;
+  cursor: pointer;
+  display: block;
+}
+
+.dataMart .tabs_box div a:hover {
+  text-decoration: none;
+}
+
+.dataMart .tabs_box div .active {
+  background-color: #2ABED1;
+  color: #fff;
+}
+
+.dataMart .tabs_box .keys_desc {
+  font-size: 14px;
+  line-height: 32px;
+  color: #2ABED1;
+  margin-top: 2px;
+  text-decoration: underline;
+}
+
+.dataMart .list_container {
+  background: linear-gradient(91.63deg, #E8FCFF 16.29%, #EDF2FE 78.49%);
+  padding: 40px 0 80px 0;
+  margin-top: 20px;
+}
+
+.dataMart .list_container .list_content {
+  width: 1200px;
+  margin: auto;
+}
+
+.dataMart .list_container .list_content .noData img {
+  width: 260px;
+  display: block;
+  margin: auto;
+}
+
+.dataMart .list_container .list_content .noData .desc {
+  color: #999;
+  line-height: 22px;
+  font-size: 14px;
+  width: 484px;
+  margin: auto;
+  text-align: center;
+}
+
+.dataMart .list_container .dataCustomization {
+  width: 180px;
+  height: 46px;
+  line-height: 46px;
+  text-align: center;
+  background-color: #2ABED1;
+  border-radius: 6px;
+  color: #fff;
+  font-size: 16px;
+  cursor: pointer;
+  margin: auto;
+  box-sizing: border-box;
+  display: block;
+  margin-top: 32px;
+}
+
+.list_container .list {
+  width: 100%;
+  display: flex;
+  justify-content: space-between;
+  flex-wrap: wrap;
+}
+
+.list_container .list .item {
+  width: 282px;
+  min-height: 204px;
+  border-radius: 16px;
+  background: #FFFFFF;
+  position: relative;
+  box-sizing: border-box;
+  padding: 42px 24px 24px 24px;
+  margin-bottom: 24px;
+}
+
+.list_container .list .item:hover {
+  box-shadow: 0px 4px 24px 0px #02348033;
+}
+
+.list_container .cornerMark {
+  position: absolute;
+  left: 0;
+  top: 0;
+  min-width: 80px;
+  min-height: 23px;
+  border-radius: 16px 0px 16px 0px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  padding: 1px 11px;
+  box-sizing: border-box;
+}
+
+.list_container .yellow {
+  background: linear-gradient(93.58deg, #FF9F40 0%, #FFCC66 100%);
+}
+
+.list_container .blue {
+  background: linear-gradient(272.12deg, #00D1FF 0%, #3399FF 100%);
+}
+
+.list_container .green {
+  background: linear-gradient(93.58deg, #00B031 0%, #0BD991 100%);
+}
+
+.list_container .blueBlack {
+  background: linear-gradient(274.07deg, #2ABED1 0%, #1DB5E6 99%, #1DB5E6 100%);
+}
+
+.list_container .cornerMark p {
+  font-size: 14px;
+  font-weight: 700;
+  line-height: 22px;
+  text-align: center;
+  /* box-shadow: 0px 2px 2px 0px #00000026; */
+  color: #fff;
+}
+
+.list_container .list .item .title {
+  width: 100%;
+  font-size: 16px;
+  font-weight: 400;
+  line-height: 24px;
+  text-align: left;
+  color: #1D1D1D;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  /*行数*/
+  -webkit-box-orient: vertical;
+}
+
+.dataMart .list .title .highlight {
+  color: rgba(42, 190, 209, 1);
+}
+
+.dataMart .list .title .bold {
+  font-weight: 700;
+}
+
+.list_container .list .item .tag_box {
+  width: 100%;
+  display: flex;
+  flex-wrap: wrap;
+  margin-top: 8px;
+}
+
+.list_container .list .item .tag_box .tag {
+  font-size: 12px;
+  line-height: 18px;
+  padding: 1px 8px;
+  margin-right: 8px;
+  border-radius: 4px;
+  box-sizing: border-box;
+}
+
+.list_container .list .item .tag_box .yellow {
+  color: #C98F37;
+  background: rgba(241, 208, 144, 0.16);
+}
+
+.list_container .list .item .tag_box .grayness {
+  color: rgba(104, 104, 104, 1);
+  background: #F5F5FB;
+  border: 1px solid rgba(236, 236, 236, 1)
+}
+
+.list_container .list .item .seeDetail {
+  width: 233px;
+  height: 36px;
+  border-radius: 6px;
+  background: linear-gradient(270deg, #3687FF 0%, #2ABED1 100%);
+  line-height: 36px;
+  color: rgba(255, 255, 255, 1);
+  font-size: 16px;
+  text-align: center;
+  margin: auto;
+  margin-top: 24px;
+  display: block;
+}
+
+.list_container .list .item .seeDetail:hover {
+  text-decoration: none;
+}
+
+.dataMart .dataMart_advertising {
+  margin: 0;
+  width: 100%;
+  position: relative;
+}
+.dataMart .dataMart_advertising .advertising{
+  width: 100%;
+  display: block;
+}
+.dataMart .dataMart_advertising .advertising_close{
+  width: 20px;
+  height: 20px;
+  position:absolute;
+  right: 40px;
+  top: 50%;
+  transform: translateY(-50%);
+  cursor: pointer;
+ 
+}
+.dataMart .fixed_bottom{
+  position: fixed;
+  left: 0;
+  bottom: 0;
+  z-index:99;
+}
+.dataMart .dataMart_dialog {
+  position: fixed;
+  z-index: 999;
+  left: 0;
+  top: 0;
+  bottom: 0;
+  right: 0;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: none;
+}
+.dataMart .dataMart_dialog .content{
+  width: 750px;
+  height: 674px;
+  border-radius: 8px;
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  transform: translate(-50%,-50%); 
+  background-color: #fff;
+  padding: 32px 0;
+  box-sizing: border-box;
+}
+.dataMart .dataMart_dialog .content .table_box{
+  width: calc(100% - 3px);
+  margin: auto;
+  margin-top: 16px;
+  height: 560px;
+  overflow-y:auto;
+  padding: 0 4px;
+}
+.dataMart .dataMart_dialog .content .table_box::-webkit-scrollbar, ::-webkit-scrollbar {
+  width: 4px;
+  height: 8px;
+}
+.dataMart .dataMart_dialog .content .table_box::-webkit-scrollbar-thumb, ::-webkit-scrollbar-thumb {
+  border-radius: 3px;
+  background-color: #E0E0E0 !important;
+  opacity: 1;
+}
+.dataMart .dataMart_dialog .content .close_{
+  width: 20px;
+  height: 20px;
+  position: absolute;
+  right: 16px;
+  top: 16px;
+  cursor: pointer;
+}
+.dataMart .dataMart_dialog .content h1{
+font-size: 18px;
+font-weight: 400;
+line-height: 28px;
+text-align: center;
+color: #1D1D1D;
+}
+.dataMart_dialog table{
+  width: 686px;
+  border-collapse: collapse;
+  box-sizing: border-box;
+  margin: auto;
+  /* border: 1px solid #E5E5E5; */
+}
+.dataMart_dialog table th{ 
+ background-color: #F5F6F7;
+ border: 1px solid #E5E5E5;
+ padding:11px 16px ;
+ box-sizing: border-box;
+ line-height: 22px;
+ color:#999999; 
+ font-size: 14px;
+ vertical-align: middle
+}
+.dataMart_dialog table td{ 
+  border: 1px solid #E5E5E5;
+  padding:11px 16px ;
+  box-sizing: border-box;
+  line-height: 22px;
+  color: #1D1D1D; 
+  font-size: 14px;
+  vertical-align: middle
+ }
+ .dataMart_dialog table .keys{
+  text-align: center;
+  width: 140px;
+
+ }
+ .dataMart_dialog table .values{
+  width: calc(100% - 140px);
+  text-align: left;
+ }

+ 242 - 0
src/web/staticres/css/dataSmt/dataMart_detail.css

@@ -0,0 +1,242 @@
+.dataMart_detail {
+  padding-top: 72px;
+  background-color: #F5F5FB;
+  overflow: hidden;
+}
+.dataMart_detail .detail_header{
+  width: 1200px;
+  box-sizing: border-box;
+  margin: auto;
+  background-color: #fff;
+  padding: 32px 36px 22px 36px;
+  border-radius: 4px;
+  position: relative;
+  margin-top: 20px;
+}
+.dataMart_detail .cornerMark {
+  position: absolute;
+  left: 0;
+  top: 0;
+  min-width: 80px;
+  min-height: 23px;
+  border-radius: 4px 0px 16px 0px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  padding: 1px 11px;
+  box-sizing: border-box;
+}
+.dataMart_detail .cornerMark p {
+  font-size: 14px;
+  font-weight: 700;
+  line-height: 22px;
+  text-align: center;
+  /* box-shadow: 0px 2px 2px 0px #00000026; */
+  color: #fff;
+}
+.dataMart_detail .detail_header .yellow {
+  background: linear-gradient(93.58deg, #FF9F40 0%, #FFCC66 100%);
+}
+
+.dataMart_detail .detail_header .blue {
+  background: linear-gradient(272.12deg, #00D1FF 0%, #3399FF 100%);
+}
+
+.dataMart_detail .detail_header .green {
+  background: linear-gradient(93.58deg, #00B031 0%, #0BD991 100%);
+}
+
+.dataMart_detail .detail_header .blueBlack {
+  background: linear-gradient(274.07deg, #2ABED1 0%, #1DB5E6 99%, #1DB5E6 100%);
+}
+.dataMart_detail .detail_header .title{
+  font-size: 24px;
+  line-height: 36px;
+  color: #252627;
+}
+.dataMart_detail .detail_header .highlight {
+  color: rgba(42, 190, 209, 1);
+}
+
+.dataMart_detail .detail_header .bold {
+  font-weight: 700;
+
+}
+.dataMart_detail .detail_header .tag_box {
+  width: 100%;
+  display: flex;
+  flex-wrap: wrap;
+  margin-top: 12px;
+}
+
+.dataMart_detail .detail_header .tag_box .tag {
+  font-size: 12px;
+  line-height: 18px;
+  padding: 1px 8px;
+  margin-right: 8px;
+  border-radius: 4px;
+  box-sizing: border-box;
+}
+
+.dataMart_detail .detail_header .tag_box .yellow {
+  color: #C98F37;
+  background: rgba(241, 208, 144, 0.16);
+}
+
+.dataMart_detail .detail_header .tag_box .grayness {
+  color: rgba(104, 104, 104, 1);
+  background: #F5F5FB;
+  border: 1px solid rgba(236, 236, 236, 1)
+}
+.dataMart_detail .detail_header .desc{
+  color: #5F5E64;
+  font-size: 14px;
+  line-height: 22px;
+  margin-top: 12px;
+}
+.dataMart_detail .detail_header .button_box{
+  display: flex;
+  margin-top: 24px;
+  align-items: end;
+}
+.detail_header .button_box button{
+  width: 132px;
+  height: 36px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  box-sizing: border-box;
+  font-size: 16px;
+  border-radius: 6px;
+}
+.detail_header .button_box .consult{
+  background-color: #fff;
+  border: 1px solid #E0E0E0;
+  color: #1d1d1d;
+}
+.detail_header .button_box .purchase{
+  background-color: #2ABED1;
+  color: #fff;
+  margin-left: 32px;
+}
+.detail_header .dataCustomization{
+  line-height: 22px;
+  font-size: 14px;
+  color: #5F5E64;
+  margin-left: 16px;
+}
+.detail_header .dataCustomization a{
+  line-height: 22px;
+  font-size: 14px;
+}
+.dataMart_detail .middle{
+  width: 1200px;
+  margin: auto;
+  background-color: #fff;
+  margin-bottom: 80px;
+  padding: 32px 0;
+  margin-top: 16px;
+}
+.dataMart_detail .middle .title{
+  line-height: 24px;
+  height: 24px;
+  font-size: 20px;
+  color: #1D1D1D;
+  position: relative;
+  padding-left: 40px;
+}
+.dataMart_detail .middle .title::after{
+  width: 3px;
+  height: 24px;
+  content: '';
+  background-color: #2ABED1;
+  border-radius: 0 2px 2px 0;
+  display: block;
+  position:absolute;
+  left: 0;
+  top: 0;
+}
+.dataMart_detail .middle .coreAdvantage{
+  margin-top: 16px;
+  padding: 0 40px;
+  width: 100%;
+  display: flex;
+  justify-content:space-between;
+  box-sizing: border-box;
+  margin-bottom: 64px;
+}
+.dataMart_detail .middle .coreAdvantage .item{
+  width: 268px;
+  height: 231px;
+  border-radius: 16px;
+  background-size: 100% 100%;
+  box-sizing: border-box;
+  padding-top: 54px;
+}
+.dataMart_detail .middle .coreAdvantage .item .box:hover{
+  box-shadow: 0px 4px 20px 0px #001A411F;
+
+}
+.dataMart_detail .middle .coreAdvantage .item .box{
+  width: 100%;
+  height: 100%;
+  border-radius: 16px;
+  overflow: hidden;
+}
+.dataResource{
+  background-image: url(/images/dataSmt/data.png);
+}
+.coverageArea{
+  background-image: url(/images/dataSmt/coverage.png);
+}
+.service{
+  background-image: url(/images/dataSmt/service.png);
+}
+.professionalTeam{
+  background-image: url(/images/dataSmt/team.png);
+}
+.dataMart_detail .middle .coreAdvantage .item .box h1{
+ font-size: 20px;
+ line-height: 32px;
+ color: #1D1D1D;
+ text-align: center;
+ margin-top: 69px;
+}
+.dataMart_detail .middle .coreAdvantage .item .box p{
+  width: 212px;
+  font-size: 14px;
+  line-height: 22px;
+  color: #686868;
+  text-align: center;
+  margin: auto;
+  margin-top: 9px;
+ }
+.dataMart_detail .middle .table_content{
+  margin-top: 16px;
+  padding: 0 40px;
+  width: 100%;
+  box-sizing: border-box;
+}
+.table_content .tableDescriptions{
+  color: #999999;
+  font-size: 14px;
+  line-height: 22px;
+}
+.table_content .table_img{
+  width: 100%;
+  margin-top: 16px;
+}
+.table_content .table_img img{
+  width: 100%;
+  cursor: pointer;
+}
+.dataMart_detail .foot_{
+  width: 100%;
+  margin: 0;
+
+}
+.dataMart_detail .foot_ img{
+  width: 100%;
+  display: block;
+
+}

+ 449 - 0
src/web/staticres/dataSmt/css/index.css

@@ -0,0 +1,449 @@
+a:hover,
+a:visited,
+a:active,
+a:focus{
+  text-decoration: none;
+}
+.page--datamarket-index{
+  padding-top: 72px;
+}
+.page--datamarket-index .market-banner{
+  width: 100%;
+  height: 480px;
+  background: url(/dataSmt/images/land-page-banner.png) no-repeat center center;
+  background-size: 100% 480px;
+}
+.page--datamarket-index .banner-title {
+  padding: 128px 0 22px;
+  font-size: 54px;
+  line-height: 72px;
+  color: #1D1D1D;
+  font-weight: 200;
+  letter-spacing: 12px;
+}
+.page--datamarket-index .banner-subtitle {
+  font-size: 20px;
+  line-height: 32px;
+  color: #686868;
+}
+
+.page--datamarket-index .market-modules{
+  position: relative;
+  margin-top: -75px;
+  background: transparent;
+  z-index: 10;
+}
+.page--datamarket-index .market-modules-container{
+  position: relative;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  height: 150px;
+  background: linear-gradient(#DCFBFF, #FFFFFF);
+  box-shadow: 0 2px 2px 0 #fff inset, 0 6px 24px 0px rgba(2, 52, 128, 0.1);
+  z-index: 1;
+  border-radius: 16px;
+}
+.page--datamarket-index .item-module{
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 25%;
+  flex: 1;
+  flex-shrink: 0;
+  text-align: center;
+  font-size: 16px;
+  line-height: 20px;
+}
+.page--datamarket-index .item-module:not(:last-child){
+  border-right: 1px solid #ECECEC;
+}
+.page--datamarket-index .item-module > img{
+  width: 96px;
+  height: 96px;
+  margin-right: 20px;
+  flex-shrink: 0;
+}
+
+.page--datamarket-index .d-header{
+  padding-top: 80px;
+}
+
+.page--datamarket-index .h-title{
+  color: #1D1D1D;
+  font-size: 32px;
+  line-height: 32px;
+  text-align: center;
+}
+.page--datamarket-index .h-desc{
+  margin-top: 12px;
+  color: #686868;
+  font-size: 18px;
+  line-height: 28px;
+  text-align: center;
+}
+
+.page--datamarket-index .data-download{
+  width: 100%;
+  /* height: 638px; */
+  background: url(/dataSmt/images/data-download-bg.png) no-repeat bottom center #fff;
+  background-size: 100% 340px;
+}
+
+.page--datamarket-index .download-pro-container {
+  display: flex;
+  align-items: center;
+  margin-top: 56px;
+  border-radius: 16px;
+  overflow: hidden;
+  box-shadow: 0 10px 18px 0px rgba(4, 35, 82, 0.1); 
+}
+.page--datamarket-index .item-pro{
+  flex: 1;
+  width: 25%;
+  padding: 28px 0 24px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  background: linear-gradient(to left, #C5F4FA, #EAFEFF);
+}
+.page--datamarket-index .item-pro.disabled{
+  background: linear-gradient(to left,#EBF2F6, #F3F8FC);
+}
+
+.page--datamarket-index  .item-pro > img{
+  width: 80px;
+  height: 80px;
+}
+
+.page--datamarket-index .item-pro > p{
+  margin-top: 8px;
+  font-size: 18px;
+  line-height: 28px;
+  color: #1D1D1D;
+}
+
+.page--datamarket-index .item-pro .btn-light.no-click{
+  background: #95AFC8!important;
+  cursor: default!important;
+}
+.page--datamarket-index .download-info-container {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-top: 48px;
+}
+.page--datamarket-index .item-info{
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  min-width: 200px;
+  font-size: 16px;
+  line-height: 24px;
+  color: #1D1D1D;
+  text-align: center;
+}
+.page--datamarket-index  .item-info:not(:last-child){
+  margin-right: 140px;
+}
+.page--datamarket-index .item-info strong{
+  font-weight: 700;
+  font-size: 24px;
+  line-height: 22px;
+}
+.page--datamarket-index .item-info > p{
+  margin-top: 6px;
+}
+.download-footer{
+  padding: 32px 0 48px;
+  text-align: center;
+}
+.learn-more{
+  color: #2ABED1;
+  font-size: 18px;
+  line-height: 28px;
+  text-decoration: none;
+}
+.learn-more:active,
+.learn-more:hover,
+.learn-more:visited,
+.learn-more:focus{
+  color: #2ABED1;
+  text-decoration: none;
+}
+
+.page--datamarket-index .data-supermarket{}
+
+.page--datamarket-index .super-container{
+  display: flex;
+  justify-content: space-between;
+  margin-top: 56px;
+}
+.page--datamarket-index .super-container .super-left{
+  width: 688px;
+  height: 354px;
+  padding: 32px 40px;
+  background: linear-gradient(to left, #3CADF9, #10BDE3, #276EF3), url(/dataSmt/images/supermarket-left-bg.png) no-repeat;
+  background-position: right center;
+  background-blend-mode: color-burn;
+  background-size: 100% 100%;
+  border-radius: 16px;
+}
+.super-left .data-list{
+  margin-bottom: 10px;
+}
+.super-left .data-list > h4{
+  font-weight: bold;
+  font-size: 18px;
+  line-height: 28px;
+  color: #fff;
+}
+.super-left .data-list > p{
+  font-size: 14px;
+  line-height: 22px;
+  color: #fff;
+}
+.super-left .data-list-more{
+  margin-left: 120px;
+}
+.super-left .data-list-more:hover{
+  color: #fff;
+}
+.page--datamarket-index .super-container .super-right{
+  width: 488px;
+  height: 354px;
+  padding: 32px 40px;
+  background: linear-gradient(#E8FCFF,#EDF2FE), url(/dataSmt/images/supermarket-right-bg.png) no-repeat;
+  background-position: center center;
+  background-blend-mode: color-burn;
+  background-size: 100% 100%;
+  border-radius: 16px;
+}
+.page--datamarket-index .hot-title{
+  font-size: 20px;
+  line-height: 32px;
+  color: #1D1D1D;
+}
+.page--datamarket-index .hot-icon{
+  color: #FF3A20;
+  font-size: 16px;
+  line-height: 24px;
+}
+.page--datamarket-index .hot-data-container{
+  margin-top: 12px;
+}
+.page--datamarket-index .hot-data-item{
+  display: block;
+  text-decoration: none;
+  color: #1D1D1D;
+  font-size: 16px;
+  line-height: 24px;
+  overflow: hidden;
+  max-width: 210px;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+.page--datamarket-index .hot-data-item:hover{
+  color: #2ABED1;
+  text-decoration: none;
+}
+
+.page--datamarket-index .data-export{
+  padding-bottom: 80px;
+}
+.data-export .export-content{
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 48px 125px 40px;
+}
+.data-export .export-item{
+  display: flex;
+  align-items: center;
+}
+.data-export .export-item > img{
+  width: 80px;
+  height: 80px;
+  margin-right: 12px;
+}
+.data-export .export-item > span{
+  color: #1D1D1D;
+  font-size: 18px;
+  line-height: 28px;
+}
+.data-export .learn-more-container{
+  padding-bottom: 56px;
+  text-align: center;
+}
+
+.data-export .export-case{
+  width: 100%;
+  height: 480px;
+  background: #fff;
+  border-radius: 16px;
+  box-shadow: 0 4px 24px 0px rgba(2, 52, 128, 0.1); 
+}
+.data-export .export-case .case-title{
+  padding: 28px 0 32px;
+  color: #1D1D1D;
+  font-size: 20px;
+  line-height: 32px;
+  text-align: center;
+}
+.data-export .export-case .case-container{
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+}
+.data-export .case-container .case-item{
+  flex: 1;
+  display: flex;
+  padding: 32px 32px 28px;
+  flex-direction: column;
+  align-items: center;
+  border-right: 1px solid #ECECEC;
+  border-bottom: 1px solid #ECECEC;
+}
+.data-export .case-container .case-item:nth-child(n+5) {
+  border-bottom: 0;
+}
+.data-export .case-container .case-item:nth-child(4n) {
+  border-right: 0;
+}
+.data-export .case-item > img{
+  width: 180px;
+  height: 50px;
+}
+.data-export .case-item > p{
+  margin-top: 8px;
+  font-size: 16px;
+  line-height: 24px;
+  color: #1D1D1D;
+}
+
+.page--datamarket-index .data-scene{
+  width: 100%;
+  height: 554px;
+  background: url(/dataSmt/images/data-application-bg.png) no-repeat center center;
+  background-size: cover;
+}
+
+.data-scene .scene-title{
+  padding-top: 72px;
+  font-size: 32px;
+  line-height: 42px;
+  color: #fff;
+  text-align: center;
+}
+.data-scene .scene-container{
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-top: 56px;
+}
+.data-scene .scene-item{
+  width: 282px;
+  height: 208px;
+  padding: 32px;
+  border-radius: 12px;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+}
+.data-scene .scene-item > h4{
+  color: #1D1D1D;
+  font-size: 20px;
+  line-height: 32px;
+}
+.data-scene .scene-item > p{
+  margin-top: 16px;
+  color: #686868;
+  font-size: 14px;
+  line-height: 22px;
+}
+.data-scene .scene-item:nth-child(1){
+  background-image: url(/dataSmt/images/scene-item-1.png);
+}
+.data-scene .scene-item:nth-child(2){
+  background-image: url(/dataSmt/images/scene-item-2.png);
+}
+.data-scene .scene-item:nth-child(3){
+  background-image: url(/dataSmt/images/scene-item-3.png);
+}
+.data-scene .scene-item:nth-child(4){
+  background-image: url(/dataSmt/images/scene-item-4.png);
+}
+.data-scene .scene-btn{
+  width: 240px;
+  height: 48px;
+  line-height: 48px;
+  margin: 48px auto 0;
+  background-color: #fff;
+  border-radius: 8px;
+  text-align: center;
+  cursor: pointer;
+}
+
+.data-scene .scene-btn > span{
+  background-image: linear-gradient(#33CCCC, #3399FF);
+  -webkit-background-clip: text;
+  color: transparent;
+  font-size: 20px;
+}
+
+.btn-light{
+  position: relative;
+  display: inline-block;
+  width: 132px;
+  height: 36px;
+  margin-top: 16px;
+  line-height: 36px;
+  background: linear-gradient(to right,#2ABED1, #3687FF);
+  border-radius: 6px;
+  color: #fff;
+  font-size: 16px;
+  text-align: center;
+  text-decoration: none;
+  overflow: hidden;
+  cursor: pointer;
+}
+.btn-light:hover,
+.btn-light:active,
+.btn-light:visited,
+.btn-light:focus{
+  color: #fff;
+  text-decoration: none;
+}
+.btn-light::after {
+  content: '';
+  display: block;
+  position: absolute;
+  top: -120px;
+  left: -80px;
+  width: 36px;
+  height: 360px;
+  background: #fff;
+  opacity: 0.16;
+  transform: rotate(-45deg);
+  transition: all 800ms ease-out;
+}
+
+.btn-light:hover::after {
+  left: 200%;
+}
+
+@keyframes CfadeInUp {
+  from {
+    transform: translateY(50px);
+  }
+
+  to {
+    transform: translateY(0px);
+    opacity: 1;
+  }
+}
+
+.CfadeInUp {
+  /* opacity: 0; */
+  animation: 1s ease forwards alternate;
+}

二进制
src/web/staticres/dataSmt/images/case-ccscc.png


二进制
src/web/staticres/dataSmt/images/case-cec.png


二进制
src/web/staticres/dataSmt/images/case-langchao.png


二进制
src/web/staticres/dataSmt/images/case-liantong.png


二进制
src/web/staticres/dataSmt/images/case-minsheng.png


二进制
src/web/staticres/dataSmt/images/case-ruijie.png


二进制
src/web/staticres/dataSmt/images/case-siemens.png


二进制
src/web/staticres/dataSmt/images/case-soft.png


部分文件因为文件数量过多而无法显示