lianbingjie 2 vuotta sitten
vanhempi
commit
6d259d37a7
47 muutettua tiedostoa jossa 3234 lisäystä ja 1858 poistoa
  1. 34 18
      jyBXBase/api/bxbase.api
  2. 22 18
      jyBXBase/api/internal/logic/addSearchScreenLogic.go
  3. 21 17
      jyBXBase/api/internal/logic/checkSearchScreenLogic.go
  4. 33 18
      jyBXBase/api/internal/types/types.go
  5. 90 0
      jyBXBase/api/test/apitest.http
  6. 11 0
      jyBXBase/api/test/http-client.env.json
  7. 4 0
      jyBXBase/entity/db.go
  8. 31 4
      jyBXBase/rpc/bxbase.proto
  9. 3 0
      jyBXBase/rpc/bxbase/bxbase.go
  10. 15 2
      jyBXBase/rpc/internal/logic/addsearchlogic.go
  11. 19 5
      jyBXBase/rpc/internal/logic/checksearchlogic.go
  12. 4 1
      jyBXBase/rpc/internal/logic/showsearchlogic.go
  13. 573 254
      jyBXBase/rpc/type/bxbase/bxbase.pb.go
  14. 1 1
      jyBXBase/rpc/type/bxbase/bxbase_grpc.pb.go
  15. 7 3
      jyBXBase/rpc/util/common.go
  16. 28 19
      jyBXCore/api/bxcore.api
  17. 29 22
      jyBXCore/api/internal/logic/searchListLogic.go
  18. 28 19
      jyBXCore/api/internal/types/types.go
  19. 1 2
      jyBXCore/go.mod
  20. 4 2
      jyBXCore/go.sum
  21. 1 1
      jyBXCore/rpc/bxcore.go
  22. 86 61
      jyBXCore/rpc/bxcore.proto
  23. 266 0
      jyBXCore/rpc/entity/search.go
  24. 13 4
      jyBXCore/rpc/etc/bxcore.yaml
  25. 1 0
      jyBXCore/rpc/etc/db.yaml
  26. 1 1
      jyBXCore/rpc/init/label.go
  27. 17 9
      jyBXCore/rpc/internal/config/config.go
  28. 47 168
      jyBXCore/rpc/internal/logic/getsearchlistlogic.go
  29. 1 1
      jyBXCore/rpc/internal/logic/searchlimitlogic.go
  30. 2 2
      jyBXCore/rpc/internal/server/bxcoreserver.go
  31. 46 15
      jyBXCore/rpc/model/es/es.go
  32. 325 0
      jyBXCore/rpc/model/es/search.go
  33. 0 300
      jyBXCore/rpc/model/es/searchQuery.go
  34. 53 0
      jyBXCore/rpc/service/search.go
  35. 528 266
      jyBXCore/rpc/type/bxcore/bxcore.pb.go
  36. 178 523
      jyBXCore/rpc/util/search.go
  37. 29 19
      jyBXCore/rpc/util/userInfo.go
  38. 24 0
      jyBXSubscribe/api/test/apitest.http
  39. 19 2
      jyBXSubscribe/rpc/bxsubscribe.proto
  40. 1 0
      jyBXSubscribe/rpc/bxsubscribe/bxsubscribe.go
  41. 27 0
      jyBXSubscribe/rpc/internal/logic/bypushhistorylogic.go
  42. 11 0
      jyBXSubscribe/rpc/internal/logic/getsublistlogic.go
  43. 1 1
      jyBXSubscribe/rpc/internal/logic/msgdistributorlogic.go
  44. 47 9
      jyBXSubscribe/rpc/model/push.go
  45. 493 71
      jyBXSubscribe/rpc/type/bxsubscribe/bxsubscribe.pb.go
  46. 6 0
      jyBXSubscribe/rpc/type/bxsubscribe/bxsubscribe_grpc.pb.go
  47. 53 0
      jyBXSubscribe/rpc/util/util.go

+ 34 - 18
jyBXBase/api/bxbase.api

@@ -69,24 +69,28 @@ type (
 
 	//保存筛选条件
 	AddSearchScreen {
-		UserId       string `header:"userId"`
-		AppId        string `header:"appId"` //appId
-		Type         string `header:"type,optional"`
-		Keywords     string `json:"searchvalue"`         //搜索词
-		Publishtime  string `json:"publishtime"`         //发布时间
-		City         string `json:"city,optional"`       //城市
-		Area         string `json:"area,optional"`       //地区
-		Subtype      string `json:"subtype,optional"`    //信息类型
-		Minprice     string `json:"minprice,optional"`   //最低价格
-		Maxprice     string `json:"maxprice,optional"`   //最高价格
-		Industry     string `json:"industry,optional"`   //选中的行业
-		SelectType   string `json:"selectType"`          //标题 or 全文
-		Buyerclass   string `json:"buyerclass,optional"` //采购单位行业
-		Hasbuyertel  string `json:"buyertel,optional"`   //是否有采购电话
-		Haswinnertel string `json:"winnertel,optional"`  //是否有中标电话
-		FileExists   string `json:"fileExists,optional"` //附件
-		Notkey       string `json:"notkey,optional"`     //排除词
-		InKey        string `json:"inkey,optional"`
+		UserId          string `header:"userId"`
+		AppId           string `header:"appId"` //appId
+		Type            string `header:"type,optional"`
+		Keywords        string `json:"searchvalue,optional"` //搜索词
+		Publishtime     string `json:"publishtime"`          //发布时间
+		City            string `json:"city,optional"`        //城市
+		Area            string `json:"area,optional"`        //地区
+		Subtype         string `json:"subtype,optional"`     //信息类型
+		Minprice        string `json:"minprice,optional"`    //最低价格
+		Maxprice        string `json:"maxprice,optional"`    //最高价格
+		Industry        string `json:"industry,optional"`    //选中的行业
+		SelectType      string `json:"selectType"`           //标题 or 全文
+		Buyerclass      string `json:"buyerclass,optional"`  //采购单位行业
+		Hasbuyertel     string `json:"buyertel,optional"`    //是否有采购电话
+		Haswinnertel    string `json:"winnertel,optional"`   //是否有中标电话
+		FileExists      string `json:"fileExists,optional"`  //附件
+		Notkey          string `json:"notkey,optional"`      //排除词 关键词:排除词(副:五组,每组最多15个字符)
+		InKey           string `json:"inkey,optional"`
+		SearchGroup     int    `json:"searchGroup,optional"`     // 搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+		SearchMode      int    `json:"searchMode,optional"`      // 搜索模式:0:精准搜索;1:模糊搜索
+		WordsMode       int    `json:"wordsMode,optional"`       // 搜索关键词模式;默认0:包含所有,1:包含任意
+		AdditionalWords string `json:"additionalWords,optional"` // 关键词:附加关键词(副:五组,每组最多15个字符)
 	}
 	//首页最新招标信息
 	NewestReq {
@@ -109,6 +113,17 @@ type (
 	IncludedReq {
 		AppId string `header:"appId,default=10000"`
 	}
+	// 保存搜索/订阅 列表模式入参
+	SaveListModeReq {
+		UserId string `header:"userId"`
+		Type   string `path:"type,options=search|subscribe"` // search 搜索列表  subscribe 订阅列表
+		Mode   int    `json:"mode"`                          // 0-精简列表 1-详细列表
+	}
+	// 获取获取搜索/订阅
+	ShowListModeReq {
+		UserId string `header:"userId"`
+		Type   string `path:"type,options=search|subscribe"` // search 搜索列表  subscribe 订阅列表
+	}
 )
 
 service bxbase-api {
@@ -151,4 +166,5 @@ service bxbase-api {
 	@doc "收录情况"
 	@handler Included
 	post /jybx/base/included (IncludedReq) returns(CommonRes)
+	
 }

+ 22 - 18
jyBXBase/api/internal/logic/addSearchScreenLogic.go

@@ -30,24 +30,28 @@ func NewAddSearchScreenLogic(ctx context.Context, svcCtx *svc.ServiceContext, r
 
 func (l *AddSearchScreenLogic) AddSearchScreen(req *types.AddSearchScreen) (resp *types.CommonRes, err error) {
 	res, err0 := l.svcCtx.Bxbase.AddSearch(l.ctx, &bxbase.AddSearchReq{
-		UserId:       req.UserId,
-		Type:         req.Type,
-		Keywords:     req.Keywords,
-		PublishTime:  req.Publishtime,
-		City:         req.City,
-		Area:         req.Area,
-		Subtype:      req.Subtype,
-		MinPrice:     req.Minprice,
-		MaxPrice:     req.Maxprice,
-		Industry:     req.Industry,
-		SelectType:   req.SelectType,
-		BuyerClass:   req.Buyerclass,
-		HasBuyerTel:  req.Hasbuyertel,
-		HasWinnerTel: req.Haswinnertel,
-		FileExists:   req.FileExists,
-		NotKey:       req.Notkey,
-		InKey:        req.InKey,
-		AppId:        req.AppId,
+		UserId:          req.UserId,
+		Type:            req.Type,
+		Keywords:        req.Keywords,
+		PublishTime:     req.Publishtime,
+		City:            req.City,
+		Area:            req.Area,
+		Subtype:         req.Subtype,
+		MinPrice:        req.Minprice,
+		MaxPrice:        req.Maxprice,
+		Industry:        req.Industry,
+		SelectType:      req.SelectType,
+		BuyerClass:      req.Buyerclass,
+		HasBuyerTel:     req.Hasbuyertel,
+		HasWinnerTel:    req.Haswinnertel,
+		FileExists:      req.FileExists,
+		NotKey:          req.Notkey,
+		InKey:           req.InKey,
+		AppId:           req.AppId,
+		SearchGroup:     int64(req.SearchGroup),
+		SearchMode:      int64(req.SearchMode),
+		WordsMode:       int64(req.WordsMode),
+		AdditionalWords: req.AdditionalWords,
 	})
 	if err0 != nil {
 		return &types.CommonRes{

+ 21 - 17
jyBXBase/api/internal/logic/checkSearchScreenLogic.go

@@ -30,23 +30,27 @@ func NewCheckSearchScreenLogic(ctx context.Context, svcCtx *svc.ServiceContext,
 
 func (l *CheckSearchScreenLogic) CheckSearchScreen(req *types.AddSearchScreen) (resp *types.CommonRes, err error) {
 	res, err0 := l.svcCtx.Bxbase.CheckSearch(l.ctx, &bxbase.AddSearchReq{
-		UserId:       req.UserId,
-		Type:         req.Type,
-		Keywords:     req.Keywords,
-		PublishTime:  req.Publishtime,
-		Area:         req.Area,
-		City:         req.City,
-		Subtype:      req.Subtype,
-		MinPrice:     req.Minprice,
-		MaxPrice:     req.Maxprice,
-		Industry:     req.Industry,
-		SelectType:   req.SelectType,
-		BuyerClass:   req.Buyerclass,
-		HasBuyerTel:  req.Hasbuyertel,
-		HasWinnerTel: req.Haswinnertel,
-		FileExists:   req.FileExists,
-		NotKey:       req.Notkey,
-		AppId:        req.AppId,
+		UserId:          req.UserId,
+		Type:            req.Type,
+		Keywords:        req.Keywords,
+		PublishTime:     req.Publishtime,
+		Area:            req.Area,
+		City:            req.City,
+		Subtype:         req.Subtype,
+		MinPrice:        req.Minprice,
+		MaxPrice:        req.Maxprice,
+		Industry:        req.Industry,
+		SelectType:      req.SelectType,
+		BuyerClass:      req.Buyerclass,
+		HasBuyerTel:     req.Hasbuyertel,
+		HasWinnerTel:    req.Haswinnertel,
+		FileExists:      req.FileExists,
+		NotKey:          req.Notkey,
+		AppId:           req.AppId,
+		SearchGroup:     int64(req.SearchGroup),
+		SearchMode:      int64(req.SearchMode),
+		WordsMode:       int64(req.WordsMode),
+		AdditionalWords: req.AdditionalWords,
 	})
 	if err0 != nil {
 		return &types.CommonRes{

+ 33 - 18
jyBXBase/api/internal/types/types.go

@@ -60,24 +60,28 @@ type DelSearchScreen struct {
 }
 
 type AddSearchScreen struct {
-	UserId       string `header:"userId"`
-	AppId        string `header:"appId"` //appId
-	Type         string `header:"type,optional"`
-	Keywords     string `json:"searchvalue"`         //搜索词
-	Publishtime  string `json:"publishtime"`         //发布时间
-	City         string `json:"city,optional"`       //城市
-	Area         string `json:"area,optional"`       //地区
-	Subtype      string `json:"subtype,optional"`    //信息类型
-	Minprice     string `json:"minprice,optional"`   //最低价格
-	Maxprice     string `json:"maxprice,optional"`   //最高价格
-	Industry     string `json:"industry,optional"`   //选中的行业
-	SelectType   string `json:"selectType"`          //标题 or 全文
-	Buyerclass   string `json:"buyerclass,optional"` //采购单位行业
-	Hasbuyertel  string `json:"buyertel,optional"`   //是否有采购电话
-	Haswinnertel string `json:"winnertel,optional"`  //是否有中标电话
-	FileExists   string `json:"fileExists,optional"` //附件
-	Notkey       string `json:"notkey,optional"`     //排除词
-	InKey        string `json:"inkey,optional"`
+	UserId          string `header:"userId"`
+	AppId           string `header:"appId"` //appId
+	Type            string `header:"type,optional"`
+	Keywords        string `json:"searchvalue,optional"` //搜索词
+	Publishtime     string `json:"publishtime"`          //发布时间
+	City            string `json:"city,optional"`        //城市
+	Area            string `json:"area,optional"`        //地区
+	Subtype         string `json:"subtype,optional"`     //信息类型
+	Minprice        string `json:"minprice,optional"`    //最低价格
+	Maxprice        string `json:"maxprice,optional"`    //最高价格
+	Industry        string `json:"industry,optional"`    //选中的行业
+	SelectType      string `json:"selectType"`           //标题 or 全文
+	Buyerclass      string `json:"buyerclass,optional"`  //采购单位行业
+	Hasbuyertel     string `json:"buyertel,optional"`    //是否有采购电话
+	Haswinnertel    string `json:"winnertel,optional"`   //是否有中标电话
+	FileExists      string `json:"fileExists,optional"`  //附件
+	Notkey          string `json:"notkey,optional"`      //排除词 关键词:排除词(副:五组,每组最多15个字符)
+	InKey           string `json:"inkey,optional"`
+	SearchGroup     int    `json:"searchGroup,optional"`     // 搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+	SearchMode      int    `json:"searchMode,optional"`      // 搜索模式:0:精准搜索;1:模糊搜索
+	WordsMode       int    `json:"wordsMode,optional"`       // 搜索关键词模式;默认0:包含所有,1:包含任意
+	AdditionalWords string `json:"additionalWords,optional"` // 关键词:附加关键词(副:五组,每组最多15个字符)
 }
 
 type NewestReq struct {
@@ -99,3 +103,14 @@ type CommonRes struct {
 type IncludedReq struct {
 	AppId string `header:"appId,default=10000"`
 }
+
+type SaveListModeReq struct {
+	UserId string `header:"userId"`
+	Type   string `path:"type,options=search|subscribe"` // search 搜索列表  subscribe 订阅列表
+	Mode   int    `json:"mode"`                          // 0-精简列表 1-详细列表
+}
+
+type ShowListModeReq struct {
+	UserId string `header:"userId"`
+	Type   string `path:"type,options=search|subscribe"` // search 搜索列表  subscribe 订阅列表
+}

+ 90 - 0
jyBXBase/api/test/apitest.http

@@ -0,0 +1,90 @@
+// 接口测试用例
+
+### 搜索/订阅 列表模式保存
+POST http://{{addr}}/jybx/base/subscribe/saveListMode
+Content-Type: application/json
+UserId:test20130110
+
+{
+  "mode": 1
+}
+
+### 搜索/订阅 列表模式获取
+POST http://{{ addr }}/jybx/base/subscribe/showListMode
+Content-Type: application/json
+UserId:test20130110
+
+
+
+### 校验筛选条件是否重复保存
+POST http://{{addr}}/jybx/base/checkSearchScreen
+Content-Type: application/json
+UserId:test20130110
+appId:10000
+
+{
+  "searchvalue": "景山公园 天坛 地坛 陶然亭 颐和园",
+  "selectType": "content,title,buyer",
+  "industry": "建筑工程_材料设备,建筑工程_工程施工,建筑工程_勘察设计,建筑工程_监理咨询,建筑工程_机电安装",
+  "minprice": "",
+  "maxprice": "",
+  "publishtime": "fiveyear",
+  "subtype": "",
+  "buyerclass": "交通",
+  "buyertel": "y",
+  "winnertel": "y",
+  "notkey": "医院",
+  "fileExists": "0",
+  "area": "北京",
+  "city": "",
+  "searchGroup": "0",
+  "searchMode": "1",
+  "wordsMode": "1",
+  "additionalWords": "九龙山 医院 "
+}
+### 筛选条件保存
+POST http://{{addr}}/jybx/base/addSearchScreen
+Content-Type: application/json
+Cookie: SESSIONID=4b0dfa144d8cfa0c899e7281ff00656291d621db
+
+{
+  "searchvalue": "景山公园 天坛 地坛 陶然亭 颐和园",
+  "selectType": "content,title,buyer",
+  "industry": "建筑工程_材料设备,建筑工程_工程施工,建筑工程_勘察设计,建筑工程_监理咨询,建筑工程_机电安装",
+  "minprice": "",
+  "maxprice": "",
+  "publishtime": "fiveyear",
+  "subtype": "",
+  "buyerclass": "交通",
+  "buyertel": "y",
+  "winnertel": "y",
+  "notkey": "医院",
+  "fileExists": "0",
+  "area": "北京",
+  "city": "",
+  "inkey": "742c4bce4303dffdaa8ce3c0b99ee814",
+  "searchGroup": "0",
+  "searchMode": "0",
+  "wordsMode": "1",
+  "additionalWords": "九龙山 医院"
+}
+
+
+
+### 查看已保存的筛选条件
+POST http://{{addr}}/jybx/base/showSearchScreen
+Content-Type: application/json
+Cookie: SESSIONID=4b0dfa144d8cfa0c899e7281ff00656291d621db
+
+
+
+### 删除已保存的筛选条件
+POST http://{{addr}}/jybx/base/delSearchScreen
+Content-Type: application/json
+UserId:test20130110
+appId:10000
+
+{
+"id": "63bcfd44d2d550dfc36773dd"
+}
+

+ 11 - 0
jyBXBase/api/test/http-client.env.json

@@ -0,0 +1,11 @@
+{
+  "240dev": {
+    "addr": "192.168.3.240:8006"
+  },
+  "frontProxy240": {
+    "addr": "192.168.3.240:8077"
+  },
+  "local": {
+    "addr": "127.0.0.1:8006"
+  }
+}

+ 4 - 0
jyBXBase/entity/db.go

@@ -48,3 +48,7 @@ type EsStruct struct {
 	Addr string `json:"addr"`
 	Size int    `json:"size"`
 }
+
+const (
+	ListModeCollection = "list_mode" // 搜索/订阅 列表模式 集合
+)

+ 31 - 4
jyBXBase/rpc/bxbase.proto

@@ -136,12 +136,16 @@ message ListSearchRes{
   string id = 17;
   bool isPay = 18;
   string tabularflag = 19;
+  int64  searchGroup = 20;//搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+  int64  searchMode = 21;//搜索模式:0:精准搜索;1:模糊搜索
+  int64  wordsMode = 22;// 搜索关键词模式;默认0:包含所有,1:包含任意
+  string additionalWords = 23;//关键词:附加关键词(副:五组,每组最多15个字符)
 }
 
 message AddSearchReq{
   string userId = 1;
   string type = 2;
-  string keywords = 3;     //搜索词
+  string keywords = 3;     //搜索词 关键词:多个空格隔开(主)
   string publishTime = 4;   //发布时间
   string area = 5;       //地区
   string subtype = 6;    //信息类型
@@ -153,10 +157,14 @@ message AddSearchReq{
   string hasBuyerTel = 12;//是否有采购电话
   string hasWinnerTel = 13;//是否有中标电话
   string fileExists = 14;//附件
-  string notKey = 15;//排除词
-  string  city = 16;
+  string notKey = 15;//关键词:排除词(副:五组,每组最多15个字符)
+  string city = 16;
   string inKey = 17;
-  string  appId = 18;
+  string appId = 18;
+  int64  searchGroup = 19;//搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+  int64  searchMode = 20;//搜索模式:0:精准搜索;1:模糊搜索
+  int64  wordsMode = 21;// 搜索关键词模式;默认0:包含所有,1:包含任意
+  string additionalWords = 22;//关键词:附加关键词(副:五组,每组最多15个字符)
 }
 
 message DelSearchReq{
@@ -262,6 +270,23 @@ message IncludedResp{
 	int64 error_code = 29;
 }
 
+// 搜索订阅列表模式保存
+message SaveListModeReq{
+  string UserId = 1; // 用户id
+  string Type = 2 ; // 类型 search-搜索列表 subscribe-订阅列表
+  int64  Mode = 3;  // 列表模式 0-精简模式 1-详细模式
+}
+// 搜索订阅列表模式获取
+message ShowListModeReq{
+  string UserId = 1; // 用户id
+  string Type = 2 ; // 类型 search-搜索列表 subscribe-订阅列表
+}
+// 搜索订阅列表模式获取结果
+message ShowListModeRes{
+  int64 err_code = 1;
+  string err_msg = 2;
+  int64 data = 3;
+}
 //servie
 service bxbase {
   //新增标签
@@ -291,4 +316,6 @@ service bxbase {
 
   //剑鱼网站收录情况
   rpc Included (AppIdReq) returns(IncludedResp);
+
+
 }

+ 3 - 0
jyBXBase/rpc/bxbase/bxbase.go

@@ -40,6 +40,9 @@ type (
 	NewestList        = bxbase.NewestList
 	NewsetBidding     = bxbase.NewsetBidding
 	NewsetBiddingResp = bxbase.NewsetBiddingResp
+	SaveListModeReq   = bxbase.SaveListModeReq
+	ShowListModeReq   = bxbase.ShowListModeReq
+	ShowListModeRes   = bxbase.ShowListModeRes
 	ShowSearchReq     = bxbase.ShowSearchReq
 	ShowSearchRes     = bxbase.ShowSearchRes
 

+ 15 - 2
jyBXBase/rpc/internal/logic/addsearchlogic.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"jyBXBase/rpc/bxbase"
 	IC "jyBXBase/rpc/init"
+	"jyBXBase/rpc/util"
 	"log"
 	"strings"
 	"time"
@@ -29,7 +30,6 @@ func NewAddSearchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddSear
 
 // 添加搜索列表
 func (l *AddSearchLogic) AddSearch(in *bxbase.AddSearchReq) (res *bxbase.CommonRes, err error) {
-	// todo: add your logic here and delete this line
 	res = new(bxbase.CommonRes)
 	newData := make(map[string]interface{})
 	if in.UserId == "" {
@@ -43,8 +43,17 @@ func (l *AddSearchLogic) AddSearch(in *bxbase.AddSearchReq) (res *bxbase.CommonR
 		return
 	}
 	log.Println("添加搜索列表:", in)
-	in.NotKey = strings.Replace(in.NotKey, " ", ",", -1)
 	in.Keywords = strings.Replace(in.Keywords, " ", ",", -1)
+	switch in.SearchGroup {
+	case util.SearchGroupBidding:
+		if ValueSort(util.TopTypesBidding) == in.Subtype {
+			in.Subtype = ""
+		}
+	case util.SearchGroupLeadingProject:
+		if ValueSort(util.TopTypesLeadingProject) == in.Subtype {
+			in.Subtype = ""
+		}
+	}
 	newData["keywords"] = in.Keywords
 	newData["type"] = in.Type
 	newData["publish_time"] = in.PublishTime
@@ -63,6 +72,10 @@ func (l *AddSearchLogic) AddSearch(in *bxbase.AddSearchReq) (res *bxbase.CommonR
 	newData["creation_time"] = time.Now().Unix()
 	newData["user_id"] = in.UserId
 	newData["in_key"] = in.InKey
+	newData["searchGroup"] = in.SearchGroup
+	newData["searchMode"] = in.SearchMode
+	newData["wordsMode"] = in.WordsMode
+	newData["additionalWords"] = in.AdditionalWords
 	IC.Mgo.Save("search_condition", newData)
 	return
 }

+ 19 - 5
jyBXBase/rpc/internal/logic/checksearchlogic.go

@@ -7,6 +7,7 @@ import (
 	"crypto/md5"
 	"fmt"
 	IC "jyBXBase/rpc/init"
+	"jyBXBase/rpc/util"
 	"log"
 	"net/url"
 	"sort"
@@ -34,20 +35,18 @@ func NewCheckSearchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Check
 
 // 校验搜索列表
 func (l *CheckSearchLogic) CheckSearch(in *bxbase.AddSearchReq) (res *bxbase.CheckRes, err error) {
-	// todo: add your logic here and delete this line
 	res = new(bxbase.CheckRes)
 	if in.UserId == "" {
 		res.ErrCode = 1
 		res.ErrMsg = "用户未登录"
 		return
 	}
-	if in.Keywords == "" {
+	if in.Keywords == "" && in.AdditionalWords == "" && in.Industry == "" {
 		res.ErrCode = 1
-		res.ErrMsg = "请先输入关键词"
+		res.ErrMsg = "请先输入关键词或选择行业"
 		return
 	}
 	log.Println("校验搜索列表:", in)
-	in.NotKey = strings.Replace(in.NotKey, " ", ",", -1)
 	in.Keywords = strings.Replace(in.Keywords, " ", ",", -1)
 	query := map[string]interface{}{
 		"user_id": in.UserId,
@@ -65,8 +64,23 @@ func (l *CheckSearchLogic) CheckSearch(in *bxbase.AddSearchReq) (res *bxbase.Che
 	in.SelectType = ValueSort(in.SelectType)
 	in.BuyerClass = ValueSort(in.BuyerClass)
 	in.NotKey = ValueSort(in.NotKey)
+	in.AdditionalWords = ValueSort(in.AdditionalWords)
+	// 搜索分组为 1-招标采购公告时 2 超前项目
+	// 当所选择的信息类型是全选时,需要处理成和全部时一样的空串
+	switch in.SearchGroup {
+	case util.SearchGroupBidding:
+		if ValueSort(util.TopTypesBidding) == in.Subtype {
+			in.Subtype = ""
+		}
+	case util.SearchGroupLeadingProject:
+		if ValueSort(util.TopTypesLeadingProject) == in.Subtype {
+			in.Subtype = ""
+		}
+	}
+
 	inMap := common.StructToMapMore(in)
 	inKey := GetKeysByParam(inMap)
+
 	query["in_key"] = inKey
 	res.Data = inKey
 	if IC.Mgo.Count("search_condition", query) > 0 {
@@ -88,7 +102,7 @@ func GetKeysByParam(param map[string]interface{}) string {
 	ps := &paramSorter{[]string{}, []string{}}
 	for k, v := range param {
 		ps.Keys = append(ps.Keys, k)
-		ps.Values = append(ps.Values, common.ObjToString(v))
+		ps.Values = append(ps.Values, common.InterfaceToStr(v))
 	}
 	ps.Sort()
 	reqStr := ps.String()

+ 4 - 1
jyBXBase/rpc/internal/logic/showsearchlogic.go

@@ -27,7 +27,6 @@ func NewShowSearchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ShowSe
 
 // 获取收藏列表
 func (l *ShowSearchLogic) ShowSearch(in *bxbase.ShowSearchReq) (res *bxbase.ShowSearchRes, err error) {
-	// todo: add your logic here and delete this line
 	var (
 		data  []*bxbase.ListSearchRes
 		isOld bool
@@ -77,6 +76,10 @@ func (l *ShowSearchLogic) ShowSearch(in *bxbase.ShowSearchReq) (res *bxbase.Show
 			listSearch.FileExists = common.InterfaceToStr(vlu["file_exists"])
 			listSearch.Notkey = common.InterfaceToStr(vlu["not_key"])
 			listSearch.Tabularflag = common.InterfaceToStr(vlu["tabular_flag"])
+			listSearch.SearchGroup = common.Int64All(vlu["searchGroup"])
+			listSearch.SearchMode = common.Int64All(vlu["searchMode"])
+			listSearch.WordsMode = common.Int64All(vlu["wordsMode"])
+			listSearch.AdditionalWords = common.InterfaceToStr(vlu["additionalWords"])
 			//ppa,buyer,winner,agency
 			if SelectCheck(listSearch.SelectType, isOld) || listSearch.City != "" || listSearch.Notkey != "" ||
 				(listSearch.Publishtime != "lately-7" && listSearch.Publishtime != "lately-30" && listSearch.Publishtime != "thisyear") ||

+ 573 - 254
jyBXBase/rpc/type/bxbase/bxbase.pb.go

@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
 // 	protoc-gen-go v1.28.0
-// 	protoc        v3.15.1
+// 	protoc        v3.19.4
 // source: bxbase.proto
 
 package bxbase
@@ -1319,25 +1319,29 @@ type ListSearchRes struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	UserId      string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"`
-	Type        string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
-	Searchvalue string `protobuf:"bytes,3,opt,name=searchvalue,proto3" json:"searchvalue,omitempty"` //搜索词
-	Publishtime string `protobuf:"bytes,4,opt,name=publishtime,proto3" json:"publishtime,omitempty"` //发布时间
-	Area        string `protobuf:"bytes,5,opt,name=area,proto3" json:"area,omitempty"`               //地区
-	Subtype     string `protobuf:"bytes,6,opt,name=subtype,proto3" json:"subtype,omitempty"`         //信息类型
-	Minprice    string `protobuf:"bytes,7,opt,name=minprice,proto3" json:"minprice,omitempty"`       //最低价格
-	Maxprice    string `protobuf:"bytes,8,opt,name=maxprice,proto3" json:"maxprice,omitempty"`       //最高价格
-	Industry    string `protobuf:"bytes,9,opt,name=industry,proto3" json:"industry,omitempty"`       //选中的行业
-	SelectType  string `protobuf:"bytes,10,opt,name=selectType,proto3" json:"selectType,omitempty"`  //标题 or 全文
-	Buyerclass  string `protobuf:"bytes,11,opt,name=buyerclass,proto3" json:"buyerclass,omitempty"`  //采购单位行业
-	Buyertel    string `protobuf:"bytes,12,opt,name=buyertel,proto3" json:"buyertel,omitempty"`      //是否有采购电话
-	Winnertel   string `protobuf:"bytes,13,opt,name=winnertel,proto3" json:"winnertel,omitempty"`    //是否有中标电话
-	FileExists  string `protobuf:"bytes,14,opt,name=fileExists,proto3" json:"fileExists,omitempty"`  //附件
-	Notkey      string `protobuf:"bytes,15,opt,name=notkey,proto3" json:"notkey,omitempty"`          //排除词
-	City        string `protobuf:"bytes,16,opt,name=city,proto3" json:"city,omitempty"`
-	Id          string `protobuf:"bytes,17,opt,name=id,proto3" json:"id,omitempty"`
-	IsPay       bool   `protobuf:"varint,18,opt,name=isPay,proto3" json:"isPay,omitempty"`
-	Tabularflag string `protobuf:"bytes,19,opt,name=tabularflag,proto3" json:"tabularflag,omitempty"`
+	UserId          string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"`
+	Type            string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+	Searchvalue     string `protobuf:"bytes,3,opt,name=searchvalue,proto3" json:"searchvalue,omitempty"` //搜索词
+	Publishtime     string `protobuf:"bytes,4,opt,name=publishtime,proto3" json:"publishtime,omitempty"` //发布时间
+	Area            string `protobuf:"bytes,5,opt,name=area,proto3" json:"area,omitempty"`               //地区
+	Subtype         string `protobuf:"bytes,6,opt,name=subtype,proto3" json:"subtype,omitempty"`         //信息类型
+	Minprice        string `protobuf:"bytes,7,opt,name=minprice,proto3" json:"minprice,omitempty"`       //最低价格
+	Maxprice        string `protobuf:"bytes,8,opt,name=maxprice,proto3" json:"maxprice,omitempty"`       //最高价格
+	Industry        string `protobuf:"bytes,9,opt,name=industry,proto3" json:"industry,omitempty"`       //选中的行业
+	SelectType      string `protobuf:"bytes,10,opt,name=selectType,proto3" json:"selectType,omitempty"`  //标题 or 全文
+	Buyerclass      string `protobuf:"bytes,11,opt,name=buyerclass,proto3" json:"buyerclass,omitempty"`  //采购单位行业
+	Buyertel        string `protobuf:"bytes,12,opt,name=buyertel,proto3" json:"buyertel,omitempty"`      //是否有采购电话
+	Winnertel       string `protobuf:"bytes,13,opt,name=winnertel,proto3" json:"winnertel,omitempty"`    //是否有中标电话
+	FileExists      string `protobuf:"bytes,14,opt,name=fileExists,proto3" json:"fileExists,omitempty"`  //附件
+	Notkey          string `protobuf:"bytes,15,opt,name=notkey,proto3" json:"notkey,omitempty"`          //排除词
+	City            string `protobuf:"bytes,16,opt,name=city,proto3" json:"city,omitempty"`
+	Id              string `protobuf:"bytes,17,opt,name=id,proto3" json:"id,omitempty"`
+	IsPay           bool   `protobuf:"varint,18,opt,name=isPay,proto3" json:"isPay,omitempty"`
+	Tabularflag     string `protobuf:"bytes,19,opt,name=tabularflag,proto3" json:"tabularflag,omitempty"`
+	SearchGroup     int64  `protobuf:"varint,20,opt,name=searchGroup,proto3" json:"searchGroup,omitempty"`        //搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+	SearchMode      int64  `protobuf:"varint,21,opt,name=searchMode,proto3" json:"searchMode,omitempty"`          //搜索模式:0:精准搜索;1:模糊搜索
+	WordsMode       int64  `protobuf:"varint,22,opt,name=wordsMode,proto3" json:"wordsMode,omitempty"`            // 搜索关键词模式;默认0:包含所有,1:包含任意
+	AdditionalWords string `protobuf:"bytes,23,opt,name=additionalWords,proto3" json:"additionalWords,omitempty"` //关键词:附加关键词(副:五组,每组最多15个字符)
 }
 
 func (x *ListSearchRes) Reset() {
@@ -1505,29 +1509,61 @@ func (x *ListSearchRes) GetTabularflag() string {
 	return ""
 }
 
+func (x *ListSearchRes) GetSearchGroup() int64 {
+	if x != nil {
+		return x.SearchGroup
+	}
+	return 0
+}
+
+func (x *ListSearchRes) GetSearchMode() int64 {
+	if x != nil {
+		return x.SearchMode
+	}
+	return 0
+}
+
+func (x *ListSearchRes) GetWordsMode() int64 {
+	if x != nil {
+		return x.WordsMode
+	}
+	return 0
+}
+
+func (x *ListSearchRes) GetAdditionalWords() string {
+	if x != nil {
+		return x.AdditionalWords
+	}
+	return ""
+}
+
 type AddSearchReq struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	UserId       string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"`
-	Type         string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
-	Keywords     string `protobuf:"bytes,3,opt,name=keywords,proto3" json:"keywords,omitempty"`          //搜索词
-	PublishTime  string `protobuf:"bytes,4,opt,name=publishTime,proto3" json:"publishTime,omitempty"`    //发布时间
-	Area         string `protobuf:"bytes,5,opt,name=area,proto3" json:"area,omitempty"`                  //地区
-	Subtype      string `protobuf:"bytes,6,opt,name=subtype,proto3" json:"subtype,omitempty"`            //信息类型
-	MinPrice     string `protobuf:"bytes,7,opt,name=minPrice,proto3" json:"minPrice,omitempty"`          //最低价格
-	MaxPrice     string `protobuf:"bytes,8,opt,name=maxPrice,proto3" json:"maxPrice,omitempty"`          //最高价格
-	Industry     string `protobuf:"bytes,9,opt,name=industry,proto3" json:"industry,omitempty"`          //选中的行业
-	SelectType   string `protobuf:"bytes,10,opt,name=selectType,proto3" json:"selectType,omitempty"`     //标题 or 全文
-	BuyerClass   string `protobuf:"bytes,11,opt,name=buyerClass,proto3" json:"buyerClass,omitempty"`     //采购单位行业
-	HasBuyerTel  string `protobuf:"bytes,12,opt,name=hasBuyerTel,proto3" json:"hasBuyerTel,omitempty"`   //是否有采购电话
-	HasWinnerTel string `protobuf:"bytes,13,opt,name=hasWinnerTel,proto3" json:"hasWinnerTel,omitempty"` //是否有中标电话
-	FileExists   string `protobuf:"bytes,14,opt,name=fileExists,proto3" json:"fileExists,omitempty"`     //附件
-	NotKey       string `protobuf:"bytes,15,opt,name=notKey,proto3" json:"notKey,omitempty"`             //排除词
-	City         string `protobuf:"bytes,16,opt,name=city,proto3" json:"city,omitempty"`
-	InKey        string `protobuf:"bytes,17,opt,name=inKey,proto3" json:"inKey,omitempty"`
-	AppId        string `protobuf:"bytes,18,opt,name=appId,proto3" json:"appId,omitempty"`
+	UserId          string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"`
+	Type            string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+	Keywords        string `protobuf:"bytes,3,opt,name=keywords,proto3" json:"keywords,omitempty"`          //搜索词 关键词:多个空格隔开(主)
+	PublishTime     string `protobuf:"bytes,4,opt,name=publishTime,proto3" json:"publishTime,omitempty"`    //发布时间
+	Area            string `protobuf:"bytes,5,opt,name=area,proto3" json:"area,omitempty"`                  //地区
+	Subtype         string `protobuf:"bytes,6,opt,name=subtype,proto3" json:"subtype,omitempty"`            //信息类型
+	MinPrice        string `protobuf:"bytes,7,opt,name=minPrice,proto3" json:"minPrice,omitempty"`          //最低价格
+	MaxPrice        string `protobuf:"bytes,8,opt,name=maxPrice,proto3" json:"maxPrice,omitempty"`          //最高价格
+	Industry        string `protobuf:"bytes,9,opt,name=industry,proto3" json:"industry,omitempty"`          //选中的行业
+	SelectType      string `protobuf:"bytes,10,opt,name=selectType,proto3" json:"selectType,omitempty"`     //标题 or 全文
+	BuyerClass      string `protobuf:"bytes,11,opt,name=buyerClass,proto3" json:"buyerClass,omitempty"`     //采购单位行业
+	HasBuyerTel     string `protobuf:"bytes,12,opt,name=hasBuyerTel,proto3" json:"hasBuyerTel,omitempty"`   //是否有采购电话
+	HasWinnerTel    string `protobuf:"bytes,13,opt,name=hasWinnerTel,proto3" json:"hasWinnerTel,omitempty"` //是否有中标电话
+	FileExists      string `protobuf:"bytes,14,opt,name=fileExists,proto3" json:"fileExists,omitempty"`     //附件
+	NotKey          string `protobuf:"bytes,15,opt,name=notKey,proto3" json:"notKey,omitempty"`             //关键词:排除词(副:五组,每组最多15个字符)
+	City            string `protobuf:"bytes,16,opt,name=city,proto3" json:"city,omitempty"`
+	InKey           string `protobuf:"bytes,17,opt,name=inKey,proto3" json:"inKey,omitempty"`
+	AppId           string `protobuf:"bytes,18,opt,name=appId,proto3" json:"appId,omitempty"`
+	SearchGroup     int64  `protobuf:"varint,19,opt,name=searchGroup,proto3" json:"searchGroup,omitempty"`        //搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+	SearchMode      int64  `protobuf:"varint,20,opt,name=searchMode,proto3" json:"searchMode,omitempty"`          //搜索模式:0:精准搜索;1:模糊搜索
+	WordsMode       int64  `protobuf:"varint,21,opt,name=wordsMode,proto3" json:"wordsMode,omitempty"`            // 搜索关键词模式;默认0:包含所有,1:包含任意
+	AdditionalWords string `protobuf:"bytes,22,opt,name=additionalWords,proto3" json:"additionalWords,omitempty"` //关键词:附加关键词(副:五组,每组最多15个字符)
 }
 
 func (x *AddSearchReq) Reset() {
@@ -1688,6 +1724,34 @@ func (x *AddSearchReq) GetAppId() string {
 	return ""
 }
 
+func (x *AddSearchReq) GetSearchGroup() int64 {
+	if x != nil {
+		return x.SearchGroup
+	}
+	return 0
+}
+
+func (x *AddSearchReq) GetSearchMode() int64 {
+	if x != nil {
+		return x.SearchMode
+	}
+	return 0
+}
+
+func (x *AddSearchReq) GetWordsMode() int64 {
+	if x != nil {
+		return x.WordsMode
+	}
+	return 0
+}
+
+func (x *AddSearchReq) GetAdditionalWords() string {
+	if x != nil {
+		return x.AdditionalWords
+	}
+	return ""
+}
+
 type DelSearchReq struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -2612,6 +2676,190 @@ func (x *IncludedResp) GetErrorCode() int64 {
 	return 0
 }
 
+// 搜索订阅列表模式保存
+type SaveListModeReq struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	UserId string `protobuf:"bytes,1,opt,name=UserId,proto3" json:"UserId,omitempty"` // 用户id
+	Type   string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"`     // 类型 search-搜索列表 subscribe-订阅列表
+	Mode   int64  `protobuf:"varint,3,opt,name=Mode,proto3" json:"Mode,omitempty"`    // 列表模式 0-精简模式 1-详细模式
+}
+
+func (x *SaveListModeReq) Reset() {
+	*x = SaveListModeReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_bxbase_proto_msgTypes[29]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SaveListModeReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SaveListModeReq) ProtoMessage() {}
+
+func (x *SaveListModeReq) ProtoReflect() protoreflect.Message {
+	mi := &file_bxbase_proto_msgTypes[29]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SaveListModeReq.ProtoReflect.Descriptor instead.
+func (*SaveListModeReq) Descriptor() ([]byte, []int) {
+	return file_bxbase_proto_rawDescGZIP(), []int{29}
+}
+
+func (x *SaveListModeReq) GetUserId() string {
+	if x != nil {
+		return x.UserId
+	}
+	return ""
+}
+
+func (x *SaveListModeReq) GetType() string {
+	if x != nil {
+		return x.Type
+	}
+	return ""
+}
+
+func (x *SaveListModeReq) GetMode() int64 {
+	if x != nil {
+		return x.Mode
+	}
+	return 0
+}
+
+// 搜索订阅列表模式获取
+type ShowListModeReq struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	UserId string `protobuf:"bytes,1,opt,name=UserId,proto3" json:"UserId,omitempty"` // 用户id
+	Type   string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"`     // 类型 search-搜索列表 subscribe-订阅列表
+}
+
+func (x *ShowListModeReq) Reset() {
+	*x = ShowListModeReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_bxbase_proto_msgTypes[30]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ShowListModeReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ShowListModeReq) ProtoMessage() {}
+
+func (x *ShowListModeReq) ProtoReflect() protoreflect.Message {
+	mi := &file_bxbase_proto_msgTypes[30]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ShowListModeReq.ProtoReflect.Descriptor instead.
+func (*ShowListModeReq) Descriptor() ([]byte, []int) {
+	return file_bxbase_proto_rawDescGZIP(), []int{30}
+}
+
+func (x *ShowListModeReq) GetUserId() string {
+	if x != nil {
+		return x.UserId
+	}
+	return ""
+}
+
+func (x *ShowListModeReq) GetType() string {
+	if x != nil {
+		return x.Type
+	}
+	return ""
+}
+
+// 搜索订阅列表模式获取结果
+type ShowListModeRes struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	ErrCode int64  `protobuf:"varint,1,opt,name=err_code,json=errCode,proto3" json:"err_code,omitempty"`
+	ErrMsg  string `protobuf:"bytes,2,opt,name=err_msg,json=errMsg,proto3" json:"err_msg,omitempty"`
+	Data    int64  `protobuf:"varint,3,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (x *ShowListModeRes) Reset() {
+	*x = ShowListModeRes{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_bxbase_proto_msgTypes[31]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ShowListModeRes) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ShowListModeRes) ProtoMessage() {}
+
+func (x *ShowListModeRes) ProtoReflect() protoreflect.Message {
+	mi := &file_bxbase_proto_msgTypes[31]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ShowListModeRes.ProtoReflect.Descriptor instead.
+func (*ShowListModeRes) Descriptor() ([]byte, []int) {
+	return file_bxbase_proto_rawDescGZIP(), []int{31}
+}
+
+func (x *ShowListModeRes) GetErrCode() int64 {
+	if x != nil {
+		return x.ErrCode
+	}
+	return 0
+}
+
+func (x *ShowListModeRes) GetErrMsg() string {
+	if x != nil {
+		return x.ErrMsg
+	}
+	return ""
+}
+
+func (x *ShowListModeRes) GetData() int64 {
+	if x != nil {
+		return x.Data
+	}
+	return 0
+}
+
 var File_bxbase_proto protoreflect.FileDescriptor
 
 var file_bxbase_proto_rawDesc = []byte{
@@ -2753,7 +3001,7 @@ var file_bxbase_proto_rawDesc = []byte{
 	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x28, 0x0a,
 	0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x62, 0x78,
 	0x63, 0x6f, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65,
-	0x73, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x8f, 0x04, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74,
+	0x73, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x99, 0x05, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74,
 	0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65,
 	0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49,
 	0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
@@ -2786,220 +3034,252 @@ var file_bxbase_proto_rawDesc = []byte{
 	0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x50, 0x61, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08,
 	0x52, 0x05, 0x69, 0x73, 0x50, 0x61, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x61, 0x62, 0x75, 0x6c,
 	0x61, 0x72, 0x66, 0x6c, 0x61, 0x67, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x61,
-	0x62, 0x75, 0x6c, 0x61, 0x72, 0x66, 0x6c, 0x61, 0x67, 0x22, 0xf8, 0x03, 0x0a, 0x0c, 0x41, 0x64,
-	0x64, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73,
-	0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72,
-	0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72,
-	0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72,
-	0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d,
-	0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68,
-	0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x65, 0x61, 0x18, 0x05, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x65, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x74,
-	0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x74, 0x79,
-	0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x07,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1a,
-	0x0a, 0x08, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x08, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e,
-	0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e,
-	0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74,
-	0x54, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x6c, 0x65,
-	0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x75, 0x79, 0x65, 0x72, 0x43,
-	0x6c, 0x61, 0x73, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x79, 0x65,
-	0x72, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x61, 0x73, 0x42, 0x75, 0x79,
-	0x65, 0x72, 0x54, 0x65, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x68, 0x61, 0x73,
-	0x42, 0x75, 0x79, 0x65, 0x72, 0x54, 0x65, 0x6c, 0x12, 0x22, 0x0a, 0x0c, 0x68, 0x61, 0x73, 0x57,
-	0x69, 0x6e, 0x6e, 0x65, 0x72, 0x54, 0x65, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
-	0x68, 0x61, 0x73, 0x57, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x54, 0x65, 0x6c, 0x12, 0x1e, 0x0a, 0x0a,
-	0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06,
-	0x6e, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f,
-	0x74, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x74, 0x79, 0x18, 0x10, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x4b, 0x65,
-	0x79, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x14,
-	0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61,
-	0x70, 0x70, 0x49, 0x64, 0x22, 0x4c, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x53, 0x65, 0x61, 0x72, 0x63,
-	0x68, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05,
-	0x61, 0x70, 0x70, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70,
-	0x49, 0x64, 0x22, 0xc2, 0x01, 0x0a, 0x10, 0x4e, 0x65, 0x77, 0x65, 0x73, 0x74, 0x42, 0x69, 0x64,
-	0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x74, 0x79, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x74, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x69,
-	0x73, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69,
-	0x73, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49,
-	0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12,
-	0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
-	0x61, 0x70, 0x70, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72,
-	0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x6e, 0x74, 0x55, 0x73, 0x65,
-	0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64,
-	0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x49,
-	0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x05, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x71, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x73, 0x65,
-	0x74, 0x42, 0x69, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x19, 0x0a, 0x08,
-	0x65, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
-	0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f, 0x6d,
-	0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67,
-	0x12, 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14,
-	0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4e, 0x65, 0x77, 0x73, 0x65, 0x74, 0x42, 0x69, 0x64,
-	0x64, 0x69, 0x6e, 0x67, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xd4, 0x01, 0x0a, 0x0d, 0x4e,
-	0x65, 0x77, 0x73, 0x65, 0x74, 0x42, 0x69, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x14, 0x0a, 0x05,
-	0x69, 0x73, 0x56, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x56,
-	0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x61, 0x73, 0x53, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x73,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x68, 0x61, 0x73, 0x53, 0x75, 0x62, 0x4b, 0x65,
-	0x79, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x61, 0x73, 0x48, 0x53, 0x4b, 0x65, 0x79, 0x73, 0x18,
-	0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x61, 0x73, 0x48, 0x53, 0x4b, 0x65, 0x79, 0x73,
-	0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
-	0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x05,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x6e, 0x65, 0x77,
-	0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x18, 0x0a,
-	0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07,
-	0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x46, 0x6c,
-	0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x46, 0x6c, 0x61,
-	0x67, 0x22, 0xa6, 0x03, 0x0a, 0x0a, 0x6e, 0x65, 0x77, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74,
-	0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x65, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
-	0x61, 0x72, 0x65, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x74, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x69, 0x64, 0x61,
-	0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x62, 0x69, 0x64,
-	0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x12, 0x1e,
-	0x0a, 0x0a, 0x62, 0x75, 0x79, 0x65, 0x72, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x79, 0x65, 0x72, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x1c,
-	0x0a, 0x09, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x09, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x20, 0x0a, 0x0b,
-	0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28,
-	0x03, 0x52, 0x0b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1a,
-	0x0a, 0x08, 0x69, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x08, 0x69, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69,
-	0x74, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65,
-	0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x70,
-	0x70, 0x49, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64,
-	0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
-	0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x18, 0x0d,
-	0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73,
-	0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x43, 0x6f, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52,
-	0x05, 0x69, 0x73, 0x43, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x74, 0x65, 0x18, 0x0f,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x69, 0x74, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x70,
-	0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
-	0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3f, 0x0a, 0x09, 0x43, 0x6f,
-	0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x72, 0x72, 0x5f, 0x63,
-	0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x72, 0x72, 0x43, 0x6f,
-	0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x22, 0x52, 0x0a, 0x08, 0x43,
-	0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x72, 0x72, 0x5f, 0x63,
-	0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x72, 0x72, 0x43, 0x6f,
-	0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x64,
-	0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22,
-	0x20, 0x0a, 0x08, 0x41, 0x70, 0x70, 0x49, 0x64, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x41,
-	0x70, 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x41, 0x70, 0x70, 0x49,
-	0x64, 0x22, 0xd0, 0x07, 0x0a, 0x0c, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x52, 0x65,
-	0x73, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
-	0x52, 0x04, 0x79, 0x65, 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x12, 0x10, 0x0a, 0x03,
-	0x64, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x64, 0x61, 0x79, 0x12, 0x10,
-	0x0a, 0x03, 0x62, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x02, 0x52, 0x03, 0x62, 0x69, 0x64,
-	0x12, 0x18, 0x0a, 0x07, 0x62, 0x69, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x07, 0x62, 0x69, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x69,
-	0x64, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x0d, 0x62, 0x69, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64,
-	0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28,
-	0x02, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x72,
-	0x6f, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x2c, 0x0a, 0x11,
-	0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e,
-	0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
-	0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e,
-	0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x02, 0x52, 0x03, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07,
-	0x65, 0x6e, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65,
-	0x6e, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x69,
-	0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x65,
-	0x6e, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05,
-	0x62, 0x75, 0x79, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x62, 0x75, 0x79,
-	0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x75, 0x79, 0x65, 0x72, 0x55, 0x6e, 0x69, 0x74, 0x18,
-	0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x79, 0x65, 0x72, 0x55, 0x6e, 0x69, 0x74,
-	0x12, 0x28, 0x0a, 0x0f, 0x62, 0x75, 0x79, 0x65, 0x72, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70,
-	0x65, 0x6e, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x75, 0x79, 0x65, 0x72,
-	0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x62, 0x69,
-	0x64, 0x44, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x02,
-	0x52, 0x0c, 0x62, 0x69, 0x64, 0x44, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x2a,
-	0x0a, 0x10, 0x62, 0x69, 0x64, 0x44, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x6e,
-	0x69, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x62, 0x69, 0x64, 0x44, 0x61, 0x79,
-	0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x36, 0x0a, 0x16, 0x62, 0x69,
-	0x64, 0x44, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70,
-	0x70, 0x65, 0x6e, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x62, 0x69, 0x64, 0x44,
-	0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65,
-	0x6e, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x69, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x13,
-	0x20, 0x01, 0x28, 0x02, 0x52, 0x08, 0x62, 0x69, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x22,
-	0x0a, 0x0c, 0x62, 0x69, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x18, 0x14,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x62, 0x69, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x55, 0x6e,
-	0x69, 0x74, 0x12, 0x2e, 0x0a, 0x12, 0x62, 0x69, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x55, 0x6e,
-	0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12,
-	0x62, 0x69, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65,
-	0x6e, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x41, 0x63, 0x63, 0x75, 0x72,
-	0x61, 0x63, 0x79, 0x18, 0x16, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64,
-	0x41, 0x63, 0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x69, 0x65, 0x6c,
-	0x64, 0x41, 0x63, 0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x55, 0x6e, 0x69, 0x74, 0x18, 0x17, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x11, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x41, 0x63, 0x63, 0x75, 0x72, 0x61,
-	0x63, 0x79, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x41,
-	0x63, 0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e,
-	0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x41, 0x63,
-	0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64,
-	0x12, 0x12, 0x0a, 0x04, 0x70, 0x75, 0x73, 0x68, 0x18, 0x19, 0x20, 0x01, 0x28, 0x02, 0x52, 0x04,
-	0x70, 0x75, 0x73, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x75, 0x73, 0x68, 0x55, 0x6e, 0x69, 0x74,
-	0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x73, 0x68, 0x55, 0x6e, 0x69, 0x74,
-	0x12, 0x26, 0x0a, 0x0e, 0x70, 0x75, 0x73, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65,
-	0x6e, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x75, 0x73, 0x68, 0x55, 0x6e,
-	0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x72, 0x72, 0x6f,
-	0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x72, 0x72,
-	0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63,
-	0x6f, 0x64, 0x65, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72,
-	0x43, 0x6f, 0x64, 0x65, 0x32, 0xab, 0x05, 0x0a, 0x06, 0x62, 0x78, 0x62, 0x61, 0x73, 0x65, 0x12,
-	0x32, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x12, 0x2e, 0x62, 0x78,
-	0x63, 0x6f, 0x6c, 0x2e, 0x41, 0x64, 0x64, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x1a,
-	0x12, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x41, 0x64, 0x64, 0x6c, 0x61, 0x62, 0x65, 0x6c,
-	0x52, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x41,
-	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x47, 0x65,
-	0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a,
-	0x18, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c,
-	0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x4c, 0x61, 0x62,
-	0x65, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c,
-	0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a,
-	0x15, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x41, 0x63, 0x74,
-	0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x42, 0x43, 0x41, 0x63, 0x74, 0x69,
-	0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x42, 0x43, 0x41, 0x63, 0x74,
-	0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4c,
-	0x61, 0x62, 0x65, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x3e, 0x0a,
-	0x0c, 0x49, 0x73, 0x43, 0x6f, 0x6c, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e,
-	0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x49, 0x73, 0x43, 0x6f, 0x6c, 0x6c, 0x41, 0x63, 0x74, 0x69,
-	0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x49, 0x73,
-	0x43, 0x6f, 0x6c, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x26, 0x0a,
-	0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x0e, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4c, 0x69,
-	0x73, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x0e, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4c, 0x69,
-	0x73, 0x74, 0x52, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x0a, 0x53, 0x68, 0x6f, 0x77, 0x53, 0x65, 0x61,
-	0x72, 0x63, 0x68, 0x12, 0x14, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x68, 0x6f, 0x77,
-	0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x62, 0x78, 0x63, 0x6f,
-	0x6c, 0x2e, 0x53, 0x68, 0x6f, 0x77, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x12,
-	0x32, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x13, 0x2e, 0x62,
-	0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65,
-	0x71, 0x1a, 0x10, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
-	0x52, 0x65, 0x73, 0x12, 0x33, 0x0a, 0x0b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, 0x61, 0x72,
-	0x63, 0x68, 0x12, 0x13, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65,
-	0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e,
-	0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x53,
-	0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x13, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x44, 0x65,
-	0x6c, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x62, 0x78, 0x63,
-	0x6f, 0x6c, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0d,
-	0x4e, 0x65, 0x77, 0x65, 0x73, 0x74, 0x42, 0x69, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x17, 0x2e,
-	0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4e, 0x65, 0x77, 0x65, 0x73, 0x74, 0x42, 0x69, 0x64, 0x64,
-	0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4e,
+	0x62, 0x75, 0x6c, 0x61, 0x72, 0x66, 0x6c, 0x61, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x61,
+	0x72, 0x63, 0x68, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b,
+	0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x73,
+	0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x0a, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x77,
+	0x6f, 0x72, 0x64, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09,
+	0x77, 0x6f, 0x72, 0x64, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x61, 0x64, 0x64,
+	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x17, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x57, 0x6f,
+	0x72, 0x64, 0x73, 0x22, 0x82, 0x05, 0x0a, 0x0c, 0x41, 0x64, 0x64, 0x53, 0x65, 0x61, 0x72, 0x63,
+	0x68, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04,
+	0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
+	0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b,
+	0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12,
+	0x0a, 0x04, 0x61, 0x72, 0x65, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72,
+	0x65, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08,
+	0x6d, 0x69, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+	0x6d, 0x69, 0x6e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x50,
+	0x72, 0x69, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x50,
+	0x72, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79,
+	0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79,
+	0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0a,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65,
+	0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x75, 0x79, 0x65, 0x72, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x0b,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x79, 0x65, 0x72, 0x43, 0x6c, 0x61, 0x73, 0x73,
+	0x12, 0x20, 0x0a, 0x0b, 0x68, 0x61, 0x73, 0x42, 0x75, 0x79, 0x65, 0x72, 0x54, 0x65, 0x6c, 0x18,
+	0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x68, 0x61, 0x73, 0x42, 0x75, 0x79, 0x65, 0x72, 0x54,
+	0x65, 0x6c, 0x12, 0x22, 0x0a, 0x0c, 0x68, 0x61, 0x73, 0x57, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x54,
+	0x65, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x68, 0x61, 0x73, 0x57, 0x69, 0x6e,
+	0x6e, 0x65, 0x72, 0x54, 0x65, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78,
+	0x69, 0x73, 0x74, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x65,
+	0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x6f, 0x74, 0x4b, 0x65, 0x79,
+	0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x12,
+	0x0a, 0x04, 0x63, 0x69, 0x74, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69,
+	0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x4b, 0x65, 0x79, 0x18, 0x11, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x05, 0x69, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49,
+	0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x12, 0x20,
+	0x0a, 0x0b, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x13, 0x20,
+	0x01, 0x28, 0x03, 0x52, 0x0b, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x47, 0x72, 0x6f, 0x75, 0x70,
+	0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x14,
+	0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x6f, 0x64, 0x65,
+	0x12, 0x1c, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x15, 0x20,
+	0x01, 0x28, 0x03, 0x52, 0x09, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x28,
+	0x0a, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x57, 0x6f, 0x72, 0x64,
+	0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f,
+	0x6e, 0x61, 0x6c, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x4c, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x53,
+	0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72,
+	0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64,
+	0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x22, 0xc2, 0x01, 0x0a, 0x10, 0x4e, 0x65, 0x77, 0x65, 0x73,
+	0x74, 0x42, 0x69, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x63,
+	0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x74, 0x79, 0x12,
+	0x1a, 0x0a, 0x08, 0x69, 0x73, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x03, 0x52, 0x08, 0x69, 0x73, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x75,
+	0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65,
+	0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x74,
+	0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x6e,
+	0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x55, 0x73,
+	0x65, 0x72, 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6e, 0x65, 0x77, 0x55,
+	0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x07,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x71, 0x0a, 0x11, 0x4e,
 	0x65, 0x77, 0x73, 0x65, 0x74, 0x42, 0x69, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70,
-	0x12, 0x30, 0x0a, 0x08, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x12, 0x0f, 0x2e, 0x62,
-	0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x41, 0x70, 0x70, 0x49, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e,
-	0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x52, 0x65,
-	0x73, 0x70, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x62, 0x78, 0x62, 0x61, 0x73, 0x65, 0x62, 0x06,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x12, 0x19, 0x0a, 0x08, 0x65, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x03, 0x52, 0x07, 0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65,
+	0x72, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72,
+	0x72, 0x4d, 0x73, 0x67, 0x12, 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x14, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4e, 0x65, 0x77, 0x73, 0x65,
+	0x74, 0x42, 0x69, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xd4,
+	0x01, 0x0a, 0x0d, 0x4e, 0x65, 0x77, 0x73, 0x65, 0x74, 0x42, 0x69, 0x64, 0x64, 0x69, 0x6e, 0x67,
+	0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x56, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x05, 0x69, 0x73, 0x56, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x61, 0x73, 0x53, 0x75, 0x62,
+	0x4b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x68, 0x61, 0x73, 0x53,
+	0x75, 0x62, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x61, 0x73, 0x48, 0x53, 0x4b,
+	0x65, 0x79, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x61, 0x73, 0x48, 0x53,
+	0x4b, 0x65, 0x79, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20,
+	0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x69,
+	0x73, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c,
+	0x2e, 0x6e, 0x65, 0x77, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x04, 0x6c, 0x69, 0x73,
+	0x74, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x06, 0x20, 0x03,
+	0x28, 0x09, 0x52, 0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x73,
+	0x75, 0x62, 0x46, 0x6c, 0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75,
+	0x62, 0x46, 0x6c, 0x61, 0x67, 0x22, 0xa6, 0x03, 0x0a, 0x0a, 0x6e, 0x65, 0x77, 0x65, 0x73, 0x74,
+	0x4c, 0x69, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x65, 0x61, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x65, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x74, 0x79,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x74, 0x79, 0x12, 0x1c, 0x0a, 0x09,
+	0x62, 0x69, 0x64, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x09, 0x62, 0x69, 0x64, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75,
+	0x64, 0x67, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x62, 0x75, 0x64, 0x67,
+	0x65, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x75, 0x79, 0x65, 0x72, 0x63, 0x6c, 0x61, 0x73, 0x73,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x79, 0x65, 0x72, 0x63, 0x6c, 0x61,
+	0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x6b, 0x65, 0x79, 0x73, 0x18,
+	0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x6b, 0x65, 0x79, 0x73,
+	0x12, 0x20, 0x0a, 0x0b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x69,
+	0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x18, 0x08,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x12, 0x14,
+	0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74,
+	0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x74, 0x79, 0x70, 0x65, 0x18,
+	0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14,
+	0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61,
+	0x70, 0x70, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x02, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73,
+	0x74, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78,
+	0x69, 0x73, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x43, 0x6f, 0x6c, 0x18, 0x0e, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x43, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69,
+	0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x69, 0x74, 0x65, 0x12, 0x1e,
+	0x0a, 0x0a, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x10, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x0a, 0x73, 0x70, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3f,
+	0x0a, 0x09, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x65,
+	0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65,
+	0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f, 0x6d, 0x73,
+	0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x22,
+	0x52, 0x0a, 0x08, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x65,
+	0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65,
+	0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f, 0x6d, 0x73,
+	0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12,
+	0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64,
+	0x61, 0x74, 0x61, 0x22, 0x20, 0x0a, 0x08, 0x41, 0x70, 0x70, 0x49, 0x64, 0x52, 0x65, 0x71, 0x12,
+	0x14, 0x0a, 0x05, 0x41, 0x70, 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+	0x41, 0x70, 0x70, 0x49, 0x64, 0x22, 0xd0, 0x07, 0x0a, 0x0c, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64,
+	0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x79, 0x65, 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f,
+	0x6e, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6d, 0x6f, 0x6e, 0x74, 0x68,
+	0x12, 0x10, 0x0a, 0x03, 0x64, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x64,
+	0x61, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x02, 0x52,
+	0x03, 0x62, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x69, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x18,
+	0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x69, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x24,
+	0x0a, 0x0d, 0x62, 0x69, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18,
+	0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x62, 0x69, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70,
+	0x70, 0x65, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x02, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x20,
+	0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x18, 0x08, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x6e, 0x69, 0x74,
+	0x12, 0x2c, 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x41,
+	0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x72, 0x6f,
+	0x6a, 0x65, 0x63, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x10,
+	0x0a, 0x03, 0x65, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x02, 0x52, 0x03, 0x65, 0x6e, 0x74,
+	0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x65, 0x6e,
+	0x74, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0d, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64,
+	0x12, 0x14, 0x0a, 0x05, 0x62, 0x75, 0x79, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x02, 0x52,
+	0x05, 0x62, 0x75, 0x79, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x75, 0x79, 0x65, 0x72, 0x55,
+	0x6e, 0x69, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x79, 0x65, 0x72,
+	0x55, 0x6e, 0x69, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x75, 0x79, 0x65, 0x72, 0x55, 0x6e, 0x69,
+	0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62,
+	0x75, 0x79, 0x65, 0x72, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x22,
+	0x0a, 0x0c, 0x62, 0x69, 0x64, 0x44, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x10,
+	0x20, 0x01, 0x28, 0x02, 0x52, 0x0c, 0x62, 0x69, 0x64, 0x44, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61,
+	0x74, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x62, 0x69, 0x64, 0x44, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61,
+	0x74, 0x65, 0x55, 0x6e, 0x69, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x62, 0x69,
+	0x64, 0x44, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x36,
+	0x0a, 0x16, 0x62, 0x69, 0x64, 0x44, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x6e,
+	0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16,
+	0x62, 0x69, 0x64, 0x44, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x69, 0x74,
+	0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x69, 0x64, 0x46, 0x69, 0x65,
+	0x6c, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x02, 0x52, 0x08, 0x62, 0x69, 0x64, 0x46, 0x69, 0x65,
+	0x6c, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x62, 0x69, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x55, 0x6e,
+	0x69, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x62, 0x69, 0x64, 0x46, 0x69, 0x65,
+	0x6c, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x2e, 0x0a, 0x12, 0x62, 0x69, 0x64, 0x46, 0x69, 0x65,
+	0x6c, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x15, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x12, 0x62, 0x69, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x55, 0x6e, 0x69, 0x74,
+	0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x41,
+	0x63, 0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x18, 0x16, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0d, 0x66,
+	0x69, 0x65, 0x6c, 0x64, 0x41, 0x63, 0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x12, 0x2c, 0x0a, 0x11,
+	0x66, 0x69, 0x65, 0x6c, 0x64, 0x41, 0x63, 0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x55, 0x6e, 0x69,
+	0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x41, 0x63,
+	0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x66, 0x69,
+	0x65, 0x6c, 0x64, 0x41, 0x63, 0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x55, 0x6e, 0x69, 0x74, 0x41,
+	0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x66, 0x69, 0x65,
+	0x6c, 0x64, 0x41, 0x63, 0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70,
+	0x70, 0x65, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x75, 0x73, 0x68, 0x18, 0x19, 0x20, 0x01,
+	0x28, 0x02, 0x52, 0x04, 0x70, 0x75, 0x73, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x75, 0x73, 0x68,
+	0x55, 0x6e, 0x69, 0x74, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x73, 0x68,
+	0x55, 0x6e, 0x69, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x70, 0x75, 0x73, 0x68, 0x55, 0x6e, 0x69, 0x74,
+	0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x75,
+	0x73, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x1b, 0x0a, 0x09,
+	0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72,
+	0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x65,
+	0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x51, 0x0a, 0x0f, 0x53, 0x61, 0x76, 0x65,
+	0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x55,
+	0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x55, 0x73, 0x65,
+	0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0x3d, 0x0a, 0x0f, 0x53,
+	0x68, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16,
+	0x0a, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
+	0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x22, 0x59, 0x0a, 0x0f, 0x53, 0x68,
+	0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x12, 0x19, 0x0a,
+	0x08, 0x65, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x07, 0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f,
+	0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73,
+	0x67, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0xab, 0x05, 0x0a, 0x06, 0x62, 0x78, 0x62, 0x61, 0x73, 0x65,
+	0x12, 0x32, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x12, 0x2e, 0x62,
+	0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x41, 0x64, 0x64, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x52, 0x65, 0x71,
+	0x1a, 0x12, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x41, 0x64, 0x64, 0x6c, 0x61, 0x62, 0x65,
+	0x6c, 0x52, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c,
+	0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x47,
+	0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
+	0x1a, 0x18, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65,
+	0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x4c, 0x61,
+	0x62, 0x65, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x2e, 0x62, 0x78, 0x63, 0x6f,
+	0x6c, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
+	0x1a, 0x15, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x41, 0x63,
+	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x42, 0x43, 0x41, 0x63, 0x74,
+	0x69, 0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x42, 0x43, 0x41, 0x63,
+	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e,
+	0x4c, 0x61, 0x62, 0x65, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x3e,
+	0x0a, 0x0c, 0x49, 0x73, 0x43, 0x6f, 0x6c, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16,
+	0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x49, 0x73, 0x43, 0x6f, 0x6c, 0x6c, 0x41, 0x63, 0x74,
+	0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x49,
+	0x73, 0x43, 0x6f, 0x6c, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x26,
+	0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x0e, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4c,
+	0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x0e, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4c,
+	0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x0a, 0x53, 0x68, 0x6f, 0x77, 0x53, 0x65,
+	0x61, 0x72, 0x63, 0x68, 0x12, 0x14, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x68, 0x6f,
+	0x77, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x62, 0x78, 0x63,
+	0x6f, 0x6c, 0x2e, 0x53, 0x68, 0x6f, 0x77, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73,
+	0x12, 0x32, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x13, 0x2e,
+	0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52,
+	0x65, 0x71, 0x1a, 0x10, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,
+	0x6e, 0x52, 0x65, 0x73, 0x12, 0x33, 0x0a, 0x0b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, 0x61,
+	0x72, 0x63, 0x68, 0x12, 0x13, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x41, 0x64, 0x64, 0x53,
+	0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c,
+	0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x09, 0x44, 0x65, 0x6c,
+	0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x13, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x44,
+	0x65, 0x6c, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x10, 0x2e, 0x62, 0x78,
+	0x63, 0x6f, 0x6c, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x42, 0x0a,
+	0x0d, 0x4e, 0x65, 0x77, 0x65, 0x73, 0x74, 0x42, 0x69, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x17,
+	0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x4e, 0x65, 0x77, 0x65, 0x73, 0x74, 0x42, 0x69, 0x64,
+	0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e,
+	0x4e, 0x65, 0x77, 0x73, 0x65, 0x74, 0x42, 0x69, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73,
+	0x70, 0x12, 0x30, 0x0a, 0x08, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x12, 0x0f, 0x2e,
+	0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x41, 0x70, 0x70, 0x49, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x13,
+	0x2e, 0x62, 0x78, 0x63, 0x6f, 0x6c, 0x2e, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x52,
+	0x65, 0x73, 0x70, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x62, 0x78, 0x62, 0x61, 0x73, 0x65, 0x62,
+	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -3014,7 +3294,7 @@ func file_bxbase_proto_rawDescGZIP() []byte {
 	return file_bxbase_proto_rawDescData
 }
 
-var file_bxbase_proto_msgTypes = make([]protoimpl.MessageInfo, 29)
+var file_bxbase_proto_msgTypes = make([]protoimpl.MessageInfo, 32)
 var file_bxbase_proto_goTypes = []interface{}{
 	(*AddlabelReq)(nil),       // 0: bxcol.AddlabelReq
 	(*AddlabelRes)(nil),       // 1: bxcol.AddlabelRes
@@ -3045,6 +3325,9 @@ var file_bxbase_proto_goTypes = []interface{}{
 	(*CheckRes)(nil),          // 26: bxcol.CheckRes
 	(*AppIdReq)(nil),          // 27: bxcol.AppIdReq
 	(*IncludedResp)(nil),      // 28: bxcol.IncludedResp
+	(*SaveListModeReq)(nil),   // 29: bxcol.SaveListModeReq
+	(*ShowListModeReq)(nil),   // 30: bxcol.ShowListModeReq
+	(*ShowListModeRes)(nil),   // 31: bxcol.ShowListModeRes
 }
 var file_bxbase_proto_depIdxs = []int32{
 	4,  // 0: bxcol.GetLabelActionRes.labels:type_name -> bxcol.LabelByUser
@@ -3440,6 +3723,42 @@ func file_bxbase_proto_init() {
 				return nil
 			}
 		}
+		file_bxbase_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SaveListModeReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_bxbase_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ShowListModeReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_bxbase_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ShowListModeRes); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
@@ -3447,7 +3766,7 @@ func file_bxbase_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_bxbase_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   29,
+			NumMessages:   32,
 			NumExtensions: 0,
 			NumServices:   1,
 		},

+ 1 - 1
jyBXBase/rpc/type/bxbase/bxbase_grpc.pb.go

@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 // versions:
 // - protoc-gen-go-grpc v1.2.0
-// - protoc             v3.15.1
+// - protoc             v3.19.4
 // source: bxbase.proto
 
 package bxbase

+ 7 - 3
jyBXBase/rpc/util/common.go

@@ -18,9 +18,13 @@ import (
 )
 
 const (
-	query          = `{"query":{"terms":{"_id":["%s"]}},"_source":["_id","subtype","s_winner","buyertel","winnertel","buyerclass"],"from":0,"size":%d}`
-	mongodb_fields = `{"_id":1,"area":1,"publishtime":1,"s_subscopeclass":1,"subtype":1,"title":1,"toptype":1,"type":1, "buyerclass":1,"budget":1,"bidamount":1,"winnertel":1,"s_winner":1,"buyertel":1,"attach_text":1}`
-	querys         = `{"query":{"terms":{"_id":["%s"]}},"_source":["_id","title","detail","area","city","publishtime","projectname","buyer","buyerclass","s_winner","bidamount","subtype","toptype","projectcode","buyertel","budget","bidopentime","agency","projectscope","winnerperson","winnertel"],"from":0,"size":%d}}`
+	query                     = `{"query":{"terms":{"_id":["%s"]}},"_source":["_id","subtype","s_winner","buyertel","winnertel","buyerclass"],"from":0,"size":%d}`
+	mongodb_fields            = `{"_id":1,"area":1,"publishtime":1,"s_subscopeclass":1,"subtype":1,"title":1,"toptype":1,"type":1, "buyerclass":1,"budget":1,"bidamount":1,"winnertel":1,"s_winner":1,"buyertel":1,"attach_text":1}`
+	querys                    = `{"query":{"terms":{"_id":["%s"]}},"_source":["_id","title","detail","area","city","publishtime","projectname","buyer","buyerclass","s_winner","bidamount","subtype","toptype","projectcode","buyertel","budget","bidopentime","agency","projectscope","winnerperson","winnertel"],"from":0,"size":%d}}`
+	SearchGroupBidding        = 1 // 搜索分组:1:招标采购公告;2:超前项目
+	SearchGroupLeadingProject = 2 // 搜索分组:1:招标采购公告;2:超前项目
+	TopTypesBidding           = "招标预告,招标公告,招标结果,招标信用信息"
+	TopTypesLeadingProject    = "拟建,采购意向"
 )
 
 //是否是付费用户 -bool: true:是 fasle:不是

+ 28 - 19
jyBXCore/api/bxcore.api

@@ -9,25 +9,34 @@ info (
 
 type (
 	searchReq {
-		AppId          string `header:"appId,optional"`
-		PageNum        int64  `json:"pageNum"`
-		PageSize       int64  `json:"pageSize"`
-		KeyWords       string `json:"keyWords,optional"`
-		Province       string `json:"province,optional"`
-		City           string `json:"city,optional"`
-		Subtype        string `json:"subtype,optional"`
-		Toptype        string `json:"toptype,optional"`
-		PublishTime    string `json:"publishTime,optional"`
-		SelectType     string `json:"selectType,optional"`
-		Price          string `json:"price,optional"`
-		Industry       string `json:"industry,optional"`
-		BuyerClass     string `json:"buyerClass,optional"`
-		BuyerTel       string `json:"buyerTel,optional"`
-		WinnerTel      string `json:"winnerTel,optional"`
-		ExclusionWords string `json:"exclusionWords,optional"`
-		FileExists     string `json:"fileExists,optional"`
-		UserType       string `path:"userType,optional"`
-		SplitKeywords  string `json:"splitKeywords,optional"`
+		UserType        string `path:"userType,optional"`
+		AppId           string `header:"appId"`
+		UserId          string `header:"userId"`
+		Phone           string `header:"phone"`
+		NewUserId       string `header:"newUserId"`
+		EntId           int64  `header:"entId,optional"`
+		EntUserId       int64  `header:"entUserId,optional"`
+		PageNum         int64  `json:"pageNum,optional"`
+		PageSize        int64  `json:"pageSize,optional"`
+		Province        string `json:"province,optional"`
+		City            string `json:"city,optional"`
+		Subtype         string `json:"subtype,optional"`
+		TopType         string `json:"toptype,optional"`
+		PublishTime     string `json:"publishTime,optional"`
+		SelectType      string `json:"selectType,optional"`
+		Price           string `json:"price,optional"`
+		Industry        string `json:"industry,optional"`
+		BuyerClass      string `json:"buyerClass,optional"`
+		BuyerTel        string `json:"buyerTel,optional"`
+		WinnerTel       string `json:"winnerTel,optional"`
+		FileExists      string `json:"fileExists,optional"`
+		SearchGroup     int64  `json:"searchGroup,optional"`
+		SearchMode      int64  `json:"searchMode,optional"`
+		WordsMode       int64  `json:"wordsMode,optional"`
+		KeyWords        string `json:"keyWords,optional"`
+		AdditionalWords string `json:"additionalWords,optional"`
+		ExclusionWords  string `json:"exclusionWords,optional"`
+		BidField        string `json:"bidField,optional"` //医疗领域化信息
 	}
 	//
 	commonResp {

+ 29 - 22
jyBXCore/api/internal/logic/searchListLogic.go

@@ -31,28 +31,35 @@ func NewSearchListLogic(ctx context.Context, svcCtx *svc.ServiceContext, r *http
 func (l *SearchListLogic) SearchList(req *types.SearchReq) (resp *types.CommonResp, err error) {
 	t := time.Now()
 	res, err := l.svcCtx.BxCore.GetSearchList(l.ctx, &bxcore.SearchReq{
-		PageNum:        req.PageNum,
-		PageSize:       req.PageSize,
-		PublishTime:    req.PublishTime,
-		Province:       req.Province,
-		City:           req.City,
-		Industry:       req.Industry,
-		BuyerClass:     req.BuyerClass,
-		KeyWords:       req.KeyWords,
-		Subtype:        req.Subtype,
-		SelectType:     req.SelectType,
-		Price:          req.Price,
-		FileExists:     req.FileExists,
-		BuyerTel:       req.BuyerTel,
-		WinnerTel:      req.WinnerTel,
-		ExclusionWords: req.ExclusionWords,
-		AppId:          req.AppId,
-		UserType:       req.UserType,
-		SplitKeywords:  req.SplitKeywords,
-		UserId:         l.r.Header.Get("userId"),
-		EntId:          l.r.Header.Get("entId"),
-		Platform:       util.CheckPlatform(l.r),
-		Toptype:        req.Toptype,
+		AppId:           req.AppId,
+		UserId:          req.UserId,
+		Phone:           req.Phone,
+		NewUserId:       req.NewUserId,
+		EntId:           req.EntId,
+		EntUserId:       req.EntUserId,
+		PageNum:         req.PageNum,
+		PageSize:        req.PageSize,
+		Province:        req.Province,
+		City:            req.City,
+		Subtype:         req.Subtype,
+		TopType:         req.TopType,
+		PublishTime:     req.PublishTime,
+		SelectType:      req.SelectType,
+		Price:           req.Price,
+		Industry:        req.Industry,
+		BuyerClass:      req.BuyerClass,
+		BuyerTel:        req.BuyerTel,
+		WinnerTel:       req.WinnerTel,
+		FileExists:      req.FileExists,
+		SearchGroup:     req.SearchGroup,
+		SearchMode:      req.SearchMode,
+		WordsMode:       req.WordsMode,
+		KeyWords:        req.KeyWords,
+		AdditionalWords: req.AdditionalWords,
+		ExclusionWords:  req.ExclusionWords,
+		UserType:        req.UserType,
+		Platform:        util.CheckPlatform(l.r),
+		BidField:        req.BidField,
 	})
 	log.Println("请求接口耗时:", time.Since(t).Seconds())
 	if err != nil {

+ 28 - 19
jyBXCore/api/internal/types/types.go

@@ -2,25 +2,34 @@
 package types
 
 type SearchReq struct {
-	AppId          string `header:"appId,optional"`
-	PageNum        int64  `json:"pageNum"`
-	PageSize       int64  `json:"pageSize"`
-	KeyWords       string `json:"keyWords,optional"`
-	Province       string `json:"province,optional"`
-	City           string `json:"city,optional"`
-	Subtype        string `json:"subtype,optional"`
-	Toptype        string `json:"toptype,optional"`
-	PublishTime    string `json:"publishTime,optional"`
-	SelectType     string `json:"selectType,optional"`
-	Price          string `json:"price,optional"`
-	Industry       string `json:"industry,optional"`
-	BuyerClass     string `json:"buyerClass,optional"`
-	BuyerTel       string `json:"buyerTel,optional"`
-	WinnerTel      string `json:"winnerTel,optional"`
-	ExclusionWords string `json:"exclusionWords,optional"`
-	FileExists     string `json:"fileExists,optional"`
-	UserType       string `path:"userType,optional"`
-	SplitKeywords  string `json:"splitKeywords,optional"`
+	UserType        string `path:"userType,optional"`
+	AppId           string `header:"appId"`
+	UserId          string `header:"userId"`
+	Phone           string `header:"phone"`
+	NewUserId       string `header:"newUserId"`
+	EntId           int64  `header:"entId,optional"`
+	EntUserId       int64  `header:"entUserId,optional"`
+	PageNum         int64  `json:"pageNum,optional"`
+	PageSize        int64  `json:"pageSize,optional"`
+	Province        string `json:"province,optional"`
+	City            string `json:"city,optional"`
+	Subtype         string `json:"subtype,optional"`
+	TopType         string `json:"toptype,optional"`
+	PublishTime     string `json:"publishTime,optional"`
+	SelectType      string `json:"selectType,optional"`
+	Price           string `json:"price,optional"`
+	Industry        string `json:"industry,optional"`
+	BuyerClass      string `json:"buyerClass,optional"`
+	BuyerTel        string `json:"buyerTel,optional"`
+	WinnerTel       string `json:"winnerTel,optional"`
+	FileExists      string `json:"fileExists,optional"`
+	SearchGroup     int64  `json:"searchGroup,optional"`
+	SearchMode      int64  `json:"searchMode,optional"`
+	WordsMode       int64  `json:"wordsMode,optional"`
+	KeyWords        string `json:"keyWords,optional"`
+	AdditionalWords string `json:"additionalWords,optional"`
+	ExclusionWords  string `json:"exclusionWords,optional"`
+	BidField        string `json:"bidField,optional"` //医疗领域化信息
 }
 
 type CommonResp struct {

+ 1 - 2
jyBXCore/go.mod

@@ -3,10 +3,9 @@ module jyBXCore
 go 1.16
 
 require (
-	app.yhyue.com/moapp/jybase v0.0.0-20220829123944-ed6966c3fcb3
+	app.yhyue.com/moapp/jybase v0.0.0-20230117032034-ad7c00ffe11a
 	bp.jydev.jianyu360.cn/BaseService/gateway v1.3.4
 	github.com/go-sql-driver/mysql v1.6.0
-	github.com/golang/protobuf v1.5.2
 	github.com/zeromicro/go-zero v1.4.0
 	google.golang.org/grpc v1.49.0
 	google.golang.org/protobuf v1.28.1

+ 4 - 2
jyBXCore/go.sum

@@ -4,8 +4,8 @@ app.yhyue.com/moapp/jybase v0.0.0-20220415064050-37ce64b3e2d4/go.mod h1:qNRA0sHu
 app.yhyue.com/moapp/jybase v0.0.0-20220418104200-46c3fff161c7/go.mod h1:qNRA0sHuYqcLoYoP8irpaWnW9YsXixe6obBIkwaXpD0=
 app.yhyue.com/moapp/jybase v0.0.0-20220420032112-668025915ee4/go.mod h1:qNRA0sHuYqcLoYoP8irpaWnW9YsXixe6obBIkwaXpD0=
 app.yhyue.com/moapp/jybase v0.0.0-20220421060131-a1001013ba46/go.mod h1:qNRA0sHuYqcLoYoP8irpaWnW9YsXixe6obBIkwaXpD0=
-app.yhyue.com/moapp/jybase v0.0.0-20220829123944-ed6966c3fcb3 h1:yKOLZmtjWansB6QvwMbeqXDdm4kq3ALc92aqVzyCgu4=
-app.yhyue.com/moapp/jybase v0.0.0-20220829123944-ed6966c3fcb3/go.mod h1:HelrO6tcD9TcKb/HOP2BLbzppyDz2kpQSFhPMQTUgbQ=
+app.yhyue.com/moapp/jybase v0.0.0-20230117032034-ad7c00ffe11a h1:wD4aWPSYdiX1cIP4lzzPD2s7fYhKa3muIf97l9tonJE=
+app.yhyue.com/moapp/jybase v0.0.0-20230117032034-ad7c00ffe11a/go.mod h1:zB47XTeJvpcbtBRYgkQuxOICWNexiZfbUO+7aUf6mNs=
 bp.jydev.jianyu360.cn/BP/jynsq v0.0.0-20220222052708-ebc43af90698/go.mod h1:ojo/AUH9Yr1wzarEjOaNMkj1Cet/9r8IgLyba64Z52E=
 bp.jydev.jianyu360.cn/BaseService/gateway v0.0.0-20220419090715-88ddb32961be/go.mod h1:Yj4oabIGItuMoF0BXYLz2XAnF581kxgXBrvlUtIJrkI=
 bp.jydev.jianyu360.cn/BaseService/gateway v1.3.4 h1:zl5eZrKDBENVVBUiPpzyQQ0/SBdGUmZS3thXycSEO1g=
@@ -270,6 +270,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
+github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=

+ 1 - 1
jyBXCore/rpc/bxcore.go

@@ -22,7 +22,7 @@ func main() {
 	go func() {
 		//正文、附件搜索限制
 		util.LimitSearchInit()
-		err := endless.ListenAndServe(":"+MC.InterfaceToStr(IC.C.Webrpcport), nil, func() {})
+		err := endless.ListenAndServe(":"+MC.InterfaceToStr(IC.C.WebRpcPort), nil, func() {})
 		if err != nil {
 			log.Println("ListenAndServe: ", err)
 		}

+ 86 - 61
jyBXCore/rpc/bxcore.proto

@@ -1,31 +1,41 @@
 syntax = "proto3";
 
 package bxcore;
-option go_package="./bxcore";
+option go_package = "./bxcore";
 
 message SearchReq {
   string appId = 1;//剑鱼默认10000
-  int64  pageNum = 2;//当前页码
-  int64  pageSize = 3;//每页数量
-  string  keyWords = 4;//关键词
-  string  province = 5;//省份
-  string  city = 6;//城市
-  string  subtype = 7;//信息类型-二级
-  string  publishTime = 8;//发布时间
-  string selectType = 9;//搜索范围:标题;正文等
-  string  price = 10;//价格
-  string industry = 11;//行业
-  string buyerClass = 12;//采购单位类型
-  string buyerTel = 13;//采购单位联系方式
-  string winnerTel = 14;//中标单位联系方式
-  string exclusionWords = 15;//排除词
-  string fileExists = 16;//是否有附件
-  string  userId = 17;
-  string  entId = 18;
-  string  userType = 19;//用户状态 fType:免费用户	pType:付费用户	vType:超级订阅用户	mType:大会员用户	eType:商机管理用户
-  string  splitKeywords = 20;//分词结果
-  string  platform = 21;//请求平台
-  string  toptype = 22;//信息类型-一级分类
+  string  userId = 2;//用户id
+  string  phone = 3;//手机号
+  string  newUserId = 4;//base_user_id 新用户id
+  int64  entId = 5;//企业id 没有企业 企业id=0
+  int64  entUserId = 6;//企业用户id  当前企业下的员工id 没有企业默认0
+  int64  pageNum = 7;//当前页码
+  int64  pageSize = 8;//每页数量
+  string  province = 9;//省份
+  string  city = 10;//城市
+  string  subtype = 11;//信息类型-二级
+  string  topType = 12;//信息类型-一级分类
+  string  publishTime = 13;//发布时间
+  string selectType = 14;//搜索范围:标题;正文等
+  string  price = 15;//价格
+  string industry = 16;//行业
+  string buyerClass = 17;//采购单位类型
+  string buyerTel = 18;//采购单位联系方式
+  string winnerTel = 19;//中标单位联系方式
+  string fileExists = 20;//是否有附件
+  int64 searchGroup = 21;//搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+  int64 searchMode = 22;//搜索模式:0:精准搜索;1:模糊搜索
+  int64 wordsMode = 23;//搜索关键词模式;默认0:包含所有,1:包含任意
+  string keyWords = 24;//关键词:多个空格隔开(主)
+  string additionalWords = 25;//关键词:附加关键词(副:五组,每组最多15个字符)
+  string exclusionWords = 26;//关键词:排除词(副:五组,每组最多15个字符)
+  string  userType = 27;//用户状态 fType:免费用户;pType:付费用户;vType:超级订阅用户;mType:大会员用户;eType:商机管理用户
+  string  platform = 28;//请求平台
+  bool  isPay = 29;//是否是付费用户
+  string interceptKeyWords = 30;//关键词截取后的关键词;
+  string interceptOtherWords = 31;//关键词截取后 后面三个字
+  string bidField = 32;//领域化标识
 }
 
 message SearchResp {
@@ -34,46 +44,61 @@ message SearchResp {
   SearchData data = 3;
 }
 message SearchData {
-  int64 count = 1;
-  string keyWords = 2;
-  int64  isLimit = 3;
-  repeated string historyKeys = 4;
-  repeated SearchList list = 5;
-  int64  totalPage = 6;
-  string interceptWord = 7;
-  int64  interceptLimit = 8;
-  string  interceptKeywords= 9;
+  int64 count = 1;//返回数据量
+  string keyWords = 2;//关键词
+  int64  isLimit = 3;//全文检索限制//限制正文、附件查询 //return 1 正常 //return -1 抱歉!由于系统繁忙暂时无法进行搜索,请1分钟后再试! //return -2 抱歉!由于系统繁忙暂时无法进行搜索,请稍后再试!
+  repeated string historyKeys = 4;//历史搜索关键词
+  repeated SearchList list = 5;//搜索列表
+  int64 total = 6;//查询总结果数量
+  string remark = 7;//备注
+  int64 interceptLimit = 8;//关键词截取长度
+  string interceptOtherWords= 9;//关键词截取剩余关键词
+  string interceptKeyWords= 10;//关键词截取后的关键词
 }
 
 message  SearchList {
-  string  id = 1;
-  string  area = 2;
-  string  areaUrl = 3;
-  string  buyerClass = 4;
-  string  city = 5;
-  string  detail = 6;
-  string  industry = 7;
-  string  industryUrl = 8;
-  int64  publishTime = 9;
-  string  subtype = 10;
-  string  subtypeUrl = 11;
-  bool fileExists = 12;
-  string  title = 13;
-  bool isCollected = 14;
-  int64 bidamount = 15;//中标金额
-  int64  budget = 16;//预算
-  string projectName = 17;//项目名称
-  string  buyer = 18;//采购单位
-  string winner = 19;//中标企业
-  int64 bidopenTime = 20;//开标时间
-  PInfo projectInfo = 21;//拟建项目信息
-  string projectCode = 22;//项目代码
-  string  site = 23;//网站名称
-  string spiderCode = 24;//网站代码
+  string id = 1;//信息id
+  string area = 2;//地区
+  string areaUrl = 3;//地区标签地址
+  string buyerClass = 4;//采购单位类型
+  string city = 5;//城市
+  string detail = 6;//正文搜索内容
+  string industry = 7;//行业标签
+  string industryUrl = 8;//行业标签地址
+  int64  publishTime = 9;//发布时间
+  bool   fileExists = 10;//是否有附件
+  string subtype = 11;//信息类型
+  string subtypeUrl = 12;//信息类型标签地址
+  string title = 13;//标题
+  bool   isCollected = 14;//信息是否被收藏
+  string projectName = 15;//项目名称
+  string projectCode = 16;//项目代码
+  int64  budget = 17;//预算
+  int64  bidAmount = 18;//中标金额
+  string buyer = 19;//采购单位
+  string buyerTel = 20;//采购单位联系电话
+  string buyerPerson = 21;//采购单位联系人
+  string agency = 22;//代理机构
+  string agencyPerson = 23;//代理机构联系人
+  string agencyTel = 24;//代理机构联系电话
+  repeated WinnerInfo winnerInfo = 25;//中标企业信息
+  int64 bidOpenTime = 26;//开标时间
+  int64 signEndTime = 27;//报名截止时间
+  int64 bidEndTime = 28;//投标截止时间
+  string site = 29;//网站名称
+  string spiderCode = 30;//网站代码
+  PInfo  projectInfo = 31;//拟建项目信息
+}
+//
+message WinnerInfo{
+  string winner = 1;
+  string winnerTel = 2;
+  string winnerPerson = 3;
+  string winnerId = 4;
 }
 //
 message PInfo {
-  string approveCode =1;//项目代码
+  string approveCode = 1;//项目代码
   string approveContent = 2;//项目内容
   string approveDept = 3;//审批部门
   string approveStatus = 4 ;//审批状态
@@ -84,12 +109,12 @@ message PInfo {
 //
 message SearchLimitReq {
   string appid = 1;
-  int64 timeOut = 2;
-  int64 count = 3;
-  int64 flag = 4;
+  int64  timeOut = 2;
+  int64  count = 3;
+  int64  flag = 4;
   int64  percentage = 5;
-  string  userId = 6;
-  string  searchType = 7;
+  string userId = 6;
+  string searchType = 7;
 }
 //
 message SearchLimitResp {

+ 266 - 0
jyBXCore/rpc/entity/search.go

@@ -0,0 +1,266 @@
+package entity
+
+import (
+	MC "app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/redis"
+	"encoding/json"
+	"fmt"
+	"github.com/zeromicro/go-zero/core/logx"
+	"jyBXCore/rpc/bxcore"
+	IC "jyBXCore/rpc/init"
+	"jyBXCore/rpc/service"
+	"jyBXCore/rpc/util"
+	"strings"
+	"time"
+)
+
+var (
+	SearchCacheKey   = "searchDataCache_%d_%s_%s_%s"
+	SearchCacheCount = "searchCountCache_%d_%s_%s_%s"
+)
+
+type KeyWordsSearch struct{}
+
+func NewKeyWordsSearch() *KeyWordsSearch {
+	return &KeyWordsSearch{}
+}
+
+// IsEmptySearch  是否是空搜索,如果是空搜索查缓存数据
+func (kws *KeyWordsSearch) IsEmptySearch(in *bxcore.SearchReq) bool {
+	//有主关键词 或 选择了行业,都不是空搜索
+	if strings.TrimSpace(in.KeyWords) != "" || strings.TrimSpace(in.Industry) != "" || strings.TrimSpace(in.AdditionalWords) != "" {
+		return false
+	}
+	//所有的未登录空搜索 缓存都最多查500条数据
+	return true
+}
+
+// GetBidSearchListByCache   查询缓存数据
+//未登录用户默认搜索和关键词搜索改成500条和免费用户保持一致--需求调整P260来自产品经理杨蘭20220116
+func (kws *KeyWordsSearch) GetBidSearchListByCache(in *bxcore.SearchReq) (list []*bxcore.SearchList, count, total int64) {
+	//缓存数据 最大量是5000条  100页数据
+	l, c := func(in *bxcore.SearchReq) (list []*bxcore.SearchList, count int64) {
+		//缓存数据总量 - 当前平台
+		redisCountKey := fmt.Sprintf(SearchCacheCount, in.SearchGroup, MC.If(in.IsPay, "v", "f").(string), MC.If(in.BidField != "", in.BidField, "n").(string), in.Platform)
+		count = int64(redis.GetInt(util.RedisNameNew, redisCountKey))
+		//缓存数据: SearchGroup-全部;招标信息;超前项目信息;kws.PageNum-当前页 免费用户 or 付费用户
+		redisDataKey := fmt.Sprintf(SearchCacheKey, in.SearchGroup, MC.If(in.IsPay, "v", "f").(string), MC.If(in.BidField != "", in.BidField, "n").(string), in.Platform)
+		sCache, err := redis.GetNewBytes(util.RedisNameNew, redisDataKey)
+		logx.Info("-------------------------redisDataKey--------------------------------:", redisDataKey)
+		if err == nil {
+			if sCache != nil && len(*sCache) > 0 {
+				err = json.Unmarshal(*sCache, &list)
+				if err == nil {
+					return
+				} else {
+					logx.Info("缓存序列化异常")
+				}
+			}
+		}
+		//无缓存数据 或 缓存数据查询异常
+		//查库>存redis缓存
+		//查询缓存数据 参数初始化
+		kws.DefaultSearchParamsAuto(in)
+		//缓存数据
+		count, list = service.GetBidSearchData(in, true)
+		if len(list) > 0 {
+			redis.Put(util.RedisNameNew, redisCountKey, count, MC.If(IC.C.DefaultSearchCacheTime > 0, IC.C.DefaultSearchCacheTime*60*60, 24*60*60).(int))
+			b, err := json.Marshal(list)
+			if err == nil {
+				redis.PutBytes(util.RedisNameNew, redisDataKey, &b, MC.If(IC.C.DefaultSearchCacheTime > 0, IC.C.DefaultSearchCacheTime*60*60, 24*60*60).(int))
+			} else {
+				logx.Info("默认搜索查询结果保存redis缓存异常")
+			}
+		} else {
+			logx.Info("默认搜索 暂无数据")
+		}
+		return
+	}(in)
+	if len(l) > 0 {
+		total = c
+		limitCount := int64(util.SearchPageSize * MC.If(in.IsPay, util.SearchMaxPageNum_PAYED, util.SearchMaxPageNum).(int))
+		count = c
+		if count > limitCount {
+			count = limitCount
+		}
+		list = l[(in.PageNum-1)*in.PageSize : in.PageNum*in.PageSize]
+		//是否收藏
+		util.MakeCollection(in.UserId, list)
+	}
+	return
+}
+
+// DefaultSearchParamsAuto 缓存查询条件初始化
+func (kws *KeyWordsSearch) DefaultSearchParamsAuto(in *bxcore.SearchReq) {
+	in.TopType = ""
+	in.City = ""
+	in.Industry = ""
+	in.FileExists = ""
+	in.WinnerTel = ""
+	in.BuyerTel = ""
+	in.BuyerClass = ""
+	in.Price = ""
+	in.SelectType = "title"
+	in.Province = ""
+}
+
+// SaveKeyWordsToHistory 保存历史记录
+func (kws *KeyWordsSearch) SaveKeyWordsToHistory(in *bxcore.SearchReq) {
+	if in.KeyWords != "" {
+		//历史记录
+		history := redis.GetStr("other", "s_"+in.UserId)
+		keys := util.SearchHistory(history, in.KeyWords, in.AdditionalWords)
+		if len(keys) > 0 {
+			if b := redis.Put("other", "s_"+in.UserId, strings.Join(keys, ","), -1); !b {
+				logx.Info("保存搜索记录异常,用户id:", in.UserId)
+			}
+		}
+	}
+}
+
+// GetSearchKeyWordsQueryStr 关键词和附加词处理 获取关键词查询条件;是否进行分词查询
+func (kws *KeyWordsSearch) GetSearchKeyWordsQueryStr(in *bxcore.SearchReq) (searchWords []string) {
+	// in.SearchMode 搜索模式:0:精准搜索;1:模糊搜索
+	// 精准搜索:不分词,完全匹配;(中间带空格的关键词组自动分词)
+	// 模糊搜索:对用户输入的单个关键词进行分词处理,但必须都存在;
+	//主关键词词组
+	if in.KeyWords != "" {
+		if in.SearchMode == 1 {
+			if ikWords := util.HttpEs(in.KeyWords, "ik_smart", IC.DB.Es.Addr); ikWords != "" {
+				in.KeyWords = ikWords
+			}
+		}
+		searchWords = append(searchWords, in.KeyWords)
+	}
+	//多组附加词,每组间,号隔开。每组内如果关键词中间有空格,自动分词
+	if in.AdditionalWords != "" {
+		if in.SearchMode == 1 {
+			var (
+				addWords []string
+			)
+			for _, awv := range strings.Split(in.AdditionalWords, ",") {
+				if strings.TrimSpace(awv) != "" {
+					if ikWords := util.HttpEs(awv, "ik_smart", IC.DB.Es.Addr); ikWords != "" {
+						addWords = append(addWords, ikWords)
+					}
+				}
+			}
+			if len(addWords) > 0 {
+				in.AdditionalWords = strings.Join(addWords, ",")
+			}
+		}
+		searchWords = append(searchWords, strings.Split(in.AdditionalWords, ",")...)
+	}
+	return
+}
+
+// SearchParamsHandle 搜索条件 处理
+func (kws *KeyWordsSearch) SearchParamsHandle(in *bxcore.SearchReq) []string {
+	//判断用户身份
+	userInfo := util.GetVipState(IC.MainMysql, IC.Mgo, in.UserId, in.EntId)
+	//是否是付费用户
+	in.IsPay = userInfo.IsPayedUser()
+	//默认搜索范围
+	if in.SelectType == "" {
+		in.SelectType = "title,content"
+	}
+	queryItems := userInfo.GetQueryItems(in.SelectType, IC.C.BidSearchOldUserLimit)
+	in.SelectType = strings.Join(queryItems, ",")
+	// in.SearchGroup 搜索分组 搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+	//	详情页判断是否能使用超前项目  老版超级订阅、大会员、商机管理有权限
+	if in.SearchGroup < 0 || in.SearchGroup > 2 {
+		in.SearchGroup = 1
+	}
+	//信息类型
+	if in.Subtype == "" && in.TopType == "" {
+		//(免费用户和新版超级订阅用户 有搜索权限,但是没有查看权限)
+		if in.SearchGroup > 0 && len(IC.C.DefaultTopTypes) >= int(in.SearchGroup) {
+			in.Subtype = IC.C.DefaultTopTypes[in.SearchGroup-1]
+		}
+	}
+	// in.SearchMode 搜索模式 搜索模式:0:精准搜索;1:模糊搜索
+	// 精准搜索:不分词,完全匹配;(中间带空格的关键词组自动分词)
+	// 模糊搜索:对用户输入的单个关键词进行分词处理,但必须都存在;
+	if in.SearchMode < 0 || in.SearchMode > 1 {
+		in.SearchMode = 0
+	}
+	// in.WordsMode 搜索关键词模式;默认0:包含所有,1:包含任意
+	if in.WordsMode < 0 || in.WordsMode > 1 {
+		in.WordsMode = 0
+	}
+	//查询时间publishTime
+	if in.PublishTime == "" {
+		//付费用户最新5年;免费用户||未登录用户最新1年
+		in.PublishTime = fmt.Sprintf("%d-%d", time.Now().AddDate(-1, 0, 0).Unix(), time.Now().Unix())
+		if userInfo.IsPayedUser() {
+			in.PublishTime = fmt.Sprintf("%d-%d", time.Now().AddDate(-5, 0, 0).Unix(), time.Now().Unix())
+		}
+	}
+	//默认每页数据量
+	if in.PageSize <= 0 {
+		in.PageSize = 50
+	}
+	//第一页
+	if in.PageNum <= 0 {
+		in.PageNum = 1
+	}
+	//行业格式化
+	if in.Industry != "" {
+		in.Industry = strings.TrimSpace(in.Industry)
+	}
+	//免费用户:高级筛选 采购单位类型、采购单位联系方式、中标企业联系方式、排除词、城市
+	if !userInfo.IsPayedUser() {
+		in.BuyerClass = ""
+		in.BuyerTel = ""
+		in.WinnerTel = ""
+		in.ExclusionWords = ""
+		in.City = ""
+		in.ExclusionWords = ""
+	}
+	//判断是否有关键词
+	if in.KeyWords != "" {
+		//关键词处理
+		in.KeyWords = strings.TrimSpace(in.KeyWords)
+		in.InterceptKeyWords, in.InterceptOtherWords, in.KeyWords = util.InterceptSearchKW(in.KeyWords, MC.IntAllDef(IC.C.KeywordsLimit, 35), len(in.Industry) == 0)
+	}
+	//附加词 每组附加词不能超过15个字符
+	if in.AdditionalWords != "" {
+		var additionalWords []string
+		for _, ak := range strings.Split(in.AdditionalWords, ",") {
+			if len([]rune(ak)) > 15 {
+				additionalWords = append(additionalWords, string([]rune(ak)[:15]))
+			} else {
+				additionalWords = append(additionalWords, ak)
+			}
+		}
+		in.AdditionalWords = strings.Join(additionalWords, ",") //分组不变
+	}
+	//更新关键词搜索历史记录
+	go kws.SaveKeyWordsToHistory(in)
+	//排除词  每组排除词不能超过15个字符
+	if in.ExclusionWords != "" {
+		var exclusionWords []string
+		for _, ak := range strings.Split(in.ExclusionWords, ",") {
+			if len([]rune(ak)) > 15 {
+				exclusionWords = append(exclusionWords, string([]rune(ak)[:15]))
+			} else {
+				exclusionWords = append(exclusionWords, ak)
+			}
+		}
+		in.ExclusionWords = strings.Join(exclusionWords, IC.C.JYKeyMark) //util.MatchSpace.ReplaceAllString(in.ExclusionWords, IC.C.JYKeyMark)
+	}
+	return kws.GetSearchKeyWordsQueryStr(in) //格式化关键词
+}
+
+// GetBidSearchList 非空搜索 查询
+func (kws *KeyWordsSearch) GetBidSearchList(in *bxcore.SearchReq) (count, total int64, list []*bxcore.SearchList) {
+	//排除异常in.PageNum参数
+	count, list = service.GetBidSearchData(in, false)
+	util.MakeCollection(in.UserId, list)
+	total = count //返回数据总量提示信息
+	limitCount := MC.If(in.IsPay, int64(util.SearchPageSize*util.SearchMaxPageNum_PAYED), int64(util.SearchPageSize*util.SearchMaxPageNum)).(int64)
+	if count > limitCount {
+		count = limitCount //付费用户count 最多5000条,100页数据,每页50条;免费用户count 最多500条,10页数据,每页50条。
+	}
+	return
+}

+ 13 - 4
jyBXCore/rpc/etc/bxcore.yaml

@@ -5,13 +5,13 @@ Etcd:
     - 127.0.0.1:2379
   Key: bxcore.rpc
 Timeout: 12000
-Webrpcport: 8013
+WebRpcPort: 8013
 BidSearchOldUserLimit: 1627920001
 LabelUrl:
   Area: /list/area/%s.html
-  Stype: /list/stype/%s.html
+  SType: /list/stype/%s.html
   Industry: /list/industry/%s.html
-PCSTime: 24
+DefaultSearchCacheTime: 24
 LimitSearchText:
   Flag: true
   Count: 40
@@ -31,4 +31,13 @@ PaySearchLimit:
   WordSize: 7
   PageNum: 1
   PageSize: 20
-KeywordsLimit: 35
+KeywordsLimit: 35 #主搜索框 关键词长度限制
+DefaultBidInfo: #默认搜索
+  PageNum: 10 #总页数
+  Count: 500 #查询数据量
+  PayCount: 5000 #付费用户查询数据量
+DefaultTopTypes:
+  - 招标预告,招标公告,招标结果,招标信用信息
+  - 拟建,采购意向
+JYKeyMark: " "
+ContextOldVipLimit: 1664553600

+ 1 - 0
jyBXCore/rpc/etc/db.yaml

@@ -9,6 +9,7 @@ mysql:
 redis:
     addr:
         - other=192.168.3.206:1712
+        - newother=192.168.3.206:1712
 es:
     addr: http://192.168.3.206:9800
     size: 50

+ 1 - 1
jyBXCore/rpc/init/label.go

@@ -34,7 +34,7 @@ func LabelInit() {
 			case 2:
 				url = fmt.Sprintf(C.LabelUrl.Industry, MC.ObjToString(v["code"]))
 			case 3:
-				url = fmt.Sprintf(C.LabelUrl.Stype, MC.ObjToString(v["code"]))
+				url = fmt.Sprintf(C.LabelUrl.SType, MC.ObjToString(v["code"]))
 			}
 			for _, nv := range strings.Split(names, ",") {
 				LabelMap[nv] = labelStruct{

+ 17 - 9
jyBXCore/rpc/internal/config/config.go

@@ -7,15 +7,15 @@ import (
 
 type Config struct {
 	zrpc.RpcServerConf
-	Webrpcport            int64
-	BidSearchOldUserLimit int64
+	WebRpcPort            int64
+	BidSearchOldUserLimit int64 //老用户 使用付费功能
 	LabelUrl              struct {
 		Area     string
-		Stype    string
+		SType    string
 		Industry string
 	}
-	PCSTime         int //清除搜索列表内存缓存 间隔时间
-	LimitSearchText struct {
+	DefaultSearchCacheTime int //清除搜索列表内存缓存 间隔时间
+	LimitSearchText        struct {
 		Flag       bool
 		Count      int
 		TimeOut    int
@@ -24,8 +24,8 @@ type Config struct {
 		Msg        string
 		LimitKey   string
 	}
-	SearchTypeSwitch bool
-	FileSignBool     bool
+	SearchTypeSwitch bool //标题和正文 同时查询,关键词>1;是否优化查询只查正文(正文包含标题)
+	FileSignBool     bool //IC.C.FileSignBool列表是否显示附件标识开关
 	PaySearchLimit   struct {
 		Switch   bool
 		Year     int
@@ -33,8 +33,16 @@ type Config struct {
 		WordSize int
 		PageNum  int64
 		PageSize int64
-	}
-	KeywordsLimit int
+	} //优化付费用户搜索速度
+	KeywordsLimit  int //关键词长度限制
+	DefaultBidInfo struct {
+		PageNum  int
+		Count    int
+		PayCount int
+	} //招标信息初始化
+	DefaultTopTypes    []string //信息类型初始值
+	JYKeyMark          string   //关键词分组标识
+	ContextOldVipLimit int64    //老版超级订阅 超前项目权限
 }
 
 type Db struct {

+ 47 - 168
jyBXCore/rpc/internal/logic/getsearchlistlogic.go

@@ -2,10 +2,8 @@ package logic
 
 import (
 	MC "app.yhyue.com/moapp/jybase/common"
-	"app.yhyue.com/moapp/jybase/redis"
 	"context"
-	"encoding/json"
-	"fmt"
+	"jyBXCore/rpc/entity"
 	IC "jyBXCore/rpc/init"
 	"jyBXCore/rpc/util"
 	"strings"
@@ -31,191 +29,72 @@ func NewGetSearchListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Get
 	}
 }
 
-// 标讯搜索结果列表数据
+// GetSearchList 标讯搜索结果列表数据
 func (l *GetSearchListLogic) GetSearchList(in *bxcore.SearchReq) (*bxcore.SearchResp, error) {
 	defer MC.Catch()
-	t := time.Now()
+	//用户身份 是否登录
+	if in.UserId == "" {
+		return &bxcore.SearchResp{
+			ErrCode: -1,
+			ErrMsg:  "用户信息异常",
+		}, nil
+	}
 	res := &bxcore.SearchData{
 		Count:          0,
 		List:           []*bxcore.SearchList{},
 		InterceptLimit: int64(MC.IntAllDef(IC.C.KeywordsLimit, 35)),
 	}
-	if in.UserId != "" {
-		//历史记录
-		history_str := redis.GetStr("other", "s_"+in.UserId)
-		arrs := util.SearchHistory(history_str, in.KeyWords)
-		//redis.Del("other", "s_"+in.UserId)
-		if len(arrs) > 0 {
-			redis.Put("other", "s_"+in.UserId, strings.Join(arrs, ","), -1)
-			//res.HistoryKeys = arrs
-		}
-	}
-	//
-	if in.SelectType == "" {
-		in.SelectType = "title,content"
+	//初始化搜索对象
+	ks := entity.NewKeyWordsSearch()
+	//处理搜索条件
+	heightWords := ks.SearchParamsHandle(in)
+	//判断是否是空搜索,如果是空搜索,查缓存数据
+	if ks.IsEmptySearch(in) {
+		res.List, res.Count, res.Total = ks.GetBidSearchListByCache(in)
+		return &bxcore.SearchResp{
+			Data:    res,
+			ErrMsg:  "",
+			ErrCode: 0,
+		}, nil
 	}
-	in.Industry = strings.TrimSpace(in.Industry)
-	userInfo := util.GetVipState(IC.MainMysql, IC.Mgo, in.UserId)
-	//付费用户
-	if in.UserType != "fType" && !userInfo.IsPayedUser() {
+	//异常付费用户  参数不是免费fType,但是又不是付费用户;还有一种是未登录用户 稍后处理
+	if in.UserType != "fType" && !in.IsPay {
 		return &bxcore.SearchResp{
 			ErrCode: -1,
 			ErrMsg:  "无权限",
 		}, nil
 	}
-	if in.UserType == "fType" {
-		in.BuyerClass = ""
-		in.BuyerTel = ""
-		in.WinnerTel = ""
-		in.ExclusionWords = ""
-		in.City = ""
-	}
-	in.KeyWords = strings.TrimSpace(in.KeyWords)
-	//搜索范围
-	queryItems := userInfo.GetQueryItems(in.SelectType, IC.C.BidSearchOldUserLimit)
-	in.SelectType = strings.Join(queryItems, ",")
-	//b_word, s_word := "", ""
+	t := time.Now()
+	//招标信息有效查询
 	res.IsLimit = 1
-	//以后可能会出现 关键词 C++ 等带+的关键词
-	if in.KeyWords != "" {
-		res.InterceptKeywords, res.InterceptWord, in.KeyWords = util.InterceptSearchKW(in.KeyWords, MC.IntAllDef(IC.C.KeywordsLimit, 35), len(in.Industry) == 0)
-	}
 	//查询数据
-	if in.KeyWords != "" || in.Industry != "" {
-		//查询数据
-		searchLimit := util.IsSearchLimit(strings.Split(in.SelectType, ","))
-		//全文检索限制
-		if searchLimit {
-			res.IsLimit = util.IsLimited(in.UserId, in.UserType != "fType")
-			if res.IsLimit == 1 { //没有被限制
-				defer util.Limit()
-			}
+	searchLimit := util.IsSearchLimit(strings.Split(in.SelectType, ","))
+	//全文检索限制
+	if searchLimit {
+		res.IsLimit = util.IsLimited(in.UserId, in.UserType != "fType")
+		if res.IsLimit == 1 { //没有被限制
+			defer util.Limit()
 		}
-		//无限制
-		if res.IsLimit == 1 {
-			var count int64
-			var list = []*bxcore.SearchList{}
-			//付费用户搜索优化
-			publishTime := in.PublishTime
+	}
+	//无限制
+	if res.IsLimit == 1 {
+		//付费用户搜索优化--默认搜索5年数据,数据量太多,接口反应太慢,前两页数据 时间范围根据配置缩小查询以达到快速查询的目的。
+		publishTime := in.PublishTime
+		if b := util.IsOptimize(IC.C, in); b {
 			t1 := time.Now()
-			if b := util.IsOptimize(IC.C, in); b {
-				count, list = util.GetBidSearchData(in)
-				count += 1 //避免刚好50条 无法加载下一页数据
-			}
-			logx.Info("1查询耗时", time.Since(t1))
+			res.Count, res.Total, res.List = ks.GetBidSearchList(in) // util.GetBidSearchData(in)
+			logx.Info("1查询耗时:", time.Since(t1))
+		}
+		//如果优化查询数据量太少,和配置数据量作比较,不够的话走原始查询
+		if res.Count < IC.C.PaySearchLimit.PageSize {
 			t2 := time.Now()
-			//分词后 第二页数据请求 先获取全部数据 再切割
-			if in.SplitKeywords != "" && strings.Contains(in.SplitKeywords, "+&&&") && in.PageNum == 2 {
-				in.KeyWords = strings.ReplaceAll(in.KeyWords, "+&&&", "")
-				in.PageNum = 1
-			}
-			//不够配置条 走原始查询
-			if count < IC.C.PaySearchLimit.PageSize {
-				in.PublishTime = publishTime
-				count, list = util.GetBidSearchData(in)
-			}
+			in.PublishTime = publishTime
+			res.Count, res.Total, res.List = ks.GetBidSearchList(in) //util.GetBidSearchData(in)
 			logx.Info("2查询耗时:", time.Since(t2))
-			res.KeyWords = in.KeyWords
-			//二次搜索- 一次搜索结果少于一页数据;关键词长度大于三;第一,二页请求;搜索范围包括title;四个条件
-			if len([]rune(in.KeyWords)) > 3 && int(count) < util.SearchPageSize && in.PageNum < 3 && strings.Contains(in.SelectType, "title") {
-				if iksk := util.HttpEs(in.KeyWords, "ik_smart", IC.DB.Es.Addr); iksk != "" {
-					t3 := time.Now()
-					iksk_temp := in.KeyWords
-					in.KeyWords = iksk
-					in.SelectType = "title"
-					//最多查两页数据
-					in.PageSize = 2 * in.PageSize
-					_, secondList := util.GetBidSearchData(in)
-					//数据合并 去重 排序
-					list = util.DelRepeatSearchData(list, secondList)
-					count = int64(len(list))
-					switch {
-					case count > util.SearchPageSize:
-						count = MC.If(count > int64(util.SearchPageSize*2), int64(util.SearchPageSize*2), count).(int64)
-						list = list[:util.SearchPageSize]
-						if in.SplitKeywords != "" {
-							list = list[util.SearchPageSize:count]
-						}
-					case count <= util.SearchPageSize:
-						list = list[:count]
-					}
-					var kbool = map[string]bool{}
-					var karr = []string{}
-					for _, v := range strings.Split(fmt.Sprintf("%s+%s", iksk_temp, iksk), "+") {
-						if kbool[v] {
-							continue
-						}
-						karr = append(karr, v)
-						kbool[v] = true
-					}
-					//+&&& 作为二次搜索第二页数据请求的标识(临时处理)
-					res.KeyWords = strings.Join(karr, "+") + "+&&&"
-					logx.Info("3查询耗时:", time.Since(t3))
-				}
-			}
-			limitCount := MC.If(in.UserType != "fType", int64(util.SearchPageSize*util.SearchMaxPageNum_PAYED), int64(util.SearchPageSize*util.SearchMaxPageNum)).(int64)
-			if count > limitCount {
-				count = limitCount
-			}
-			//是否收藏
-			//util.MakeCollection(in.UserId, list)
-			res.TotalPage = MC.If(in.PageNum == 1, (count+int64(util.SearchPageSize)-1)/int64(util.SearchPageSize), res.TotalPage).(int64)
-			res.Count = count
-			res.List = list
-		}
-		logx.Info("关键词 -0- 查询耗时:", time.Since(t).Seconds())
-	} else if in.Platform == "PC" {
-		var count int64 = 0
-		var list = []*bxcore.SearchList{}
-		redisDataKey := fmt.Sprintf("PC_SearchDataCache_%s_%d", in.Platform, in.PageNum)
-		sCache, err := redis.GetNewBytes(util.RedisName, redisDataKey)
-		if err == nil {
-			redisCountKey := fmt.Sprintf("PC_SearchCountCache_%s", in.Platform)
-			count = int64(redis.GetInt(util.RedisName, redisCountKey))
-			if sCache != nil && len(*sCache) > 0 {
-				err = json.Unmarshal(*sCache, &list)
-				if err != nil {
-					return &bxcore.SearchResp{
-						ErrCode: -1,
-						ErrMsg:  "缓存数据序列化异常:" + err.Error(),
-					}, nil
-				}
-			} else {
-				pcstime := IC.C.PCSTime * 60 * 60
-				//缓存数据
-				_in := &bxcore.SearchReq{
-					PageNum:  in.PageNum,
-					PageSize: in.PageSize,
-				}
-				count, list = util.SearchCahcheData(_in)
-				limitCount := int64(util.SearchPageSize * util.SearchMaxPageNum)
-				if count > limitCount {
-					count = limitCount
-				}
-				if len(list) > 0 {
-					redis.Put(util.RedisName, redisCountKey, count, pcstime)
-					b, err := json.Marshal(list)
-					if err == nil {
-						redis.PutBytes(util.RedisName, redisDataKey, &b, pcstime)
-					} else {
-						return &bxcore.SearchResp{
-							ErrCode: -1,
-							ErrMsg:  "缓存数据 转化异常:" + err.Error(),
-						}, nil
-					}
-				}
-			}
-			//是否收藏
-			util.MakeCollection(in.UserId, list)
-			res.TotalPage = MC.If(in.PageNum == 1, (count+int64(util.SearchPageSize)-1)/int64(util.SearchPageSize), res.TotalPage).(int64)
-			res.Count = count
-			res.List = list
-		} else {
-			return &bxcore.SearchResp{
-				ErrCode: -1,
-				ErrMsg:  "查询redis缓存异常:" + err.Error(),
-			}, nil
 		}
+		res.KeyWords = strings.Join(heightWords, " ")
+		res.InterceptOtherWords = in.InterceptOtherWords
+		res.InterceptKeyWords = in.InterceptKeyWords
 	}
 	logx.Info("关键词 -全部- 查询耗时:", time.Since(t).Seconds())
 	return &bxcore.SearchResp{

+ 1 - 1
jyBXCore/rpc/internal/logic/searchlimitlogic.go

@@ -27,7 +27,7 @@ func NewSearchLimitLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Searc
 	}
 }
 
-// 标讯搜索限制内容
+// SearchLimit 标讯搜索限制内容
 func (l *SearchLimitLogic) SearchLimit(in *bxcore.SearchLimitReq) (*bxcore.SearchLimitResp, error) {
 	if in.UserId == "" || !util.IsCanLogin(in.UserId) {
 		return &bxcore.SearchLimitResp{

+ 2 - 2
jyBXCore/rpc/internal/server/bxcoreserver.go

@@ -22,13 +22,13 @@ func NewBxCoreServer(svcCtx *svc.ServiceContext) *BxCoreServer {
 	}
 }
 
-// 标讯搜索结果列表数据
+// GetSearchList 标讯搜索结果列表数据
 func (s *BxCoreServer) GetSearchList(ctx context.Context, in *bxcore.SearchReq) (*bxcore.SearchResp, error) {
 	l := logic.NewGetSearchListLogic(ctx, s.svcCtx)
 	return l.GetSearchList(in)
 }
 
-// 标讯搜索限制内容
+// SearchLimit 标讯搜索限制内容
 func (s *BxCoreServer) SearchLimit(ctx context.Context, in *bxcore.SearchLimitReq) (*bxcore.SearchLimitResp, error) {
 	l := logic.NewSearchLimitLogic(ctx, s.svcCtx)
 	return l.SearchLimit(in)

+ 46 - 15
jyBXCore/rpc/model/es/es.go

@@ -3,20 +3,50 @@ package es
 import (
 	elastic "app.yhyue.com/moapp/jybase/esv1"
 	"fmt"
+	"github.com/zeromicro/go-zero/core/logx"
 	"strconv"
 	"strings"
 )
 
 const (
-	highlightStr = `"%s": {"fragment_size": %d,"number_of_fragments": 1}`
-	HL           = `"highlight": {"pre_tags": [""],"post_tags": [""],"fields": {%s}}`
+	queryBoolMustTermDomain = `{"bool": {"must": [{ "term": {"bid_field": "%s" }}]}}` // 领域化数据类型
+	multiMatch              = `{"multi_match": {"query": "%s","type": "phrase", "fields": [%s]}}`
+	query                   = `{"query":{"bool":{"must":[%s],"must_not":[%s]}}}`
+	queryBoolShould         = `{"bool":{"should":[%s],"minimum_should_match": 1}}`
+	queryBoolMustBoolShould = `{"bool":{"must":[{"range":{"bidamount":{%s}}}]}},{"bool":{"must":[{"range":{"budget":{%s}}}],"must_not":[{"range":{"bidamount":{"gte":-1}}}]}}`
+	queryBoolMust           = `{"bool":{"must":[{"terms":{"s_subscopeclass":[%s]}}]}}`
+	queryBoolMustTerm       = `{"bool": {"must": [{ "term": {"isValidFile": %d }}]}}`
+	queryMissing            = `{"constant_score":{"filter":{"missing":{"field":"%s"}}}}`
+	gte                     = `"gte": %s`
+	lte                     = `"lte": %s`
+	HighlightStr            = `"%s": {"fragment_size": %d,"number_of_fragments": 1}`
+	HL                      = `"highlight": {"pre_tags": [""],"post_tags": [""],"fields": {%s}}`
+	INDEX                   = "bidding"
+	TYPE                    = "bidding"
+	BidSearchSort           = `{"dataweight":-1,"publishtime":-1}`
+	BidSearchFieldBase      = `"_id","title","publishtime","dataweight","toptype","subtype","type","area","city","s_subscopeclass","bidamount","budget","buyerclass","spidercode","site"`                                                    //搜索列表基础字段
+	BidSearchFieldOfVip     = BidSearchFieldBase + `,"buyer","buyertel","buyerperson","agency","agencytel","agencyperson","s_winner","winnertel","winnerperson","signendtime","bidendtime","bidopentime","budget","projectinfo","entidlist"` //付费列表字段
+	BidSearchFieldFile      = `,"isValidFile"`                                                                                                                                                                                               //根据配置开关 选择是否显示 是否有附件提示,IC.C.FileSignBool
+	BidSearchDomainField    = BidSearchFieldOfVip + `,"purchasing"`                                                                                                                                                                          //领域数据字段基本字段
+	//DefaultFields       = `"title"`                                                                                                                                                                                                      //最新招标信息
 )
 
-var SR = strings.Replace
+var (
+	SR = strings.Replace
+	//信息类型 一级类型参数和数据类型转换
+	topTypeMap = map[string]string{
+		"招标预告":   "预告",
+		"招标公告":   "招标",
+		"招标结果":   "结果",
+		"招标信用信息": "其它",
+		"拟建项目":   "拟建",
+		"采购意向":   "采购意向",
+	}
+)
 
-type EsSearch struct {
+type SearchByES struct {
 	Index      string
-	Itype      string
+	IType      string
 	Query      string
 	FindFields string
 	Order      string
@@ -27,27 +57,28 @@ type EsSearch struct {
 	HighLight  bool
 }
 
-//
-func (e *EsSearch) GetAllByNgramWithCount() (int64, *[]map[string]interface{}) {
-	qstr := e.Query
+// GetAllByNgramWithCount  获取es查询结果及总数量
+func (e *SearchByES) GetAllByNgramWithCount() (int64, *[]map[string]interface{}) {
 	if e.Query != "" {
+		queryStr := e.Query
 		if e.HighLight {
-			ws := []string{}
+			var ws []string
 			for _, w := range strings.Split(e.FindFields, ",") {
-				ws = append(ws, fmt.Sprintf(highlightStr, w, e.Count))
+				ws = append(ws, fmt.Sprintf(HighlightStr, w, e.Count))
 			}
-			qstr = qstr[:len(qstr)-1] + `,` + fmt.Sprintf(HL, strings.Join(ws, ",")) + `}`
+			queryStr = queryStr[:len(queryStr)-1] + `,` + fmt.Sprintf(HL, strings.Join(ws, ",")) + `}`
 		}
 		if len(e.Fields) > 0 {
-			qstr = qstr[:len(qstr)-1] + `,"_source":[` + e.Fields + "]}"
+			queryStr = queryStr[:len(queryStr)-1] + `,"_source":[` + e.Fields + "]}"
 		}
 		if len(e.Order) > 0 {
-			qstr = qstr[:len(qstr)-1] + `,"sort":[` + SR(SR(SR(SR(e.Order, ",", "},{", -1), " ", "", -1), ":-1", `:"desc"`, -1), ":1", `:"asc"`, -1) + `]}`
+			queryStr = queryStr[:len(queryStr)-1] + `,"sort":[` + SR(SR(SR(SR(e.Order, ",", "},{", -1), " ", "", -1), ":-1", `:"desc"`, -1), ":1", `:"asc"`, -1) + `]}`
 		}
 		if e.Start > -1 {
-			qstr = qstr[:len(qstr)-1] + `,"from":` + strconv.Itoa(e.Start) + `,"size":` + strconv.Itoa(e.Limit) + "}"
+			queryStr = queryStr[:len(queryStr)-1] + `,"from":` + strconv.Itoa(e.Start) + `,"size":` + strconv.Itoa(e.Limit) + "}"
 		}
-		return elastic.GetWithCount(e.Index, e.Itype, qstr)
+		logx.Info("queryStr:", queryStr)
+		return elastic.GetWithCount(e.Index, e.IType, queryStr)
 	} else {
 		return 0, nil
 	}

+ 325 - 0
jyBXCore/rpc/model/es/search.go

@@ -0,0 +1,325 @@
+package es
+
+import (
+	MC "app.yhyue.com/moapp/jybase/common"
+	elastic "app.yhyue.com/moapp/jybase/esv1"
+	"fmt"
+	"github.com/zeromicro/go-zero/core/logx"
+	"jyBXCore/rpc/bxcore"
+	IC "jyBXCore/rpc/init"
+	"strconv"
+	"strings"
+)
+
+// GetSearchQuery  整理关键词等查询条件
+func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
+	var (
+		//搜索范围是否只有附件
+		//搜索范围只选择附件,是否有附件条件无效;
+		isFileSearch                            = in.SelectType == "filetext"
+		wordsMusts, wordsShould, musts, mustNot []string
+		findFields                              string
+		selectTypeArr                           = strings.Split(in.SelectType, ",")
+	)
+	if selectTypeArr == nil || len(selectTypeArr) == 0 {
+		findFields = `"title"`
+	} else {
+		findFields = fmt.Sprintf(`"%s"`, strings.Join(selectTypeArr, "\",\""))
+	}
+	switchBool := strings.Contains(findFields, "detail") && strings.Contains(findFields, "title") && IC.C.SearchTypeSwitch
+	if mustQuery != "" {
+		musts = append(musts, mustQuery)
+	}
+	//此时关键词中间有IC.C.JYKeyMark进行隔离
+	if in.KeyWords != "" {
+		var (
+			keyWordsMusts []string
+		)
+		for _, v := range strings.Split(in.KeyWords, IC.C.JYKeyMark) {
+			if elastic.ReplaceYH(v) == "" {
+				continue
+			}
+			//单个字  搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
+			//detail 正文不支持单字查询
+			if len([]rune(elastic.ReplaceYH(v))) == 1 && DetailFileORTitle(findFields) {
+				findFields += `,"title"`
+			} else if switchBool && len([]rune(elastic.ReplaceYH(v))) > 1 {
+				//标题 全文搜索 搜索类型开关打开 默认搜索全文;(全文包含标题)(单字排除)
+				if strings.Contains(findFields, `"title",`) {
+					findFields = strings.Replace(findFields, `"title",`, ``, -1)
+				} else if strings.Contains(findFields, `,"title"`) {
+					findFields = strings.Replace(findFields, `,"title"`, ``, -1)
+				}
+			}
+			keyWordsMusts = append(keyWordsMusts, fmt.Sprintf(fmt.Sprintf(multiMatch, "%s", findFields), elastic.ReplaceYH(v)))
+		}
+		//搜索关键词模式;默认0:包含所有,1:包含任意
+		if in.WordsMode == 1 {
+			wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(keyWordsMusts, ",")))
+		} else {
+			wordsMusts = append(wordsMusts, keyWordsMusts...)
+		}
+	}
+	//附加词
+	if in.AdditionalWords != "" {
+		//多组附加词,每组间,号隔开。每组内如果关键词中间有空格,自动分词
+		var (
+			addWordsMusts []string
+		)
+		for _, aws := range strings.Split(in.AdditionalWords, ",") {
+			var (
+				addWordsMust []string
+			)
+			for _, v := range strings.Split(aws, IC.C.JYKeyMark) {
+				if elastic.ReplaceYH(v) == "" {
+					continue
+				}
+				//单个字  搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
+				//detail 正文不支持单字查询
+				if len([]rune(elastic.ReplaceYH(v))) == 1 && DetailFileORTitle(findFields) {
+					findFields += `,"title"`
+				} else if switchBool && len([]rune(elastic.ReplaceYH(v))) > 1 {
+					//标题 全文搜索 搜索类型开关打开 默认搜索全文;(全文包含标题)(单字排除)
+					if strings.Contains(findFields, `"title",`) {
+						findFields = strings.Replace(findFields, `"title",`, ``, -1)
+					} else if strings.Contains(findFields, `,"title"`) {
+						findFields = strings.Replace(findFields, `,"title"`, ``, -1)
+					}
+				}
+				addWordsMust = append(addWordsMust, fmt.Sprintf(fmt.Sprintf(multiMatch, "%s", findFields), elastic.ReplaceYH(v)))
+				addWordsMusts = append(addWordsMusts, addWordsMust...)
+				if in.WordsMode == 0 {
+					wordsMusts = append(wordsMusts, addWordsMust...)
+				}
+				addWordsMust = []string{}
+			}
+			//搜索关键词模式;默认0:包含所有,1:包含任意
+			if in.WordsMode == 1 {
+				wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(addWordsMusts, ",")))
+				addWordsMusts = []string{}
+			}
+		}
+	}
+	//搜索关键词模式;默认0:包含所有,1:包含任意
+	//包含任意一组
+	if len(wordsShould) > 0 {
+		musts = append(musts, fmt.Sprintf(queryBoolShould, strings.Join(wordsShould, ",")))
+	} else if len(wordsMusts) > 0 {
+		musts = append(musts, fmt.Sprintf(elastic.NgramMust, strings.Join(wordsMusts, ",")))
+	}
+	//排除词
+	if notKey := strings.TrimSpace(in.ExclusionWords); notKey != "" {
+		notKeyMultiMatch := fmt.Sprintf(multiMatch, "%s", findFields)
+		var notKeyMustNot []string
+		//多组排除词
+		for _, nks := range strings.Split(notKey, ",") {
+			//单组排除词 空格分割
+			for _, v := range strings.Split(nks, IC.C.JYKeyMark) {
+				v = strings.TrimSpace(v)
+				if v == "" {
+					continue
+				}
+				if len([]rune(elastic.ReplaceYH(v))) == 1 {
+					//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
+					if DetailFileORTitle(findFields) {
+						notKeyMultiMatch = fmt.Sprintf(multiMatch, "%s", findFields+`,"title"`)
+					}
+				}
+				notKeyMustNot = append(notKeyMustNot, fmt.Sprintf(notKeyMultiMatch, elastic.ReplaceYH(v)))
+			}
+		}
+		mustNot = append(mustNot, fmt.Sprintf(queryBoolShould, strings.Join(notKeyMustNot, ",")))
+	}
+	//行业
+	if in.Industry != "" {
+		musts = append(musts, fmt.Sprintf(queryBoolMust, `"`+strings.ReplaceAll(in.Industry, ",", `","`)+`"`))
+	}
+	//价格
+	if in.Price != "" && len(strings.Split(in.Price, "-")) > 1 {
+		minPrice, maxPrice := strings.Split(in.Price, "-")[0], strings.Split(in.Price, "-")[1]
+		if minPrice != "" || maxPrice != "" {
+			sq := ``
+			if minPrice != "" {
+				min, _ := strconv.ParseFloat(minPrice, 64)
+				minPrice = fmt.Sprintf("%.0f", min*10000)
+				if minPrice == "0" {
+					minPrice = ""
+				}
+			}
+			if maxPrice != "" {
+				max, _ := strconv.ParseFloat(maxPrice, 64)
+				maxPrice = fmt.Sprintf("%.0f", max*10000)
+				if maxPrice == "0" {
+					maxPrice = ""
+				}
+			}
+			if minPrice != "" {
+				sq += fmt.Sprintf(gte, minPrice)
+			}
+			if minPrice != "" && maxPrice != "" {
+				sq += `,`
+			}
+			if maxPrice != "" {
+				sq += fmt.Sprintf(lte, maxPrice)
+			}
+			if minPrice != "" || maxPrice != "" {
+				query_price := fmt.Sprintf(queryBoolShould, fmt.Sprintf(queryBoolMustBoolShould, sq, sq))
+				musts = append(musts, query_price)
+			}
+		}
+	}
+	//采购单位联系方式
+	hasBuyerTel := in.BuyerTel
+	if hasBuyerTel != "" {
+		if hasBuyerTel == "y" {
+			mustNot = append(mustNot, fmt.Sprintf(queryMissing, "buyertel"))
+		} else {
+			musts = append(musts, fmt.Sprintf(queryMissing, "buyertel"))
+		}
+	}
+	//中标企业联系方式
+	hasWinnerTel := in.WinnerTel
+	if hasWinnerTel != "" {
+		if hasWinnerTel == "y" {
+			mustNot = append(mustNot, fmt.Sprintf(queryMissing, "winnertel"))
+		} else {
+			musts = append(musts, fmt.Sprintf(queryMissing, "winnertel"))
+		}
+	}
+	//附件
+	fileExists := in.FileExists
+	if !isFileSearch && fileExists != "" {
+		if fileExists == "1" { //有附件
+			mustNot = append(mustNot, fmt.Sprintf(queryMissing, "isValidFile"))
+			musts = append(musts, fmt.Sprintf(queryBoolMustTerm, 1))
+		} else if fileExists == "-1" { //无附件
+			musts = append(musts, fmt.Sprintf(queryMissing, "isValidFile"))
+		}
+	}
+	// 如果是领域化数据则需要加标签
+	if in.BidField != "" {
+		musts = append(musts, fmt.Sprintf(queryBoolMustTermDomain, in.BidField))
+	}
+	qstr = fmt.Sprintf(query, strings.Join(musts, ","), strings.Join(mustNot, ","))
+	logx.Info("qstr:", qstr)
+	return
+}
+
+// GetBidSearchQuery  整理地区、城市、发布时间、信息类型、采购单位类型 查询条件
+func GetBidSearchQuery(in *bxcore.SearchReq) string {
+	query := ``
+	//省份
+	area := in.Province
+	if area != "" {
+		query += `{"terms":{"area":[`
+		for k, v := range strings.Split(area, ",") {
+			if k > 0 {
+				query += `,`
+			}
+			query += `"` + v + `"`
+		}
+		query += `]}}`
+	}
+	//
+	city := in.City
+	if city != "" {
+		if len(query) > 0 {
+			query += ","
+		}
+		query += `{"terms":{"city":[`
+		for k, v := range strings.Split(city, ",") {
+			if k > 0 {
+				query += `,`
+			}
+			query += `"` + v + `"`
+		}
+		query += `]}}`
+	}
+	if query != "" {
+		query = fmt.Sprintf(queryBoolShould, query)
+	}
+	//发布时间
+	publishTime := in.PublishTime
+	if publishTime != "" && len(strings.Split(publishTime, "-")) > 1 {
+		if len(query) > 0 {
+			query += ","
+		}
+		startTime := strings.Split(publishTime, "-")[0]
+		endTime := strings.Split(publishTime, "-")[1]
+		query += `{"range":{"publishtime":{`
+		if startTime != "" {
+			query += `"gte":` + startTime
+		}
+		if startTime != "" && endTime != "" {
+			query += `,`
+		}
+		if endTime != "" {
+			query += `"lt":` + endTime
+		}
+		query += `}}}`
+	}
+	//信息类型-二级
+	subtype := in.Subtype
+	topType := MC.If(in.TopType != "", strings.Split(in.TopType, ","), []string{}).([]string)
+	allType := ``
+	//二级分类
+	if subtype != "" {
+		var typeInt = 0
+		allType += `{"terms":{"subtype":[`
+		for k, v := range strings.Split(subtype, ",") {
+			if tType := MC.If(topTypeMap[v] != "" && in.TopType == "", topTypeMap[v], "").(string); tType != "" {
+				topType = append(topType, tType)
+				typeInt += 1
+				continue
+			}
+			if k > typeInt {
+				allType += `,`
+			}
+			allType += `"` + v + `"`
+		}
+		allType += `]}}`
+	}
+	//信息类型  一级分类
+	logx.Info("topType:", topType)
+	if len(topType) > 0 {
+		if allType != "" {
+			allType += ","
+		}
+		allType += `{"terms":{"toptype":[`
+		for k, v := range topType {
+			if k > 0 {
+				allType += `,`
+			}
+			allType += `"` + v + `"`
+		}
+		allType += `]}}`
+	}
+
+	if allType != "" {
+		if query != "" {
+			query += ","
+		}
+		query += fmt.Sprintf(queryBoolShould, allType)
+	}
+	//采购单位类型
+	buyerClass := in.BuyerClass
+	if buyerClass != "" {
+		if len(query) > 0 {
+			query += ","
+		}
+		query += `{"terms":{"buyerclass":[`
+		for k, v := range strings.Split(buyerClass, ",") {
+			if k > 0 {
+				query += `,`
+			}
+			query += `"` + v + `"`
+		}
+		query += `]}}`
+	}
+	return query
+}
+
+// DetailFileORTitle 包含正文或 附件 不包含标题
+func DetailFileORTitle(findFields string) bool {
+	return (strings.Contains(findFields, `"detail"`) || strings.Contains(findFields, `"filetext"`)) && !strings.Contains(findFields, `"title"`)
+}

+ 0 - 300
jyBXCore/rpc/model/es/searchQuery.go

@@ -1,300 +0,0 @@
-package es
-
-import (
-	MC "app.yhyue.com/moapp/jybase/common"
-	elastic "app.yhyue.com/moapp/jybase/esv1"
-	"fmt"
-	"jyBXCore/rpc/entity"
-	"strconv"
-	"strings"
-	"time"
-)
-
-const (
-	queryByIds        = `{"query":{"bool":{"must":[{"terms":{"_id":[%s]}}]}}}`
-	multiMatch        = `{"multi_match": {"query": %s,"type": "phrase", "fields": [%s]}}`
-	query             = `{"query":{"bool":{"must":[%s],"must_not":[%s],"should":[%s],"minimum_should_match": %d}}}`
-	queryBoolShould   = `{"bool":{"should":[%s],"minimum_should_match": 1}}`
-	queryPrice        = `{"bool":{"must":[{"range":{"bidamount":{%s}}}]}},{"bool":{"must":[{"range":{"budget":{%s}}}],"must_not":[{"range":{"bidamount":{"gte":-1}}}]}}`
-	queryBoolMust     = `{"terms":{"%s":[%s]}}`
-	queryBoolMustAnd  = `{"bool":{"must":[%s]%s}}`
-	queryMissing      = `{"constant_score":{"filter":{"missing":{"field":"%s"}}}}`
-	queryBoolMustTerm = `{"bool": {"must": [{ "term": {"isValidFile": %d }}]}}`
-	gte               = `"gte": %s`
-	lte               = `"lte": %s`
-	queryPublishTime  = `{"range":{"publishtime":{%s}}}`
-)
-
-var topType = map[string]string{
-	"招标预告":   "预告",
-	"招标公告":   "招标",
-	"招标结果":   "结果",
-	"招标信用信息": "其它",
-	"拟建项目":   "拟建",
-	"采购意向":   "采购意向",
-}
-
-type SearchQuery struct{}
-
-func (s *SearchQuery) BiddingSearchQuery(bsp *entity.BiddingSearchParams) (qstr string) {
-	if len(bsp.SelectIds) > 0 {
-		return fmt.Sprintf(queryByIds, `"`+strings.Join(bsp.SelectIds, `","`)+`"`)
-	}
-
-	var bools []string
-	var musts = []string{fmt.Sprintf(`{"range":{"comeintime":{"lt":%d}}}`, bsp.ComeInTime)}
-	var mustNot []string
-	//地区
-	var area []string
-	//省份
-	if len(bsp.Province) > 0 {
-		areaquery := `{"terms":{"area":[`
-		for k, v := range bsp.Province {
-			if k > 0 {
-				areaquery += `,`
-			}
-			areaquery += `"` + v + `"`
-		}
-		areaquery += `]}}`
-		area = append(area, areaquery)
-	}
-	//城市
-	if len(bsp.City) > 0 {
-		areaquery := `{"terms":{"city":[`
-		for k, v := range bsp.City {
-			if k > 0 {
-				areaquery += `,`
-			}
-			areaquery += `"` + v + `"`
-		}
-		areaquery += `]}}`
-		area = append(area, areaquery)
-	}
-	if len(area) > 0 {
-		musts = append(musts, fmt.Sprintf(queryBoolShould, strings.Join(area, ",")))
-	}
-	//检索日期
-	//发布时间
-	startTime := ""
-	now := time.Unix(bsp.ComeInTime, 0)
-	endTime := fmt.Sprintf("%d", now.Unix())
-	if strings.Contains(bsp.PublishTime, "_") { //设置检索日期
-		timeQuery := ``
-		startTime = strings.Split(bsp.PublishTime, "_")[0]
-		endTimeTmp := now
-		if etime := strings.Split(bsp.PublishTime, "_")[1]; etime != "" {
-			etTime := time.Unix(MC.Int64All(etime), 0)
-			endTimeTmp = time.Date(etTime.Year(), etTime.Month(), etTime.Day()+1, 0, 0, 0, 0, time.Local)
-		}
-		//结束时间必须小于筛选时间
-		if endTimeTmp.After(now) {
-			endTimeTmp = now
-		}
-		endTime = fmt.Sprintf("%d", endTimeTmp.Unix())
-		if startTime != "" {
-			timeQuery += fmt.Sprintf(gte, startTime)
-		}
-		if startTime != "" && endTime != "" {
-			timeQuery += `,`
-		}
-		if endTime != "" {
-			timeQuery += fmt.Sprintf(lte, endTime)
-		}
-		musts = append(musts, fmt.Sprintf(queryPublishTime, timeQuery))
-	}
-	//信息类型 toptype 一级;subtype 二级;
-	if bsp.Subtype != "" || bsp.Toptype != "" {
-		var subQuery string
-		var topTypes = strings.Split(bsp.Toptype, ",")
-		var subTypes = strings.Split(bsp.Subtype, ",")
-		for _, v := range strings.Split(bsp.Subtype, ",") {
-			if v1, ok := topType[v]; ok {
-				topTypes = append(topTypes, fmt.Sprintf(`"%s"`, v1))
-			} else {
-				subTypes = append(subTypes, fmt.Sprintf(`"%s"`, v))
-			}
-		}
-		if len(subTypes) > 0 && len(topTypes) > 0 {
-			subQuery = fmt.Sprintf(`{"bool": {"should": [{"terms": {"subtype": [%s]}},{"terms": {"toptype": [%s]}}]}}`, strings.Join(subTypes, ","), strings.Join(topTypes, ","))
-		} else if len(subTypes) > 0 {
-			subQuery = fmt.Sprintf(`{"terms":{"subtype":[%s]}}`, strings.Join(subTypes, ","))
-		} else if len(topTypes) > 0 {
-			subQuery = fmt.Sprintf(`{"terms":{"toptype":[%s]}}`, strings.Join(topTypes, ","))
-		}
-		musts = append(musts, subQuery)
-	}
-	//行业
-	if len(bsp.Industry) > 0 {
-		musts = append(musts, fmt.Sprintf(queryBoolMust, "s_subscopeclass", `"`+strings.Join(bsp.Industry, `","`)+`"`))
-	}
-	//采购单位
-	if len(bsp.Buyer) > 0 {
-		musts = append(musts, fmt.Sprintf(queryBoolMust, "buyer", `"`+strings.Join(bsp.Buyer, `","`)+`"`))
-	}
-	//采购单位类型
-	if len(bsp.BuyerClass) > 0 {
-		musts = append(musts, fmt.Sprintf(queryBoolMust, "buyerclass", `"`+strings.Join(bsp.BuyerClass, `","`)+`"`))
-	}
-	//中标单位
-	if len(bsp.Winner) > 0 {
-		musts = append(musts, fmt.Sprintf(queryBoolMust, "s_winner", `"`+strings.Join(bsp.Winner, `","`)+`"`))
-	}
-	//价格区间
-	if bsp.MinPrice != "" || bsp.MaxPrice != "" {
-		_minPrice := ""
-		_maxPrice := ""
-		sq := ``
-		if bsp.MinPrice != "" {
-			min, _ := strconv.ParseFloat(bsp.MinPrice, 64)
-			_minPrice = fmt.Sprintf("%.0f", min*10000)
-			if _minPrice == "0" {
-				_minPrice = ""
-			}
-		}
-		if bsp.MaxPrice != "" {
-			max, _ := strconv.ParseFloat(bsp.MaxPrice, 64)
-			_maxPrice = fmt.Sprintf("%.0f", max*10000)
-			if _maxPrice == "0" {
-				_maxPrice = ""
-			}
-		}
-		if _minPrice != "" {
-			sq += fmt.Sprintf(gte, _minPrice)
-		}
-		if _minPrice != "" && _maxPrice != "" {
-			sq += `,`
-		}
-		if _maxPrice != "" {
-			sq += fmt.Sprintf(lte, _maxPrice)
-		}
-		if _minPrice != "" || _maxPrice != "" {
-			musts = append(musts, fmt.Sprintf(queryBoolShould, fmt.Sprintf(queryPrice, sq, sq)))
-		}
-	}
-	boolsNum := 0
-	selectType := bsp.SelectType
-	//关键词
-	if len(bsp.Keyword) > 0 {
-		boolsNum = 1
-		queryItem := ""
-		if selectType == "" {
-			queryItem = "title"
-		} else if selectType == "all" {
-			queryItem = "detail\", \"title"
-		} else {
-			//搜索开关打开  包含标题和正文  只匹配正文
-			if bsp.SearchTypeSwitch && s.DetailANDTitle(selectType) {
-				if strings.Contains(selectType, "title,") {
-					selectType = strings.Replace(selectType, "title,", "", -1)
-				} else if strings.Contains(selectType, ",title") {
-					selectType = strings.Replace(selectType, ",title", "", -1)
-				}
-			}
-			queryItem = strings.ReplaceAll(selectType, ",", "\",\"")
-		}
-		multiMatchNew := fmt.Sprintf(multiMatch, "%s", "\""+queryItem+"\"")
-		for _, v := range bsp.Keyword {
-			var should []string
-			var mustNot []string
-			if v.Keyword != "" {
-				if strings.Contains(v.Keyword, "+") {
-					for _, vk := range strings.Split(v.Keyword, "+") {
-						//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
-						if bsp.ComeInFrom == "supersearchPage" && s.DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(vk))) == 1 {
-							queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
-							shouldKeys := fmt.Sprintf(multiMatch, "\""+vk+"\"", "\""+queryItem+"\"")
-							should = append(should, shouldKeys)
-						} else {
-							should = append(should, fmt.Sprintf(multiMatchNew, "\""+vk+"\""))
-						}
-					}
-				} else if strings.Contains(v.Keyword, " ") {
-					for _, vk := range strings.Split(v.Keyword, " ") {
-						//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
-						if bsp.ComeInFrom == "supersearchPage" && s.DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(vk))) == 1 {
-							queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
-							shouldKeys := fmt.Sprintf(multiMatch, "\""+vk+"\"", "\""+queryItem+"\"")
-							should = append(should, shouldKeys)
-						} else {
-							should = append(should, fmt.Sprintf(multiMatchNew, "\""+vk+"\""))
-						}
-					}
-				} else {
-					//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
-					if bsp.ComeInFrom == "supersearchPage" && s.DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(v.Keyword))) == 1 {
-						queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
-						shouldKeys := fmt.Sprintf(multiMatch, "\""+v.Keyword+"\"", "\""+queryItem+"\"")
-						should = append(should, shouldKeys)
-					} else {
-						should = append(should, fmt.Sprintf(multiMatchNew, "\""+v.Keyword+"\""))
-					}
-				}
-			}
-
-			//附加词
-			for _, vv := range v.Appended {
-				should = append(should, fmt.Sprintf(multiMatchNew, "\""+vv+"\""))
-			}
-
-			//排除词
-			for _, vv := range v.Exclude {
-				//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
-				if bsp.ComeInFrom == "supersearchPage" && s.DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(vv))) == 1 {
-					queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
-					shouldKeys := fmt.Sprintf(multiMatch, "\""+vv+"\"", "\""+queryItem+"\"")
-					should = append(should, shouldKeys)
-				} else {
-					mustNot = append(mustNot, fmt.Sprintf(multiMatchNew, "\""+vv+"\""))
-				}
-			}
-
-			//添加
-			if len(should) > 0 {
-				notStr := ""
-				if len(mustNot) > 0 {
-					notStr = fmt.Sprintf(`,"must_not":[%s]`, strings.Join(mustNot, ","))
-				}
-				bools = append(bools, fmt.Sprintf(queryBoolMustAnd, strings.Join(should, ","), notStr))
-			}
-		}
-	}
-	//采购单位联系方式
-	if bsp.HasBuyerTel != "" {
-		if bsp.HasBuyerTel == "y" {
-			mustNot = append(mustNot, fmt.Sprintf(queryMissing, "buyertel"))
-		} else {
-			musts = append(musts, fmt.Sprintf(queryMissing, "buyertel"))
-		}
-	}
-	//中标企业联系方式
-	if bsp.HasWinnerTel != "" {
-		if bsp.HasWinnerTel == "y" {
-			mustNot = append(mustNot, fmt.Sprintf(queryMissing, "winnertel"))
-		} else {
-			musts = append(musts, fmt.Sprintf(queryMissing, "winnertel"))
-		}
-	}
-	//搜索范围是否只有附件
-	//搜索范围只选择附件,是否有附件条件无效;
-	var isFileSearch = strings.ReplaceAll(selectType, ",", "\",\"") == "filetext"
-	if !isFileSearch && bsp.FileExists != "" {
-		if bsp.FileExists == "1" { //有附件
-			mustNot = append(mustNot, fmt.Sprintf(queryMissing, "isValidFile"))
-			musts = append(musts, fmt.Sprintf(queryBoolMustTerm, 1))
-		} else if bsp.FileExists == "-1" { //无附件
-			musts = append(musts, fmt.Sprintf(queryMissing, "isValidFile"))
-		}
-	}
-	qstr = fmt.Sprintf(query, strings.Join(musts, ","), strings.Join(mustNot, ","), strings.Join(bools, ","), boolsNum)
-	return
-}
-
-// DetailFileORTitle 包含正文或 附件 不包含标题
-func (s *SearchQuery) DetailFileORTitle(findFields string) bool {
-	return (strings.Contains(findFields, "detail") || strings.Contains(findFields, "filetext")) && !strings.Contains(findFields, "title")
-}
-
-// DetailANDTitle 包含正文包含标题
-func (s *SearchQuery) DetailANDTitle(findFields string) bool {
-	return strings.Contains(findFields, "detail") && strings.Contains(findFields, "title")
-}

+ 53 - 0
jyBXCore/rpc/service/search.go

@@ -0,0 +1,53 @@
+package service
+
+import (
+	MC "app.yhyue.com/moapp/jybase/common"
+	"github.com/zeromicro/go-zero/core/logx"
+	"jyBXCore/rpc/bxcore"
+	IC "jyBXCore/rpc/init"
+	"jyBXCore/rpc/model/es"
+	"jyBXCore/rpc/util"
+	"strings"
+	"time"
+)
+
+// GetBidSearchData  默认查询缓存数据 只查标题
+// 登录用户默认搜索500条数据,付费用户字段和免费用户字段不同,未登录用户查询5000条。
+// 标信息搜索 isCache:是否是获取缓存信息
+func GetBidSearchData(in *bxcore.SearchReq, isCache bool) (count int64, list []*bxcore.SearchList) {
+	var start = int((in.PageNum - 1) * in.PageSize)
+	if start >= 0 {
+		t := time.Now()
+		fields := MC.If(in.IsPay, es.BidSearchFieldOfVip, es.BidSearchFieldBase).(string)
+		//in.BidField(医疗)领域化字段
+		if in.BidField != "" {
+			fields = es.BidSearchDomainField
+		}
+		//IC.C.FileSignBool列表是否显示附件开关
+		if IC.C.FileSignBool {
+			fields = fields + es.BidSearchFieldFile
+		}
+		biddingSearch := es.SearchByES{
+			Index:      es.INDEX,
+			IType:      es.TYPE,
+			Query:      es.GetSearchQuery(in, es.GetBidSearchQuery(in)),
+			FindFields: MC.If(isCache, "title", "detail").(string),
+			Order:      es.BidSearchSort,
+			Fields:     fields,
+			Start:      MC.If(isCache, 0, start).(int),
+			Limit:      MC.If(isCache, MC.If(in.IsPay, IC.C.DefaultBidInfo.PayCount, IC.C.DefaultBidInfo.Count).(int), int(in.PageSize)).(int),
+			Count:      MC.If(strings.Contains(in.SelectType, "detail"), 115, 0).(int),       //高亮正文数量
+			HighLight:  MC.If(strings.Contains(in.SelectType, "detail"), true, false).(bool), //是否高亮正文
+		}
+		var repl *[]map[string]interface{}
+		count, repl = biddingSearch.GetAllByNgramWithCount()
+		if repl != nil && *repl != nil && len(*repl) > 0 {
+			//格式化查询结果
+			list = util.SearchListFormat(in.Industry, repl, strings.Contains(in.SelectType, "detail"))
+		} else {
+			logx.Info("查询数据异常")
+		}
+		logx.Info(in.KeyWords, "关键词 -1- 查询耗时:", time.Since(t).Seconds())
+	}
+	return
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 528 - 266
jyBXCore/rpc/type/bxcore/bxcore.pb.go


+ 178 - 523
jyBXCore/rpc/util/search.go

@@ -3,7 +3,6 @@ package util
 import (
 	MC "app.yhyue.com/moapp/jybase/common"
 	ME "app.yhyue.com/moapp/jybase/encrypt"
-	elastic "app.yhyue.com/moapp/jybase/esv1"
 	"crypto/rand"
 	"encoding/json"
 	"fmt"
@@ -11,7 +10,6 @@ import (
 	"io/ioutil"
 	IC "jyBXCore/rpc/init"
 	"jyBXCore/rpc/internal/config"
-	"jyBXCore/rpc/model/es"
 	"jyBXCore/rpc/type/bxcore"
 	"math/big"
 	"net/http"
@@ -23,78 +21,95 @@ import (
 	"unicode"
 )
 
-var ClearHtml = regexp.MustCompile("<[^>]*>")
-var MatchSpace = regexp.MustCompile("\\s+")
-var filterReg_3 = regexp.MustCompile("(项目|公告|公示)$")
-var filterReg_2 = regexp.MustCompile("^[)\\)>》】\\]}}〕,,;;::'\"“”。.\\??、/+=\\_—*&……\\^%$¥@!!`~·(\\(<《【\\[{{〔]+$")
-var filterReg_1 = regexp.MustCompile("^([0-9]{1,3}|[零一二三四五六七八九十]{1,2}|联系人?|电话|地址|编号|采购|政府采购|成交|更正|招标|中标|变更|结果)$")
-var filterReg = regexp.MustCompile("^[的人号时元万公告项目地址电话邮编日期联系招标中结果成交项目项目采购采购项目政府采购公告更正公告]+$")
-var PhoneReg = regexp.MustCompile("^[1][3-9][0-9]{9}$")
-var EmailPattern = regexp.MustCompile("^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$")
+var (
+	ClearHtml  = regexp.MustCompile("<[^>]*>")
+	MatchSpace = regexp.MustCompile("\\s+")
+	filterReg3 = regexp.MustCompile("(项目|公告|公示)$")
+	filterReg2 = regexp.MustCompile("^[)\\)>》】\\]}}〕,,;;::'\"“”。.\\??、/+=\\_—*&……\\^%$¥@!!`~·(\\(<《【\\[{{〔]+$")
+	filterReg1 = regexp.MustCompile("^([0-9]{1,3}|[零一二三四五六七八九十]{1,2}|联系人?|电话|地址|编号|采购|政府采购|成交|更正|招标|中标|变更|结果)$")
+	filterReg  = regexp.MustCompile("^[的人号时元万公告项目地址电话邮编日期联系招标中结果成交项目项目采购采购项目政府采购公告更正公告]+$")
+	//PhoneReg     = regexp.MustCompile("^[1][3-9][0-9]{9}$")
+	//EmailPattern = regexp.MustCompile("^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$")
+)
 
-func SearchHistory(history, searchvalue string) (arrs []string) {
-	if searchvalue != "" {
-		arrs = strings.Split(history, ",")
+// SearchHistory 格式化 关键词搜索历史记录
+func SearchHistory(history, searchValue, additionalWords string) (arrS []string) {
+	//主关键词
+	var searchKeys = strings.Split(searchValue, IC.C.JYKeyMark)
+	//附加词
+	if additionalWords != "" {
+		for _, aws := range strings.Split(additionalWords, ",") {
+			for _, as := range strings.Split(aws, IC.C.JYKeyMark) {
+				searchKeys = append(searchKeys, as)
+			}
+		}
+	}
+	//关键词 和 附加词 合并,作为新的关键词历史搜索记录
+	if len(searchKeys) > 0 {
+		arrS = strings.Split(history, ",")
 		//新增历史记录
 		if history == "" {
-			arrs = make([]string, 0)
+			arrS = make([]string, 0)
 		}
-		for k, v := range arrs {
-			if v == strings.TrimSpace(searchvalue) {
-				arrs = append(arrs[:k], arrs[k+1:]...)
-				break
+		for _, sv := range searchKeys {
+			for k, v := range arrS {
+				if v == strings.TrimSpace(sv) {
+					arrS = append(arrS[:k], arrS[k+1:]...)
+					break
+				}
 			}
 		}
-		arrs = append(arrs, searchvalue)
-		if len(arrs) > 10 {
-			arrs = arrs[1:11]
+		arrS = append(arrS, searchKeys...)
+		if len(arrS) > 10 {
+			arrS = arrS[len(arrS)-10:]
 		}
 	}
-	return arrs
+	return arrS
 }
 
-func FilteKey(k string) string {
+func FilterKey(k string) string {
 	k = strings.TrimSpace(k)
-	k = filterReg_3.ReplaceAllString(k, "")
-	k = filterReg_2.ReplaceAllString(k, "")
-	k = filterReg_1.ReplaceAllString(k, "")
+	k = filterReg3.ReplaceAllString(k, "")
+	k = filterReg2.ReplaceAllString(k, "")
+	k = filterReg1.ReplaceAllString(k, "")
 	k = filterReg.ReplaceAllString(k, "")
 	return k
 }
 
-//超过keywordsLimit个字,截断
+// InterceptSearchKW 超过keywordsLimit个字,截断
 //返回截取后的字符串和截取掉中的前3个字
-func InterceptSearchKW(word string, keywordsLimit int, isFilter bool) (b_word, a_word, s_word string) {
+// b_word:截取后的关键词;a_word:截取后 后面三个字;s_word:已截取 处理过的关键词
+func InterceptSearchKW(word string, keywordsLimit int, isFilter bool) (bWord, aWord, sWord string) {
 	if isFilter {
-		word = FilteKey(word)
+		word = FilterKey(word)
 	}
 	word = MatchSpace.ReplaceAllString(strings.TrimSpace(word), " ")
 	words := []rune(word)
 	if len(words) > keywordsLimit {
-		b_word = string(words[:keywordsLimit])
-		b_word = strings.TrimSpace(b_word)
+		bWord = string(words[:keywordsLimit])
+		bWord = strings.TrimSpace(bWord)
 		if len(words) > keywordsLimit+3 {
-			a_word = string(words[keywordsLimit : keywordsLimit+3])
+			aWord = string(words[keywordsLimit : keywordsLimit+3])
 		} else {
-			a_word = string(words[keywordsLimit:])
+			aWord = string(words[keywordsLimit:])
 		}
 	} else {
-		b_word = word
+		bWord = word
 	}
-	a_word = strings.TrimSpace(a_word)
-	s_word = MatchSpace.ReplaceAllString(b_word, "+")
+	aWord = strings.TrimSpace(aWord)
+	sWord = MatchSpace.ReplaceAllString(bWord, IC.C.JYKeyMark)
 	return
 }
 
 func HttpEs(ques, analyzer, esAddress string) (res string) {
-	var addrs []string
-	surl := ""
+	var adders []string
+	curl := ""
 	for _, s := range strings.Split(esAddress, ",") {
-		addrs = append(addrs, s)
+		adders = append(adders, s)
 	}
-	i, _ := rand.Int(rand.Reader, big.NewInt(int64(len(addrs)))) //随机
-	surl = addrs[int(i.Int64())] + "/bidding/_analyze"
-	URL, _ := url.Parse(surl)
+	i, _ := rand.Int(rand.Reader, big.NewInt(int64(len(adders)))) //随机
+	curl = adders[int(i.Int64())] + "/bidding/_analyze"
+	URL, _ := url.Parse(curl)
 	Q := URL.Query()
 	Q.Add("text", ques)
 	Q.Add("analyzer", analyzer)
@@ -102,25 +117,25 @@ func HttpEs(ques, analyzer, esAddress string) (res string) {
 	resp, err := http.Get(URL.String())
 	if err != nil {
 		logx.Info("es连接失败 err1:", err)
-		resp, err = getesResp(ques, analyzer, addrs)
+		resp, err = getESResp(ques, analyzer, adders)
 		if err != nil {
 			return
 		}
 	}
-	result, err := ioutil.ReadAll(resp.Body)
-	if err == nil {
+	result, err1 := ioutil.ReadAll(resp.Body)
+	if err1 == nil {
 		defer resp.Body.Close()
-		var resmap map[string]interface{}
-		json.Unmarshal(result, &resmap)
-		if resmap != nil && resmap["tokens"] != nil {
-			tokens := MC.ObjArrToMapArr(resmap["tokens"].([]interface{}))
+		var resMap map[string]interface{}
+		json.Unmarshal(result, &resMap)
+		if resMap != nil && resMap["tokens"] != nil {
+			tokens := MC.ObjArrToMapArr(resMap["tokens"].([]interface{}))
 			for _, v := range tokens {
 				token := MC.ObjToString(v["token"])
-				if len([]rune(token)) == 1 && unicode.IsLetter([]rune(token)[0]) {
+				if len([]rune(token)) == 1 && !unicode.Is(unicode.Scripts["Han"], []rune(token)[0]) { //(P260保留单个汉字)
 					continue
 				}
-				if res != "" {
-					res += "+"
+				if res != "" && token != "" {
+					res += IC.C.JYKeyMark
 				}
 				res += token
 			}
@@ -130,10 +145,10 @@ func HttpEs(ques, analyzer, esAddress string) (res string) {
 }
 
 //
-func getesResp(ques, analyzer string, addrs []string) (resp *http.Response, err error) {
-	for _, v := range addrs {
-		surl := v + "/bidding/_analyze"
-		URL, _ := url.Parse(surl)
+func getESResp(ques, analyzer string, adds []string) (resp *http.Response, err error) {
+	for _, v := range adds {
+		curl := v + "/bidding/_analyze"
+		URL, _ := url.Parse(curl)
 		Q := URL.Query()
 		Q.Add("text", ques)
 		Q.Add("analyzer", analyzer)
@@ -146,417 +161,25 @@ func getesResp(ques, analyzer string, addrs []string) (resp *http.Response, err
 	return resp, err
 }
 
-//pc、微信、app 招标信息搜索
-
 const (
-	INDEX          = "bidding"
-	TYPE           = "bidding"
-	bidSearch_sort = `{"dataweight":-1,"publishtime":-1}`
 	RedisName      = "other"
-	//招标搜索分页--每页显示数量
-	SearchPageSize = 50
+	RedisNameNew   = "newother"
+	SearchPageSize = 50 //招标搜索分页--每页显示数量
 	//招标搜索分页--最大页数
 	SearchMaxPageNum       = 10  //免费用户500条记录
 	SearchMaxPageNum_PAYED = 100 //付费用户5000条记录
 
-	bidSearch_field_1    = `"_id","title","publishtime","dataweight","toptype","subtype","type","area","city","s_subscopeclass","bidamount","budget","buyerclass","spidercode","site"` //,"filetext"
-	bidSearch_field      = bidSearch_field_1 + `,"bidopentime","winner","buyer","projectname","projectcode","projectinfo"`
-	bidSearch_field_file = `,"filetext","isValidFile"`
-	query_bool_should    = `{"bool":{"should":[%s],"minimum_should_match": 1}}`
 )
 
-//GetBidSearchData 标信息搜索
-func GetBidSearchData(in *bxcore.SearchReq) (count int64, list []*bxcore.SearchList) {
-	t := time.Now()
-	var hightlightContent bool = false //是否高亮正文
-	var selectTypeArr = strings.Split(in.SelectType, ",")
-	for _, v := range selectTypeArr {
-		if v == "detail" {
-			hightlightContent = true
-			break
-		}
-	}
-	qstr := GetSearchQuery(in, GetBidSearchQuery(in))
-	var start = int((in.PageNum - 1) * in.PageSize)
-	if start >= 0 {
-		field := bidSearch_field_1
-		if start == 0 {
-			field = bidSearch_field
-		}
-		if IC.C.FileSignBool {
-			field = field + bidSearch_field_file
-		}
-		biddingSearch := es.EsSearch{
-			Index:      INDEX,
-			Itype:      TYPE,
-			Query:      qstr,
-			FindFields: "detail",
-			Order:      bidSearch_sort,
-			Fields:     field,
-			Start:      start,
-			Limit:      int(in.PageSize),
-			Count:      0,
-			HighLight:  false,
-		}
-		var repl *[]map[string]interface{}
-		if hightlightContent {
-			biddingSearch.Count = 115
-			biddingSearch.HighLight = hightlightContent
-		}
-		//repl = elastic.GetAllByNgram(INDEX, TYPE, qstr, ``, bidSearch_sort, field, start, int(in.PageSize), 0, false)
-		count, repl = biddingSearch.GetAllByNgramWithCount()
-		if repl != nil && *repl != nil && len(*repl) > 0 {
-			BidListConvert(in.Industry, repl)
-			list = searchListFormart(repl, true)
-		}
-		logx.Info("关键词 -1- 查询耗时:", time.Since(t).Seconds())
-		MakeCollection(in.UserId, list)
-	}
-	logx.Info("关键词 查询耗时:", time.Since(t).Seconds())
-	return
-}
-
-//
-var topTypeMap = map[string]string{
-	"招标预告":   "预告",
-	"招标公告":   "招标",
-	"招标结果":   "结果",
-	"招标信用信息": "其它",
-	"拟建项目":   "拟建",
-	"采购意向":   "采购意向",
-}
-
-//
-func GetBidSearchQuery(in *bxcore.SearchReq) string {
-	query := ``
-	//省份
-	area := in.Province
-	if area != "" {
-		query += `{"terms":{"area":[`
-		for k, v := range strings.Split(area, ",") {
-			if k > 0 {
-				query += `,`
-			}
-			query += `"` + v + `"`
-		}
-		query += `]}}`
-	}
-	//
-	city := in.City
-	if city != "" {
-		if len(query) > 0 {
-			query += ","
-		}
-		query += `{"terms":{"city":[`
-		for k, v := range strings.Split(city, ",") {
-			if k > 0 {
-				query += `,`
-			}
-			query += `"` + v + `"`
-		}
-		query += `]}}`
-	}
-	if query != "" {
-		query = fmt.Sprintf(query_bool_should, query)
-	}
-	//发布时间
-	publishtime := in.PublishTime
-	if publishtime != "" && len(strings.Split(publishtime, "-")) > 1 {
-		if len(query) > 0 {
-			query += ","
-		}
-		starttime := strings.Split(publishtime, "-")[0]
-		endtime := strings.Split(publishtime, "-")[1]
-		query += `{"range":{"publishtime":{`
-		if starttime != "" {
-			query += `"gte":` + starttime
-		}
-		if starttime != "" && endtime != "" {
-			query += `,`
-		}
-		if endtime != "" {
-			query += `"lt":` + endtime
-		}
-		query += `}}}`
-	}
-	//信息类型-二级
-	subtype := in.Subtype
-	toptype := MC.If(in.Toptype != "", strings.Split(in.Toptype, ","), []string{}).([]string)
-	alltype := ``
-	//二级分类
-	if subtype != "" {
-		var typeInt = 0
-		alltype += `{"terms":{"subtype":[`
-		for k, v := range strings.Split(subtype, ",") {
-			if ttype := MC.If(topTypeMap[v] != "" && in.Toptype == "", topTypeMap[v], "").(string); ttype != "" {
-				toptype = append(toptype, ttype)
-				typeInt += 1
-				continue
-			}
-			if k > typeInt {
-				alltype += `,`
-			}
-			alltype += `"` + v + `"`
-		}
-		alltype += `]}}`
-	}
-	//信息类型  一级分类
-	logx.Info("toptype:", toptype)
-	if len(toptype) > 0 {
-		if alltype != "" {
-			alltype += ","
-		}
-		alltype += `{"terms":{"toptype":[`
-		for k, v := range toptype {
-			if k > 0 {
-				alltype += `,`
-			}
-			alltype += `"` + v + `"`
-		}
-		alltype += `]}}`
-	}
-
-	if alltype != "" {
-		if query != "" {
-			query += ","
-		}
-		query += fmt.Sprintf(query_bool_should, alltype)
-	}
-	//采购单位类型
-	buyerclass := in.BuyerClass
-	if buyerclass != "" {
-		if len(query) > 0 {
-			query += ","
-		}
-		query += `{"terms":{"buyerclass":[`
-		for k, v := range strings.Split(buyerclass, ",") {
-			if k > 0 {
-				query += `,`
-			}
-			query += `"` + v + `"`
-		}
-		query += `]}}`
-	}
-	return query
-}
-
-//包含正文或 附件 不包含标题
-func DetailFileORTitle(findfields string) bool {
-	return (strings.Contains(findfields, `"detail"`) || strings.Contains(findfields, `"filetext"`)) && !strings.Contains(findfields, `"title"`)
-}
-func GetSearchQuery(in *bxcore.SearchReq, mustquery string) (qstr string) {
-	multi_match := `{"multi_match": {"query": "%s","type": "phrase", "fields": [%s]}}`
-	query := `{"query":{"bool":{"must":[%s],"must_not":[%s]}}}`
-	//query := `{"query": {"function_score": {"query": {"bool": {"must": [%s],"must_not": [%s]}},"field_value_factor": {"field": "dataweight","modifier": "ln1p","missing": 0}}}}`
-
-	query_bool_should := `{"bool":{"should":[%s],"minimum_should_match": 1}}`
-	query_bools_must := `{"bool":{"must":[{"range":{"bidamount":{%s}}}]}},{"bool":{"must":[{"range":{"budget":{%s}}}],"must_not":[{"range":{"bidamount":{"gte":-1}}}]}}`
-	query_bool_must := `{"bool":{"must":[{"terms":{"s_subscopeclass":[%s]}}]}}`
-	query_bool_must_term := `{"bool": {"must": [{ "term": {"isValidFile": %d }}]}}`
-	query_missing := `{"constant_score":{"filter":{"missing":{"field":"%s"}}}}`
-	gte := `"gte": %s`
-	lte := `"lte": %s`
-	musts, must_not := []string{}, []string{}
-	if mustquery != "" {
-		musts = append(musts, mustquery)
-	}
-	//搜索范围是否只有附件
-	//搜索范围只选择附件,是否有附件条件无效;
-	var isFileSearch bool = in.SelectType == "filetext"
-	selectTypeArr := strings.Split(in.SelectType, ",")
-	var findfields string
-	if selectTypeArr == nil || len(selectTypeArr) == 0 {
-		findfields = `"title"`
-	} else {
-		findfields = fmt.Sprintf(`"%s"`, strings.Join(selectTypeArr, "\",\""))
-	}
-	//此时关键词中间有+进行隔离
-	if in.KeyWords != "" {
-		shoulds := []string{}
-		var switchBool = strings.Contains(findfields, "detail") && strings.Contains(findfields, "title") && IC.C.SearchTypeSwitch
-		keyword_multi_match := fmt.Sprintf(multi_match, "%s", findfields)
-		for _, v := range strings.Split(in.KeyWords, "+") {
-			if elastic.ReplaceYH(v) == "" {
-				continue
-			}
-			if len([]rune(elastic.ReplaceYH(v))) == 1 {
-				//单个字  搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
-				if DetailFileORTitle(findfields) {
-					keyword_multi_match = fmt.Sprintf(multi_match, "%s", findfields+`,"title"`)
-				}
-			} else {
-				//标题 全文搜索 搜索类型开关打开 默认搜索全文;(全文包含标题)(单字排除)
-				if switchBool && len([]rune(elastic.ReplaceYH(v))) > 1 {
-					if strings.Contains(findfields, `"title",`) {
-						findfields = strings.Replace(findfields, `"title",`, ``, -1)
-					} else if strings.Contains(findfields, `,"title"`) {
-						findfields = strings.Replace(findfields, `,"title"`, ``, -1)
-					}
-					keyword_multi_match = fmt.Sprintf(multi_match, "%s", findfields)
-				}
-			}
-			shoulds = append(shoulds, fmt.Sprintf(keyword_multi_match, elastic.ReplaceYH(v)))
-		}
-		musts = append(musts, fmt.Sprintf(elastic.NgramMust, strings.Join(shoulds, ",")))
-	}
-	if in.Industry != "" {
-		industrys := strings.Split(in.Industry, ",")
-		musts = append(musts, fmt.Sprintf(query_bool_must, `"`+strings.Join(industrys, `","`)+`"`))
-	}
-	//价格
-	if in.Price != "" && len(strings.Split(in.Price, "-")) > 1 {
-		minprice, maxprice := strings.Split(in.Price, "-")[0], strings.Split(in.Price, "-")[1]
-		if minprice != "" || maxprice != "" {
-			sq := ``
-			if minprice != "" {
-				min, _ := strconv.ParseFloat(minprice, 64)
-				minprice = fmt.Sprintf("%.0f", min*10000)
-				if minprice == "0" {
-					minprice = ""
-				}
-			}
-			if maxprice != "" {
-				max, _ := strconv.ParseFloat(maxprice, 64)
-				maxprice = fmt.Sprintf("%.0f", max*10000)
-				if maxprice == "0" {
-					maxprice = ""
-				}
-			}
-			if minprice != "" {
-				sq += fmt.Sprintf(gte, minprice)
-			}
-			if minprice != "" && maxprice != "" {
-				sq += `,`
-			}
-			if maxprice != "" {
-				sq += fmt.Sprintf(lte, maxprice)
-			}
-			if minprice != "" || maxprice != "" {
-				query_price := fmt.Sprintf(query_bool_should, fmt.Sprintf(query_bools_must, sq, sq))
-				musts = append(musts, query_price)
-			}
-		}
-	}
-	hasBuyerTel := in.BuyerTel
-	if hasBuyerTel != "" {
-		if hasBuyerTel == "y" {
-			must_not = append(must_not, fmt.Sprintf(query_missing, "buyertel"))
-		} else {
-			musts = append(musts, fmt.Sprintf(query_missing, "buyertel"))
-		}
-	}
-	hasWinnerTel := in.WinnerTel
-	if hasWinnerTel != "" {
-		if hasWinnerTel == "y" {
-			must_not = append(must_not, fmt.Sprintf(query_missing, "winnertel"))
-		} else {
-			musts = append(musts, fmt.Sprintf(query_missing, "winnertel"))
-		}
-	}
-	//排除词
-	notkey := in.ExclusionWords
-	if notkey = strings.TrimSpace(notkey); notkey != "" {
-		notkey_multi_match := fmt.Sprintf(multi_match, "%s", findfields)
-		notkey_must_not := []string{}
-		for _, v := range strings.Split(notkey, " ") {
-			v = strings.TrimSpace(v)
-			if v == "" {
-				continue
-			}
-			if len([]rune(elastic.ReplaceYH(v))) == 1 {
-				//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
-				if DetailFileORTitle(findfields) {
-					notkey_multi_match = fmt.Sprintf(multi_match, "%s", findfields+`,"title"`)
-				}
-			}
-			notkey_must_not = append(notkey_must_not, fmt.Sprintf(notkey_multi_match, elastic.ReplaceYH(v)))
-		}
-		must_not = append(must_not, fmt.Sprintf(query_bool_should, strings.Join(notkey_must_not, ",")))
-	}
-	//
-	fileExists := in.FileExists
-	if !isFileSearch && fileExists != "" {
-		if fileExists == "1" { //有附件
-			must_not = append(must_not, fmt.Sprintf(query_missing, "isValidFile"))
-			musts = append(musts, fmt.Sprintf(query_bool_must_term, 1))
-		} else if fileExists == "-1" { //无附件
-			musts = append(musts, fmt.Sprintf(query_missing, "isValidFile"))
-		}
-	}
-	qstr = fmt.Sprintf(query, strings.Join(musts, ","), strings.Join(must_not, ","))
-	logx.Info(qstr)
-	return
-}
-
-/*
- * 结果列表转换,目前只换行行业字段
- * 所有的招标搜索都要调用此方法,列表中有展示行业的也可以用
- * industry 搜索条件中的行业,默认为空
- */
-func BidListConvert(industry string, res *[]map[string]interface{}) {
-	if res == nil {
-		return
-	}
-	commonSubstring := func(v string) (value string) {
-		bcs := strings.Split(v, "_")
-		if len(bcs) == 1 {
-			value = bcs[0]
-		} else if len(bcs) == 2 {
-			value = bcs[0]
-			if strings.TrimSpace(value) == "" {
-				value = bcs[0]
-			}
-		}
-		return
-	}
-	for _, v := range *res {
-		v["id"] = v["_id"]
-		delete(v, "_id")
-		budget, _ := v["budget"].(float64)
-		bidamount, _ := v["bidamount"].(float64)
-		if budget == 0 || strings.TrimSpace(fmt.Sprint(v["budget"])) == "" {
-			delete(v, "budget")
-		}
-		if bidamount == 0 || strings.TrimSpace(fmt.Sprint(v["bidamount"])) == "" {
-			delete(v, "bidamount")
-		}
-		value := ""
-		subscopeclass, _ := v["s_subscopeclass"].(string)
-		subscopeclass = strings.Trim(subscopeclass, ",")
-		bct := strings.Split(subscopeclass, ",")
-		if bct == nil || len(bct) == 0 {
-			continue
-		}
-		//搜索条件中没有行业的话,取查询结果中第一个行业
-		if industry == "" {
-			value = commonSubstring(bct[0])
-		} else { //搜索条件中有行业的话,取行业中和搜索条件相对应的第一个
-			industrys := strings.Split(industry, ",")
-		L:
-			for _, bc := range bct {
-				for _, is := range industrys {
-					if bc == is {
-						value = commonSubstring(bc)
-						break L
-					}
-				}
-			}
-		}
-		if strings.TrimSpace(value) == "" {
-			continue
-		}
-		v["industry"] = value
-	}
-}
-
-//是否收藏
+// MakeCollection 是否收藏
 func MakeCollection(userId string, list []*bxcore.SearchList) {
 	if list == nil || len(list) == 0 {
 		return
 	}
 	param := []interface{}{userId}
-	wh := []string{}
+	var wh []string
 	for _, v := range list {
+		logx.Info(v.Title, "---v.id---:", v.Id)
 		array := ME.DecodeArticleId2ByCheck(v.Id)
 		if len(array) == 1 && array[0] != "" {
 			param = append(param, array[0])
@@ -565,43 +188,61 @@ func MakeCollection(userId string, list []*bxcore.SearchList) {
 	}
 	if len(wh) > 0 {
 		result := IC.MainMysql.SelectBySql(`select bid from bdcollection where userid=? and bid in (`+strings.Join(wh, ",")+`)`, param...)
-		bid_map := map[string]bool{}
+		bidMap := map[string]bool{}
 		if result != nil {
 			for _, v := range *result {
-				bid_map[ME.EncodeArticleId2ByCheck(MC.ObjToString(v["bid"]))] = true
+				bidMap[ME.EncodeArticleId2ByCheck(MC.ObjToString(v["bid"]))] = true
 			}
 		}
 		for _, v := range list {
-			if bid_map[v.Id] {
+			if bidMap[v.Id] {
 				v.IsCollected = true
 			}
 		}
 	}
 }
 
-//默认查询缓存数据
-func SearchCahcheData(in *bxcore.SearchReq) (count int64, list []*bxcore.SearchList) {
-	//最新招标信息
-	findfields := `"title"`
-	qstr := GetSearchQuery(in, GetBidSearchQuery(in))
-	//首页
-	if in.PageNum == 1 {
-		count = elastic.Count(INDEX, TYPE, qstr)
+// IndustryFormat 行业处理
+func IndustryFormat(industry, subScopeClass string) (newIndustry string) {
+	commonSubstring := func(v string) (value string) {
+		bcs := strings.Split(v, "_")
+		if len(bcs) == 1 {
+			value = bcs[0]
+		} else if len(bcs) == 2 {
+			value = bcs[0]
+			if strings.TrimSpace(value) == "" {
+				value = bcs[0]
+			}
+		}
+		return
+	}
+	bct := strings.Split(subScopeClass, ",")
+	if bct == nil || len(bct) == 0 {
+		return
 	}
-	if count > 0 || in.PageNum > 1 {
-		repl := elastic.GetAllByNgram(INDEX, TYPE, qstr, findfields, bidSearch_sort, bidSearch_field, int(in.PageNum), int(in.PageSize), 0, false)
-		if repl != nil && *repl != nil && len(*repl) > 0 {
-			BidListConvert(in.Industry, repl)
-			list = searchListFormart(repl, false)
+	//搜索条件中没有行业的话,取查询结果中第一个行业
+	if industry == "" {
+		newIndustry = commonSubstring(bct[0])
+	} else { //搜索条件中有行业的话,取行业中和搜索条件相对应的第一个
+		industryArr := strings.Split(industry, ",")
+	L:
+		for _, bc := range bct {
+			for _, is := range industryArr {
+				if bc == is {
+					newIndustry = strings.TrimSpace(commonSubstring(bc))
+					break L
+				}
+			}
 		}
 	}
 	return
 }
 
-//格式化数据
-func searchListFormart(repl *[]map[string]interface{}, b bool) (list []*bxcore.SearchList) {
+// SearchListFormat  格式化数据
+func SearchListFormat(industry string, repl *[]map[string]interface{}, b bool) (list []*bxcore.SearchList) {
 	for _, v := range *repl {
 		var searchList = &bxcore.SearchList{}
+		//正文
 		if b {
 			//正文匹配检索关键词
 			highlight, _ := v["highlight"].(map[string][]string)
@@ -611,65 +252,75 @@ func searchListFormart(repl *[]map[string]interface{}, b bool) (list []*bxcore.S
 			}
 			searchList.Detail = detail
 		}
-		searchList.Area = MC.ObjToString(v["area"])
-		searchList.AreaUrl = IC.LabelMap[searchList.Area].Url
-		searchList.BuyerClass = MC.ObjToString(v["buyerclass"])
-		searchList.City = MC.ObjToString(v["city"])
-		searchList.FileExists, _ = v["isValidFile"].(bool) //附件
-		searchList.Id = ME.EncodeArticleId2ByCheck(MC.ObjToString(v["id"]))
-		searchList.Industry = MC.ObjToString(v["industry"])
-		searchList.IndustryUrl = IC.LabelMap[searchList.Industry].Url
-		searchList.PublishTime = MC.Int64All(v["publishtime"])
-		searchList.Subtype = MC.ObjToString(v["subtype"])
-		searchList.SubtypeUrl = IC.LabelMap[searchList.Subtype].Url
-		searchList.Title = MC.ObjToString(v["title"])
-		searchList.Budget = MC.Int64All(v["budget"])
-		searchList.Bidamount = MC.Int64All(v["bidamount"])
-		searchList.ProjectName = MC.ObjToString(v["projectname"])
-		searchList.ProjectCode = MC.ObjToString(v["projectcode"])
-		searchList.ProjectInfo = &bxcore.PInfo{}
+		searchList.Id = ME.EncodeArticleId2ByCheck(MC.ObjToString(v["_id"]))                                    //ME.EncodeArticleId2ByCheck(MC.ObjToString(v["_id"]))                                         //加密信息id
+		searchList.Area = MC.ObjToString(v["area"])                                                             //地区
+		searchList.AreaUrl = IC.LabelMap[searchList.Area].Url                                                   //地区分类链接
+		searchList.BuyerClass = MC.ObjToString(v["buyerclass"])                                                 //采购单位类型
+		searchList.City = MC.ObjToString(v["city"])                                                             //城市
+		searchList.Industry = IndustryFormat(industry, strings.Trim(MC.ObjToString(v["s_subscopeclass"]), ",")) //行业
+		searchList.IndustryUrl = IC.LabelMap[searchList.Industry].Url                                           //行业分类地址
+		searchList.PublishTime = MC.Int64All(v["publishtime"])                                                  //发布时间
+		searchList.FileExists, _ = v["isValidFile"].(bool)                                                      //是否有附件
+		searchList.Subtype = MC.ObjToString(v["subtype"])                                                       //信息类型
+		searchList.SubtypeUrl = IC.LabelMap[searchList.Subtype].Url                                             //信息类型分类链接
+		searchList.Title = MC.ObjToString(v["title"])                                                           //标题
+		searchList.ProjectName = MC.ObjToString(v["projectname"])                                               //项目名称
+		searchList.ProjectCode = MC.ObjToString(v["projectcode"])                                               //项目代码
+		if budget, ok := v["budget"].(float64); ok && budget > 0 {                                              //预算
+			searchList.Budget = int64(budget)
+		}
+		if bidAmount, ok := v["bidamount"].(float64); ok && bidAmount > 0 { //中标金额
+			searchList.BidAmount = int64(bidAmount)
+		}
+		searchList.Buyer = MC.ObjToString(v["buyer"])               //采购单位
+		searchList.BuyerTel = MC.ObjToString(v["buyertel"])         //采购单位联系方式
+		searchList.BuyerPerson = MC.ObjToString(v["buyerperson"])   //采购单位联系人
+		searchList.Agency = MC.ObjToString(v["agency"])             //代理机构
+		searchList.AgencyTel = MC.ObjToString(v["agencytel"])       //代理机构联系电话
+		searchList.AgencyPerson = MC.ObjToString(v["agencyperson"]) //代理机构联系人
+		searchList.BidOpenTime = MC.Int64All(v["bidopentime"])      //开标时间
+		searchList.BidEndTime = MC.Int64All(v["bidendtime"])        //发布时间
+		searchList.SignEndTime = MC.Int64All(v["signendtime"])      //投标截止日期
+		searchList.Site = MC.ObjToString(v["site"])                 //网站来源名称
+		searchList.SpiderCode = MC.ObjToString(v["spidercode"])     //网站来源代码
+		winnerList := MC.ObjToString(v["s_winner"])                 //中标企业名称集合
+		if winnerList != "" && len(strings.Split(winnerList, ",")) > 0 {
+			for wk, wv := range strings.Split(winnerList, ",") {
+				var (
+					winnerId = ""
+				)
+				if v["entidlist"] != nil {
+					if entIdList := MC.ObjArrToStringArr(v["entidlist"].([]interface{})); len(entIdList) > wk { //中标企业id集合
+						winnerId = entIdList[wk]
+					}
+				}
+				searchList.WinnerInfo = append(searchList.WinnerInfo, &bxcore.WinnerInfo{
+					Winner:       wv,                                                                                                     //中标企业 需要单独处理
+					WinnerTel:    MC.ObjToString(v["winnertel"]),                                                                         //中标企业联系电话
+					WinnerPerson: MC.ObjToString(v["winnerperson"]),                                                                      //中标企业联系人
+					WinnerId:     MC.If(winnerId != "" && len([]rune(winnerId)) > 12, ME.EncodeArticleId2ByCheck(winnerId), "").(string), //中标企业加密id  存在winnerId 异常的情况
+				})
+			}
+		}
+		searchList.ProjectInfo = &bxcore.PInfo{} //拟建项目信息
 		if v["projectinfo"] != nil {
-			pinfo := MC.ObjToMap(v["projectinfo"])
-			searchList.ProjectInfo.ApproveCode = MC.ObjToString((*pinfo)["approvecode"])
-			searchList.ProjectInfo.ApproveContent = MC.ObjToString((*pinfo)["approvecontent"])
-			searchList.ProjectInfo.ApproveDept = MC.ObjToString((*pinfo)["approvedept"])
-			searchList.ProjectInfo.ApproveStatus = MC.ObjToString((*pinfo)["approvestatus"])
-			searchList.ProjectInfo.ProjectType = MC.ObjToString((*pinfo)["projecttype"])
-			searchList.ProjectInfo.ApproveNumber = MC.ObjToString((*pinfo)["approvenumber"])
-			searchList.ProjectInfo.ApproveTime = MC.ObjToString((*pinfo)["approvetime"])
+			pInfo := MC.ObjToMap(v["projectinfo"])
+			searchList.ProjectInfo.ApproveCode = MC.ObjToString((*pInfo)["approvecode"])
+			searchList.ProjectInfo.ApproveContent = MC.ObjToString((*pInfo)["approvecontent"])
+			searchList.ProjectInfo.ApproveDept = MC.ObjToString((*pInfo)["approvedept"])
+			searchList.ProjectInfo.ApproveStatus = MC.ObjToString((*pInfo)["approvestatus"])
+			searchList.ProjectInfo.ProjectType = MC.ObjToString((*pInfo)["projecttype"])
+			searchList.ProjectInfo.ApproveNumber = MC.ObjToString((*pInfo)["approvenumber"])
+			searchList.ProjectInfo.ApproveTime = MC.ObjToString((*pInfo)["approvetime"])
 		}
-		searchList.Winner = MC.ObjToString(v["winner"])
-		searchList.Buyer = MC.ObjToString(v["buyer"])
-		searchList.BidopenTime = MC.Int64All(v["bidopentime"])
-		searchList.Site = MC.ObjToString(v["site"])
-		searchList.SpiderCode = MC.ObjToString(v["spidercode"])
 		list = append(list, searchList)
 	}
 	return
 }
 
-//合并map数据,去重,排序
-func DelRepeatSearchData(resOne, resTwo []*bxcore.SearchList) []*bxcore.SearchList {
-	if len(resOne) > 0 && len(resTwo) > 0 {
-		for _, v := range resOne {
-			for n, m := range resTwo {
-				if v.Id == m.Id {
-					resTwo = append(resTwo[0:n], resTwo[n+1:]...)
-					break
-				}
-			}
-		}
-		resOne = append(resOne, resTwo...)
-	} else {
-		resOne = append(resOne, resTwo...)
-	}
-	//sort.Slice(resOne, func(i, j int) bool {
-	//	return resOne[i].PublishTime > resOne[j].PublishTime
-	//})
-	return resOne
-}
-
-//付费用户搜索优化
+// IsOptimize 付费用户搜索优化
+// 需求来源:付费用户 默认查询 五年内数据,数据查询耗时,
+// 付费用户 且开关打开,针对前两页数据,满足关键词(< 7个字),查询时间范围一年以上,缩短查询时间
 func IsOptimize(cc config.Config, in *bxcore.SearchReq) bool {
 	if cc.PaySearchLimit.Switch && in.UserType != "fType" {
 		//首页----字数(<7)
@@ -683,6 +334,8 @@ func IsOptimize(cc config.Config, in *bxcore.SearchReq) bool {
 	}
 	return false
 }
+
+// GetPublishTime 查询时间调整
 func GetPublishTime(y, m int, publishTime string) string {
 	//发布时间
 	timeArray := strings.Split(publishTime, "-")
@@ -693,7 +346,9 @@ func GetPublishTime(y, m int, publishTime string) string {
 			if endTime == 0 {
 				endTime = time.Now().Unix()
 			}
+			//重新计算数据查询 开始时间
 			pTime := time.Unix(endTime, 0).AddDate(y, m, 0).Unix()
+			//从新定义搜索时间跨度
 			if endTime-startTime > pTime {
 				return fmt.Sprintf("%d-%d", pTime, endTime)
 			}

+ 29 - 19
jyBXCore/rpc/util/userInfo.go

@@ -4,6 +4,7 @@ import (
 	MC "app.yhyue.com/moapp/jybase/common"
 	"app.yhyue.com/moapp/jybase/mongodb"
 	"app.yhyue.com/moapp/jybase/mysql"
+	IC "jyBXCore/rpc/init"
 	"strings"
 )
 
@@ -12,10 +13,12 @@ type VipState struct {
 	VipState     int64 //超级订阅状态(1普通 2升级版)
 	BigMember    int64 //大会员状态
 	EntMember    int64 //商机管理用户状态
-	registerData int64 //注册时间
+	RegisterData int64 //注册时间
+	IsOldVip     bool  //老版超级订阅  超前项目
+	IsNewEnt     bool  //新版商机管理
 }
 
-func GetVipState(mysql *mysql.Mysql, mg mongodb.MongodbSim, userId string) (vs *VipState) {
+func GetVipState(mysql *mysql.Mysql, mg mongodb.MongodbSim, userId string, entId int64) (vs *VipState) {
 	vs = &VipState{}
 	if userId == "" {
 		return
@@ -23,31 +26,38 @@ func GetVipState(mysql *mysql.Mysql, mg mongodb.MongodbSim, userId string) (vs *
 	phone := ""
 	data, ok := mg.FindById("user", userId, `"i_member_status":1,"i_vip_status":1,"s_m_phone":1,"s_phone":1,"o_vipjy":1,"l_registedate":1`)
 	if data != nil && len(*data) > 0 && ok {
-		i_vip_status := MC.Int64All((*data)["i_vip_status"])
-		if i_vip_status > 1 {
+		iVipStatus := MC.Int64All((*data)["i_vip_status"])
+		if iVipStatus > 1 {
 			vs.VipState = 1
-			ovipjy, _ := (*data)["o_vipjy"].(map[string]interface{})
-			if ovipjy["o_buyset"] != nil {
-				o_buyset := ovipjy["o_buyset"].(map[string]interface{})
-				if o_buyset["upgrade"] != nil {
+			oVipJY, _ := (*data)["o_vipjy"].(map[string]interface{})
+			if oVipJY["o_buyset"] != nil {
+				oBuys := oVipJY["o_buyset"].(map[string]interface{})
+				if oBuys["upgrade"] != nil {
 					vs.VipState = 2
 				}
 			}
 		}
-		if i_member_status := MC.Int64All((*data)["i_member_status"]); i_member_status > 0 {
-			vs.BigMember = i_member_status
+		if iMemberStatus := MC.Int64All((*data)["i_member_status"]); iMemberStatus > 0 {
+			vs.BigMember = iMemberStatus
 		}
-		if s_phone, _ := (*data)["s_phone"].(string); s_phone != "" {
-			phone = s_phone
-		} else if s_m_phone, _ := (*data)["s_m_phone"].(string); s_m_phone != "" {
-			phone = s_m_phone
+		if sPhone, _ := (*data)["s_phone"].(string); sPhone != "" {
+			phone = sPhone
+		} else if sMPhone, _ := (*data)["s_m_phone"].(string); sMPhone != "" {
+			phone = sMPhone
 		}
-		if phone != "" {
-			if mysql.CountBySql(`select count(1) from entniche_user where phone = ? and power =1`, phone) > 0 {
-				vs.EntMember = 1
+		if phone != "" && entId > 0 {
+			entNicheInfos := mysql.SelectBySql(`SELECT i.status,i.isNew,r.role_id,u.power FROM (entniche_user u LEFT JOIN entniche_user_role r ON r.user_id = u.id)  LEFT JOIN entniche_info i ON u.ent_id=i.id WHERE u.phone = ? and i.id = ? `, phone, entId)
+			//商机管理用户信息判断
+			if entNicheInfos != nil && len(*entNicheInfos) > 0 {
+				entNicheInfo := (*entNicheInfos)[0]
+				if MC.IntAll(entNicheInfo["status"]) > 0 && (MC.IntAll(entNicheInfo["power"]) == 1 || MC.IntAll(entNicheInfo["role_id"]) > 0) {
+					vs.EntMember = 1
+				}
+				vs.IsNewEnt = MC.Int64All(entNicheInfo["isNew"]) > 0
 			}
 		}
-		vs.registerData, _ = ((*data)["l_registedate"]).(int64)
+		vs.RegisterData, _ = ((*data)["l_registedate"]).(int64)
+		vs.IsOldVip = vs.VipState > 0 && vs.RegisterData < IC.C.ContextOldVipLimit
 	}
 	return
 }
@@ -82,7 +92,7 @@ func (vs *VipState) GetQueryItems(selectType string, limitOldTime int64) (items
 		return
 	}
 	//老用户 使用付费功能
-	isOldUser := vs.registerData != 0 && vs.registerData < limitOldTime
+	isOldUser := vs.RegisterData != 0 && vs.RegisterData < limitOldTime
 	for _, t := range strings.Split(selectType, ",") {
 		if t == "winner" && isOldUser {
 			items = append(items, "mwinner")

+ 24 - 0
jyBXSubscribe/api/test/apitest.http

@@ -0,0 +1,24 @@
+// 接口测试
+### 订阅列表
+POST http://localhost:8002/jybx/subscribe/mType/list
+Content-Type: application/json
+UserId:63aea0bd901a4b3d4e661efb
+appId:10000
+newUserId:366045
+
+{
+  "pageNum": 1,
+  "pageSize": 50,
+  "format": "table",
+  "area": "",
+  "selectTime": "all",
+  "city": "",
+  "buyerClass": "",
+  "subtype": "",
+  "industry": "",
+  "keyWords": "",
+  "fileExists": "",
+  "price": "",
+  "exportNum": "",
+  "vt": "m"
+}

+ 19 - 2
jyBXSubscribe/rpc/bxsubscribe.proto

@@ -55,7 +55,7 @@ message subscribeInfo {
   int64 ca_isvisit = 10;
   int64  ca_type = 11;
   repeated string  matchKeys = 12;
-  double budget = 13;
+  double budget = 13;// 预算
   double bidAmount = 14;
   int64 collection = 15;
   string  buyer = 16;
@@ -65,7 +65,24 @@ message subscribeInfo {
   int64  ca_isvip = 20;
   bool   ca_fileExists = 21;
   int64  source = 22;//来源;1:个人订阅 2:企业自动分发 3:企业手动分发
-  string  site = 23;
+  string  site = 23; // 网站名称
+  string buyerTel = 24; // 采购单位联系方式
+  string buyerPerson = 25; // 采购单位联系人
+  string agency =26;//代理机构
+  string agencyPerson=27;//代理机构联系人
+  string agencyTel=28;//代理机构联系电话
+  int64 signendTime=29 ;// 报名截止日期
+  int64 bidendTime=30;// 投标截止日期
+  repeated WinnerInfo winnerInfo = 31;// 中标企业信息
+  string spiderCode = 33;//网站代码
+
+}
+//
+message WinnerInfo{
+  string winner = 1;
+  string winnerTel = 2;
+  string winnerPerson = 3;
+  string winnerId = 4;
 }
 //
 message SomeInfoReq{

+ 1 - 0
jyBXSubscribe/rpc/bxsubscribe/bxsubscribe.go

@@ -42,6 +42,7 @@ type (
 	UserResq               = bxsubscribe.UserResq
 	UserStatus             = bxsubscribe.UserStatus
 	ViewStatusResp         = bxsubscribe.ViewStatusResp
+	WinnerInfo             = bxsubscribe.WinnerInfo
 
 	Bxsubscribe interface {
 		// 获取订阅推送列表

+ 27 - 0
jyBXSubscribe/rpc/internal/logic/bypushhistorylogic.go

@@ -1,6 +1,7 @@
 package logic
 
 import (
+	"app.yhyue.com/moapp/jybase/common"
 	"app.yhyue.com/moapp/jybase/encrypt"
 	"context"
 	"github.com/zeromicro/go-zero/core/logx"
@@ -64,14 +65,40 @@ func (l *ByPushHistoryLogic) ByPushHistory(in *bxsubscribe.SubscribeInfosReq) (*
 		NewUserId:        in.NewUserId,
 		BaseServiceMysql: IC.BaseServiceMysql,
 		IsEnt:            in.IsEnt,
+		UserType:         in.UserType,
 	}
 	//主体处理(fType:普通用户;vType:超级订阅用户;mType:大会员用户;eType:商机管理用户)
+<<<<<<< HEAD
 	if in.UserType == model.MemberFlag || in.UserType == model.SubVipFlag {
 		if in.PositionType == 1 {
+=======
+	infoCount := int64(0)
+	if in.UserType == model.MemberFlag {
+		infoCount = IC.MainMysql.CountBySql("select  count(id) from  entniche_wait_empower where  ent_id=? and  end_time>NOW() and  product_type like '%大会员%' ", in.EntId)
+	} else if in.UserType == model.SubVipFlag {
+		infoCount = IC.MainMysql.CountBySql("select  count(id) from  entniche_wait_empower where  ent_id=? and  end_time>NOW() and product_type like '%VIP订阅%' ", in.EntId)
+	}
+	if infoCount > 0 {
+		in.UserType = model.EntnicheFlag
+		vipType = model.EntnicheFlag
+		//主体等于企业的
+		spqp.BuySubject = 1
+	}
+
+	if in.IsEnt == true {
+		newCount := IC.MainMysql.CountBySql("select  count(id) from  entniche_info where  id =? and  status=1", spqp.EntId)
+		if newCount > 0 {
+>>>>>>> master
 			in.UserType = model.EntnicheFlag
 			vipType = model.EntnicheFlag
 		}
 	}
+<<<<<<< HEAD
+=======
+	if in.UserType == model.EntnicheFlag {
+		spqp.UserId = common.InterfaceToStr(spqp.EntUserId)
+	}
+>>>>>>> master
 	logx.Info("数据导出查询参数", in)
 	if selectIds := strings.TrimSpace(in.SelectIds); selectIds != "" {
 		spqp.SelectInfoIds = strings.Split(selectIds, ",")

+ 11 - 0
jyBXSubscribe/rpc/internal/logic/getsublistlogic.go

@@ -6,6 +6,7 @@ import (
 	"jyBXSubscribe/rpc/internal/svc"
 	"jyBXSubscribe/rpc/model"
 	"jyBXSubscribe/rpc/type/bxsubscribe"
+	"jyBXSubscribe/rpc/util"
 	"strings"
 	"time"
 
@@ -40,6 +41,12 @@ func (l *GetSubListLogic) GetSubList(in *bxsubscribe.SubscribeInfosReq) (*bxsubs
 	if in.PageNum == 1 {
 		go model.UpdateUserPushUnread(in.UserId, in.UserType)
 	}
+	isPayUser := false
+	userInfo := util.GetVipState(IC.MainMysql, IC.Mgo, in.UserId)
+	//付费用户
+	if in.UserType != "fType" && userInfo.IsPayedUser() {
+		isPayUser = true
+	}
 	//分发员工
 	var staffIds []string
 	for _, staffId := range strings.Split(in.Staffs, ",") {
@@ -74,7 +81,11 @@ func (l *GetSubListLogic) GetSubList(in *bxsubscribe.SubscribeInfosReq) (*bxsubs
 		IsEnt:            in.IsEnt,
 		BuySubject:       0,
 		UserType:         in.UserType,
+<<<<<<< HEAD
 		PositionType:     in.PositionType,
+=======
+		IsPayUser:        isPayUser,
+>>>>>>> master
 	}
 	//主体处理(fType:普通用户;vType:超级订阅用户;mType:大会员用户;eType:商机管理用户)
 	if in.UserType == model.MemberFlag || in.UserType == model.SubVipFlag {

+ 1 - 1
jyBXSubscribe/rpc/internal/logic/msgdistributorlogic.go

@@ -59,7 +59,7 @@ func (l *MsgDistributorLogic) MsgDistributor(in *bxsubscribe.MsgDistributorReq)
 			pushCas = append(pushCas, &model.PushCa{InfoId: infoId})
 		}
 	}
-	infoList := model.NewSubscribePush().GetInfoByIds(IC.MgoBidding, IC.DB.Mongo.Bidding.Collection, IC.DB.Mongo.Bidding.CollectionBack, pushCas)
+	infoList := model.NewSubscribePush().GetInfoByIds(IC.MgoBidding, IC.DB.Mongo.Bidding.Collection, IC.DB.Mongo.Bidding.CollectionBack, pushCas, false)
 	for _, info := range infoList {
 		if info.Area != "" && info.Area != "全国" {
 			regin = append(regin, info.Area)

+ 47 - 9
jyBXSubscribe/rpc/model/push.go

@@ -28,8 +28,8 @@ import (
 const (
 	pageSize            = 100
 	AllSubPushCacheSize = 200
-	query               = `{"query":{"terms":{"_id":["%s"]}},"_source":["_id","area", "publishtime", "s_subscopeclass", "subtype", "title", "toptype", "type", "buyerclass","bidamount","budget","projectname","buyer","bidopentime","s_winner","filetext"],"from":0,"size":%d}`
-	mongodb_fields      = `{"_id":1,"area":1,"publishtime":1,"s_subscopeclass":1,"subtype":1,"title":1,"toptype":1,"type":1, "buyerclass":1,"budget":1,"bidamount":1,"s_winner":1,"bidopentime":1,"buyer":1,"projectname":1}`
+	query               = `{"query":{"terms":{"_id":["%s"]}},"_source":["_id","area", "publishtime", "s_subscopeclass", "subtype", "title", "toptype", "type", "buyerclass","bidamount","budget","projectname","buyer","bidopentime","s_winner","filetext","spidercode","site","buyertel","buyerperson","agency","agencyperson","agencytel","winnerperson","winnertel","signendtime","bidendtime","entidlist"],"from":0,"size":%d}`
+	mongodb_fields      = `{"_id":1,"area":1,"publishtime":1,"s_subscopeclass":1,"subtype":1,"title":1,"toptype":1,"type":1, "buyerclass":1,"budget":1,"bidamount":1,"s_winner":1,"bidopentime":1,"buyer":1,"projectname":1,"filetext":1,"spidercode":1,"site":1,"buyertel":1,"buyerperson":1,"agency":1,"agencyperson":1,"agencytel":1,"winnerperson":1,"winnertel":1,"signendtime":1,"bidendtime":1,"entidlist":1}`
 
 	SubFreeFlag  = "fType"
 	SubVipFlag   = "vType"
@@ -107,7 +107,11 @@ type SubPushQueryParam struct {
 	SelectInfoIds    []string
 	BuySubject       int64
 	UserType         string
+<<<<<<< HEAD
 	PositionType     int64
+=======
+	IsPayUser        bool // 是否是付费用户
+>>>>>>> master
 }
 
 // 关键词参数
@@ -184,7 +188,7 @@ func (s *subscribePush) allKey(userId, userType string) string {
 }
 
 // 历史推送记录中单条信息格式化
-func (s *subscribePush) InfoFormat(p *PushCa, info *map[string]interface{}) *bxsubscribe.SubscribeInfo {
+func (s *subscribePush) InfoFormat(p *PushCa, info *map[string]interface{}, isPay bool) *bxsubscribe.SubscribeInfo {
 	area := common.ObjToString((*info)["area"])
 	if area == "A" {
 		area = "全国"
@@ -208,7 +212,7 @@ func (s *subscribePush) InfoFormat(p *PushCa, info *map[string]interface{}) *bxs
 	if _id == "" {
 		_id = common.ObjToString((*info)["_id"])
 	}
-	return &bxsubscribe.SubscribeInfo{
+	formatInfo := &bxsubscribe.SubscribeInfo{
 		XId:          encrypt.EncodeArticleId2ByCheck(_id),
 		Title:        common.InterfaceToStr((*info)["title"]),
 		Area:         area,
@@ -231,7 +235,41 @@ func (s *subscribePush) InfoFormat(p *PushCa, info *map[string]interface{}) *bxs
 		CaFileExists: p.FileExists,
 		Source:       p.Source,
 		Site:         common.InterfaceToStr((*info)["site"]),
+		SpiderCode:   common.InterfaceToStr((*info)["spidercode"]),
+	}
+	// 免费用户返回精简列表字段
+	if !isPay {
+		return formatInfo
+	}
+	winnerList := common.InterfaceToStr((*info)["s_winner"]) //中标企业名称集合
+	if winnerList != "" && len(strings.Split(winnerList, ",")) > 0 {
+		for wk, wv := range strings.Split(winnerList, ",") {
+			var (
+				winnerId = ""
+			)
+			if (*info)["entidlist"] != nil {
+				if entIdList := common.ObjArrToStringArr((*info)["entidlist"].([]interface{})); len(entIdList) > wk { //中标企业id集合
+					winnerId = entIdList[wk]
+				}
+			}
+			formatInfo.WinnerInfo = append(formatInfo.WinnerInfo, &bxsubscribe.WinnerInfo{
+				Winner:       wv,                                                                                                              //中标企业 需要单独处理
+				WinnerTel:    common.ObjToString((*info)["winnertel"]),                                                                        //中标企业联系电话
+				WinnerPerson: common.ObjToString((*info)["winnerperson"]),                                                                     //中标企业联系人
+				WinnerId:     common.If(winnerId != "" && len([]rune(winnerId)) > 12, encrypt.EncodeArticleId2ByCheck(winnerId), "").(string), //中标企业加密id  存在winnerId 异常的情况
+			})
+		}
 	}
+	// 付费用户返回详细列表字段
+	formatInfo.BuyerTel = common.ObjToString((*info)["buyertel"])
+	formatInfo.BuyerPerson = common.ObjToString((*info)["buyerperson"])
+	formatInfo.Agency = common.ObjToString((*info)["agency"])
+	formatInfo.AgencyPerson = common.ObjToString((*info)["agencyperson"])
+	formatInfo.AgencyTel = common.ObjToString((*info)["agencytel"])
+	formatInfo.SignendTime = common.Int64All((*info)["signendtime"])
+	formatInfo.BidendTime = common.Int64All((*info)["bidendtime"])
+	return formatInfo
+
 }
 
 func (s *subscribePush) Datas(spqp *SubPushQueryParam) (hasNextPage bool, total int64, result []*bxsubscribe.SubscribeInfo) {
@@ -613,7 +651,7 @@ func (s *subscribePush) getDatasFromMysql(spqp *SubPushQueryParam, starttime, en
 	if list != nil && len(*list) > 0 {
 		pushCas := s.GetJyPushs(*list)
 		if !spqp.Export {
-			result = s.GetInfoByIds(spqp.Mgo_bidding, spqp.Bidding, spqp.Bidding_back, pushCas)
+			result = s.GetInfoByIds(spqp.Mgo_bidding, spqp.Bidding, spqp.Bidding_back, pushCas, spqp.IsPayUser)
 		} else {
 			result = s.GetOnlyExportInfo(pushCas)
 		}
@@ -633,7 +671,7 @@ func (s *subscribePush) GetOnlyExportInfo(pushCas []*PushCa) []*bxsubscribe.Subs
 }
 
 // 根据id取内容
-func (s *subscribePush) GetInfoByIds(Mgo_bidding mongodb.MongodbSim, bidding, bidding_back string, pushCas []*PushCa) []*bxsubscribe.SubscribeInfo {
+func (s *subscribePush) GetInfoByIds(Mgo_bidding mongodb.MongodbSim, bidding, bidding_back string, pushCas []*PushCa, isPay bool) []*bxsubscribe.SubscribeInfo {
 	array := make([]*bxsubscribe.SubscribeInfo, len(pushCas))
 	if len(pushCas) == 0 {
 		return array
@@ -726,7 +764,7 @@ func (s *subscribePush) GetInfoByIds(Mgo_bidding mongodb.MongodbSim, bidding, bi
 		if info == nil {
 			info = map[string]interface{}{}
 		}
-		array[k] = s.InfoFormat(v, &info)
+		array[k] = s.InfoFormat(v, &info, isPay)
 	}
 	return array
 }
@@ -974,7 +1012,7 @@ func GetKeySet(t string, u *map[string]interface{}, data []string) (bool, []stri
 const (
 	INDEX      = "bidding"
 	TYPE       = "bidding"
-	bidField   = `"_id","title","publishtime","toptype","subtype","type","area","city","s_subscopeclass","buyerclass","budget","bidamount","filetext","spidercode","site"`
+	bidField   = `"_id","title","publishtime","toptype","subtype","type","area","city","s_subscopeclass","buyerclass","budget","bidamount","filetext","spidercode","site","buyer","bidopentime","buyertel","buyerperson","agency","agencyperson","agencytel","s_winner",winnerperson","winnertel","signendtime","bidendtime","entidlist"`
 	bidTime    = `{"range":{"publishtime":{"gt":%d}}}`
 	bidSort    = `{"publishtime":"desc"}`
 	findfields = `"title"`
@@ -1050,7 +1088,7 @@ func (s *subscribePush) listManager(spqp *SubPushQueryParam, list []map[string]i
 			Date:       time.Now().Unix(),
 			Keys:       matchkeys,
 			FileExists: v["filetext"] != nil,
-		}, &v)
+		}, &v, spqp.IsPayUser)
 	}
 	id := int64(0)
 	switch s.ModuleFlag {

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 493 - 71
jyBXSubscribe/rpc/type/bxsubscribe/bxsubscribe.pb.go


+ 6 - 0
jyBXSubscribe/rpc/type/bxsubscribe/bxsubscribe_grpc.pb.go

@@ -34,8 +34,11 @@ type BxsubscribeClient interface {
 	SetRead(ctx context.Context, in *SetReadReq, opts ...grpc.CallOption) (*StatusResp, error)
 	//关键词获取
 	GetKey(ctx context.Context, in *GetKeyReq, opts ...grpc.CallOption) (*KeyResp, error)
+<<<<<<< HEAD
 	//订阅设置获取
 	GetSubScribeInfo(ctx context.Context, in *UserReq, opts ...grpc.CallOption) (*UserResq, error)
+=======
+>>>>>>> master
 	//信息分发
 	MsgDistributor(ctx context.Context, in *MsgDistributorReq, opts ...grpc.CallOption) (*StatusResp, error)
 	//手动分发人员查询
@@ -158,8 +161,11 @@ type BxsubscribeServer interface {
 	SetRead(context.Context, *SetReadReq) (*StatusResp, error)
 	//关键词获取
 	GetKey(context.Context, *GetKeyReq) (*KeyResp, error)
+<<<<<<< HEAD
 	//订阅设置获取
 	GetSubScribeInfo(context.Context, *UserReq) (*UserResq, error)
+=======
+>>>>>>> master
 	//信息分发
 	MsgDistributor(context.Context, *MsgDistributorReq) (*StatusResp, error)
 	//手动分发人员查询

+ 53 - 0
jyBXSubscribe/rpc/util/util.go

@@ -1,7 +1,10 @@
 package util
 
 import (
+	MC "app.yhyue.com/moapp/jybase/common"
 	"app.yhyue.com/moapp/jybase/encrypt"
+	"app.yhyue.com/moapp/jybase/mongodb"
+	"app.yhyue.com/moapp/jybase/mysql"
 )
 
 // 加密
@@ -19,3 +22,53 @@ func DecodeId(eid string) string {
 	}
 	return encrypt.DecodeArticleId2ByCheck(eid)[0]
 }
+
+//是否是付费用户
+type VipState struct {
+	VipState     int64 //超级订阅状态(1普通 2升级版)
+	BigMember    int64 //大会员状态
+	EntMember    int64 //商机管理用户状态
+	registerData int64 //注册时间
+}
+
+func GetVipState(mysql *mysql.Mysql, mg mongodb.MongodbSim, userId string) (vs *VipState) {
+	vs = &VipState{}
+	if userId == "" {
+		return
+	}
+	phone := ""
+	data, ok := mg.FindById("user", userId, `"i_member_status":1,"i_vip_status":1,"s_m_phone":1,"s_phone":1,"o_vipjy":1,"l_registedate":1`)
+	if data != nil && len(*data) > 0 && ok {
+		i_vip_status := MC.Int64All((*data)["i_vip_status"])
+		if i_vip_status > 1 {
+			vs.VipState = 1
+			ovipjy, _ := (*data)["o_vipjy"].(map[string]interface{})
+			if ovipjy["o_buyset"] != nil {
+				o_buyset := ovipjy["o_buyset"].(map[string]interface{})
+				if o_buyset["upgrade"] != nil {
+					vs.VipState = 2
+				}
+			}
+		}
+		if i_member_status := MC.Int64All((*data)["i_member_status"]); i_member_status > 0 {
+			vs.BigMember = i_member_status
+		}
+		if s_phone, _ := (*data)["s_phone"].(string); s_phone != "" {
+			phone = s_phone
+		} else if s_m_phone, _ := (*data)["s_m_phone"].(string); s_m_phone != "" {
+			phone = s_m_phone
+		}
+		if phone != "" {
+			if mysql.CountBySql(`select count(1) from entniche_user where phone = ? and power =1`, phone) > 0 {
+				vs.EntMember = 1
+			}
+		}
+		vs.registerData, _ = ((*data)["l_registedate"]).(int64)
+	}
+	return
+}
+
+//是否是付费账户
+func (vs *VipState) IsPayedUser() bool {
+	return vs.VipState > 0 || vs.BigMember > 0 || vs.EntMember > 0
+}

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä