Эх сурвалжийг харах

Merge branch 'master' into feature/v1.1.62

yuelujie 8 сар өмнө
parent
commit
ea030d73fa

+ 53 - 2
jyBXCore/api/bxcore.api

@@ -8,6 +8,7 @@ info(
 )
 
 type (
+	commonReq struct{}
 	searchReq {
 		UserType        string   `path:"userType,optional"`
 		AppId           string   `header:"appId"`
@@ -224,6 +225,7 @@ type (
 		UserId  string `header:"userId,optional"`
 		Refresh int64  `json:"refresh,optional"`
 		Word    string `json:"word,optional"`
+		Mold    int    `json:"mold,optional"` //类型:1:直销-采购信息搜索
 	}
 )
 service bxcore-api {
@@ -258,7 +260,56 @@ service bxcore-api {
 	@handler statisticsProjectDetails//参标项目明细
 	post /jybx/core/statistics/projectDetails (ProjectDetailReq) returns (commonResp)
 	@handler searchCriteria //物业搜索条件返回
-	post /jybx/core/property/searchCriteria () returns (commonResp)
+	post /jybx/core/property/searchCriteria (commonReq) returns (commonResp)
 	@handler mobileHotWord
 	post /jybx/core/mobileHotWord (mobileHotWordReq) returns (commonResp)
-}
+}
+
+//直采-采购信息
+type (
+	purSearchReq {
+		AppId            string `header:"appId"`
+		UserId           string `header:"userId,optional"`
+		Phone            string `header:"phone,optional"`
+		NewUserId        string `header:"newUserId,optional"`
+		EntId            int64  `header:"entId,optional,omitempty"`
+		EntUserId        int64  `header:"entUserId,optional,omitempty"`
+		AccountId        string `header:"accountId,optional,omitempty"`    //账户id
+		EntAccountId     int64  `header:"entAccountId,optional,omitempty"` //企业账户id
+		PositionType     int    `header:"positionType,optional"`           //职位类型 0个人 1企业
+		PositionId       string `header:"positionId,optional"`             //职位id
+		MgoUserId        string `header:"mgoUserId,optional"`              //原userId
+		PageNum          int64  `json:"pageNum,optional"`                  //页码
+		PageSize         int64  `json:"pageSize,optional"`                 //每页数量
+		PublishTime      string `json:"publishTime,optional"`              //发布时间
+		SelectType       string `json:"selectType,optional"`               //搜索范围:默认全部;标题:title;标的物:purchasing
+		DomainFirstType  string `json:"domainFirstType,optional"`          //领域一级分类
+		DomainSecondType string `json:"domainSecondType,optional"`         //领域二级分类
+		DomainThirdType  string `json:"domainThirdType,optional"`          //领域三级分类
+		DeadlineStatus   int64  `json:"deadlineStatus,optional"`           //报名截止状态
+		DeadlineTime     string `json:"deadlineTime,optional"`             //报名截止时间
+		DeliveryArea     string `json:"deliveryArea,optional"`             //交付地点-省份
+		DeliveryCity     string `json:"deliveryCity,optional"`             //交付地点-城市
+		DeliveryDistrict string `json:"deliveryDistrict,optional"`         //交付地点-县区
+		ProjectArea      string `json:"projectArea,optional"`              //项目地区-省份
+		ProjectCity      string `json:"projectCity,optional"`              //项目地区-城市
+		ProjectDistrict  string `json:"projectDistrict,optional"`          //项目地区-县区
+		Industry         string `json:"industry,optional"`                 //行业
+		FileExists       int64  `json:"fileExists,optional"`               //附件
+		Publisher        int64  `json:"publisher,optional"`                //发布者:可选:全部、用户发布:1、平台发布:2。
+		KeyWords         string `json:"keyWords,optional"`                 //关键词
+		AdditionalWords  string `json:"additionalWords,optional"`          //附加词
+		SearchMode       int64  `json:"searchMode,optional"`               //搜索模式:0:精准搜索;1:模糊搜索
+		WordsMode        int64  `json:"wordsMode,optional"`                //搜索关键词模式;默认0:包含所有,1:包含任意
+	}
+)
+
+@server (
+	group:  purchase
+	prefix: jybx
+)
+
+service bxcore-api {
+	@handler purchaseSearch
+	post /core/purchaseSearch (purSearchReq) returns (commonResp)
+}

+ 3 - 1
jyBXCore/api/etc/bxcore-api.yaml

@@ -7,7 +7,9 @@ Webrpcport: 8014
 Gateway:
   ServerCode: jybxcore
   Etcd:
-    - 127.0.0.1:2379
+    - 192.168.3.207:2379
+    - 192.168.3.165:2379
+    - 192.168.3.204:2379
 Core:
   Etcd:
     Hosts:

+ 28 - 0
jyBXCore/api/internal/handler/purchase/purchaseSearchHandler.go

@@ -0,0 +1,28 @@
+package purchase
+
+import (
+	"net/http"
+
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/api/internal/logic/purchase"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/api/internal/svc"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/api/internal/types"
+	"github.com/zeromicro/go-zero/rest/httpx"
+)
+
+func PurchaseSearchHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.PurSearchReq
+		if err := httpx.Parse(r, &req); err != nil {
+			httpx.Error(w, err)
+			return
+		}
+
+		l := purchase.NewPurchaseSearchLogic(r.Context(), svcCtx, r)
+		resp, err := l.PurchaseSearch(&req)
+		if err != nil {
+			httpx.Error(w, err)
+		} else {
+			httpx.OkJson(w, resp)
+		}
+	}
+}

+ 12 - 0
jyBXCore/api/internal/handler/routes.go

@@ -4,6 +4,7 @@ package handler
 import (
 	"net/http"
 
+	purchase "bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/api/internal/handler/purchase"
 	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/api/internal/svc"
 
 	"github.com/zeromicro/go-zero/rest"
@@ -99,4 +100,15 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
 			},
 		},
 	)
+
+	server.AddRoutes(
+		[]rest.Route{
+			{
+				Method:  http.MethodPost,
+				Path:    "/core/purchaseSearch",
+				Handler: purchase.PurchaseSearchHandler(serverCtx),
+			},
+		},
+		rest.WithPrefix("/jybx"),
+	)
 }

+ 26 - 7
jyBXCore/api/internal/logic/mobilehotwordlogic.go

@@ -7,6 +7,7 @@ import (
 	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/api/internal/svc"
 	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/api/internal/types"
 	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/api/internal/util"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/type/bxcore"
 	"context"
 	"fmt"
 	"github.com/zeromicro/go-zero/core/logx"
@@ -29,21 +30,36 @@ func NewMobileHotWordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Mob
 
 func (l *MobileHotWordLogic) MobileHotWord(req *types.MobileHotWordReq) (resp *types.CommonResp, err error) {
 	var rsData []string
+	var baseKeys = func() []string {
+		if req.Mold > 0 {
+			keys, err := l.svcCtx.BxCore.SearchHotKey(l.ctx, &bxcore.HotKeysReq{
+				AppId:  req.AppId,
+				UserId: req.UserId,
+				Mold:   int64(req.Mold),
+			})
+			if err == nil && len(keys.Keys) > 0 {
+				return keys.Keys
+			}
+		}
+		return MC.If(req.UserId == "", IC.C.MobileIndexHotKeyUnLogin, IC.C.MobileIndexHotKey).([]string)
+	}
 	if req.Refresh == 0 { //非刷新动作 自动获取默认缓存热词 5分钟更新一次
-		rsData = MC.If(req.UserId == "", IC.HotKeyArrUnLogin, IC.HotKeyArrLoginEd).([]string)
+		rsData = baseKeys()
 	} else { // 刷新热词 需过滤已经看过的热词
-		var reqWord []string
+		var (
+			reqWord []string
+			mold    = req.Mold
+		)
 		if req.Word != "" {
 			reqWord = strings.Split(req.Word, ",")
 		}
-		redisKey := MC.If(req.UserId == "", "mobileHotWordUnLogin", fmt.Sprintf("mobileHotWordLogin_%s", req.UserId)).(string)
+		redisKey := MC.If(req.UserId == "", fmt.Sprintf("mobileHotWordUnLogin_%d", mold), fmt.Sprintf("mobileHotWordLogin_%s_%d", req.UserId, mold)).(string)
 		rData, _ := redis.Get("newother", redisKey).([]interface{})
 		redisWord := MC.ObjArrToStringArr(rData) //已浏览热词
 		if redisWord != nil {
 			reqWord = append(reqWord, redisWord...)
 		}
-
-		aData := MC.If(req.UserId == "", IC.C.MobileIndexHotKeyUnLogin, IC.C.MobileIndexHotKey).([]string)
+		var aData = baseKeys()
 		rsData = util.FilterWord(aData, reqWord, int(IC.C.MobileIndexHotKeyLimit))
 		if len(reqWord) >= len(aData)-int(IC.C.MobileIndexHotKeyLimit) { //剩余热词已经不足 重新获取
 			redis.Put("newother", redisKey, nil, 60*60*2) //剩余热词不足 重置
@@ -52,9 +68,12 @@ func (l *MobileHotWordLogic) MobileHotWord(req *types.MobileHotWordReq) (resp *t
 		}
 	}
 	var rDataArr []map[string]interface{}
-	for _, datum := range rsData {
+	for rk, rv := range rsData {
+		if rk >= int(IC.C.MobileIndexHotKeyLimit) {
+			break
+		}
 		rDataArr = append(rDataArr, map[string]interface{}{
-			"keyword": datum,
+			"keyword": rv,
 		})
 	}
 	return &types.CommonResp{

+ 77 - 0
jyBXCore/api/internal/logic/purchase/purchaseSearchLogic.go

@@ -0,0 +1,77 @@
+package purchase
+
+import (
+	"app.yhyue.com/moapp/jybase/common"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/api/internal/util"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/type/bxcore"
+	"context"
+	"net/http"
+
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/api/internal/svc"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/api/internal/types"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type PurchaseSearchLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	r      *http.Request
+}
+
+func NewPurchaseSearchLogic(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request) *PurchaseSearchLogic {
+	return &PurchaseSearchLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		r:      r,
+	}
+}
+
+func (l *PurchaseSearchLogic) PurchaseSearch(req *types.PurSearchReq) (resp *types.CommonResp, err error) {
+	defer common.Catch()
+	logx.Info("--------------------")
+	res, err := l.svcCtx.BxCore.PurchaseSearch(l.ctx, &bxcore.PurchaseReq{
+		AppId:            req.AppId,
+		UserId:           req.UserId,
+		Phone:            req.Phone,
+		NewUserId:        req.NewUserId,
+		EntId:            req.EntId,
+		EntUserId:        req.EntUserId,
+		AccountId:        req.AccountId,
+		EntAccountId:     req.EntAccountId,
+		PositionType:     int64(req.PositionType),
+		PositionId:       req.PositionId,
+		MgoUserId:        req.MgoUserId,
+		PageNum:          req.PageNum,
+		PageSize:         req.PageSize,
+		PublishTime:      req.PublishTime,
+		SelectType:       req.SelectType,
+		DomainFirstType:  req.DomainFirstType,
+		DomainSecondType: req.DomainSecondType,
+		DomainThirdType:  req.DomainThirdType,
+		DeadlineStatus:   req.DeadlineStatus,
+		DeadlineTime:     req.DeadlineTime,
+		DeliveryArea:     req.DeliveryArea,
+		DeliveryCity:     req.DeliveryCity,
+		DeliveryDistrict: req.DeliveryDistrict,
+		ProjectArea:      req.ProjectArea,
+		ProjectCity:      req.ProjectCity,
+		ProjectDistrict:  req.ProjectDistrict,
+		Industry:         req.Industry,
+		FileExists:       req.FileExists,
+		Publisher:        req.Publisher,
+		KeyWords:         req.KeyWords,
+		AdditionalWords:  req.AdditionalWords,
+		SearchMode:       req.SearchMode,
+		WordsMode:        req.WordsMode,
+		UserAgent:        l.r.UserAgent(),
+		Platform:         util.CheckPlatform(l.r),
+	})
+	return &types.CommonResp{
+		Err_code: res.ErrCode,
+		Err_msg:  res.ErrMsg,
+		Data:     res.Data,
+	}, nil
+}

+ 40 - 0
jyBXCore/api/internal/types/types.go

@@ -1,6 +1,9 @@
 // Code generated by goctl. DO NOT EDIT.
 package types
 
+type CommonReq struct {
+}
+
 type SearchReq struct {
 	UserType        string   `path:"userType,optional"`
 	AppId           string   `header:"appId"`
@@ -220,4 +223,41 @@ type MobileHotWordReq struct {
 	UserId  string `header:"userId,optional"`
 	Refresh int64  `json:"refresh,optional"`
 	Word    string `json:"word,optional"`
+	Mold    int    `json:"mold,optional"` //类型:1:直销-采购信息搜索
+}
+
+type PurSearchReq struct {
+	AppId            string `header:"appId"`
+	UserId           string `header:"userId,optional"`
+	Phone            string `header:"phone,optional"`
+	NewUserId        string `header:"newUserId,optional"`
+	EntId            int64  `header:"entId,optional,omitempty"`
+	EntUserId        int64  `header:"entUserId,optional,omitempty"`
+	AccountId        string `header:"accountId,optional,omitempty"`    //账户id
+	EntAccountId     int64  `header:"entAccountId,optional,omitempty"` //企业账户id
+	PositionType     int    `header:"positionType,optional"`           //职位类型 0个人 1企业
+	PositionId       string `header:"positionId,optional"`             //职位id
+	MgoUserId        string `header:"mgoUserId,optional"`              //原userId
+	PageNum          int64  `json:"pageNum,optional"`                  //页码
+	PageSize         int64  `json:"pageSize,optional"`                 //每页数量
+	PublishTime      string `json:"publishTime,optional"`              //发布时间
+	SelectType       string `json:"selectType,optional"`               //搜索范围:默认全部;标题:title;标的物:purchasing
+	DomainFirstType  string `json:"domainFirstType,optional"`          //领域一级分类
+	DomainSecondType string `json:"domainSecondType,optional"`         //领域二级分类
+	DomainThirdType  string `json:"domainThirdType,optional"`          //领域三级分类
+	DeadlineStatus   int64  `json:"deadlineStatus,optional"`           //报名截止状态
+	DeadlineTime     string `json:"deadlineTime,optional"`             //报名截止时间
+	DeliveryArea     string `json:"deliveryArea,optional"`             //交付地点-省份
+	DeliveryCity     string `json:"deliveryCity,optional"`             //交付地点-城市
+	DeliveryDistrict string `json:"deliveryDistrict,optional"`         //交付地点-县区
+	ProjectArea      string `json:"projectArea,optional"`              //项目地区-省份
+	ProjectCity      string `json:"projectCity,optional"`              //项目地区-城市
+	ProjectDistrict  string `json:"projectDistrict,optional"`          //项目地区-县区
+	Industry         string `json:"industry,optional"`                 //行业
+	FileExists       int64  `json:"fileExists,optional"`               //附件
+	Publisher        int64  `json:"publisher,optional"`                //发布者:可选:全部、用户发布:1、平台发布:2。
+	KeyWords         string `json:"keyWords,optional"`                 //关键词
+	AdditionalWords  string `json:"additionalWords,optional"`          // 附加词
+	SearchMode       int64  `json:"searchMode,optional"`               //搜索模式:0:精准搜索;1:模糊搜索
+	WordsMode        int64  `json:"wordsMode,optional"`                //搜索关键词模式;默认0:包含所有,1:包含任意
 }

+ 102 - 1
jyBXCore/rpc/bxcore.proto

@@ -629,6 +629,104 @@ message TipInfo {
   string openType = 7;
 }
 
+//
+message HotKeysReq{
+  string appId = 1;
+  string userId = 2;
+  int64 mold = 3;
+}
+
+message HotKeysRes{
+  repeated string keys = 1;
+}
+//
+
+message PurchaseReq {
+  string appId = 1;//剑鱼默认10000
+  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
+  string accountId = 7; //账户id
+  int64 entAccountId = 8; //企业账户id
+  int64 positionType = 9; //职位类型 0个人 1企业
+  string positionId = 10;  //职位id
+  string mgoUserId = 11;  //原userId
+  int64  pageNum = 12;//当前页码
+  int64  pageSize = 13;//每页数量
+  string  publishTime = 14;//发布时间
+  string selectType = 15;//搜索范围:默认全部;标题:title;标的物:purchasing
+  string domainFirstType = 16;//领域
+  string domainSecondType = 17;//领域
+  string domainThirdType = 18;//领域
+  string  deliveryArea = 19;//交付地点-省份
+  string deliveryCity = 20;//交付地点-城市
+  string deliveryDistrict = 21;//交付地点-县区
+  string projectArea = 22;     //项目地区-省份
+  string projectCity  = 23;    //项目地区-城市
+  string projectDistrict  = 24; //项目地区-县区
+  string industry = 25;//行业
+  int64 fileExists = 26;//是否有附件
+  int64 publisher = 27;//发布者:可选:全部、用户发布:1、平台发布:2。
+  string keyWords = 28;//关键词:多个空格隔开(主)
+  string additionalWords = 29;//关键词:附加关键词(副:五组,每组最多15个字符)
+  int64 searchMode = 30;//搜索模式:0:精准搜索;1:模糊搜索
+  int64 wordsMode = 31;//搜索关键词模式;默认0:包含所有,1:包含任意
+  string userAgent = 32;//请求头信息
+  string  platform = 33;//请求平台
+  int64 deadlineStatus = 34;//报名截止状态
+  string deadlineTime = 35;//报名截止时间
+}
+
+
+message PurchaseResp {
+  int64 err_code = 1;
+  string err_msg = 2;
+  PurchaseData data = 3;
+}
+message PurchaseData {
+  int64 total = 1;//返回数据总量
+  int64 pageSize = 2;//每页数据量
+  int64 pageNum = 3;//当前页码
+  string tipMsg = 4;//输入框的关键词太长进行截取后的关键词
+  string highlightWords = 5;//格式化后的关键词
+  repeated PurchaseList list = 6;//搜索列表
+  int64 count = 7;//返回查询结果数据量
+  string interceptKeywords = 8;
+  int64 interceptLimit = 9;
+  string interceptOtherWords = 10;
+  string keyWords = 11;
+  int64 bCount = 12;
+}
+
+message  PurchaseList {
+  string id = 1;//信息id
+  string area = 2;//地区
+  string city = 3;//城市
+  string district = 4;// 区县
+  string regionUrl = 5;//地区标签地址
+  string buyerClass = 6;//采购单位类型
+  int64  publishTime = 7;//发布时间
+  bool   fileExists = 8;//是否有附件
+  string title = 9;//标题
+  int64  price = 10;//预算 or 中标金额
+  string buyer = 11;//采购单位
+  string buyerTel = 12;//采购单位联系电话
+  string deliveryLoc = 14;//交付地点
+  string industry = 15;//行业标签
+  string buyerPerson = 16;//采购单位联系人
+  string agency = 17;//代理机构
+  string agencyPerson = 18;//代理机构联系人
+  string agencyTel = 19;//代理机构联系电话
+  repeated WinnerInfo winnerInfo = 20;//中标企业信息
+  int64 bidOpenTime = 21;//开标时间
+  int64 signEndTime = 22;//报名截止时间
+  int64 bidEndTime = 23;//投标截止时间
+  string publicType = 24;//发布平台
+  string originalTitle = 25;//原标题
+  int64 isNew = 26; //是否是新的网站来源 is_yg_new==1
+}
 //
 service BxCore {
   //标讯搜索结果列表数据
@@ -661,5 +759,8 @@ service BxCore {
   rpc PolymerizeSearch(PolymerizeSearchReq) returns (PolymerizeSearchResp);
   rpc ProjectDetails(ProjectDetailsReq) returns (DetailDataRes);
   rpc PropertySearchCriteria(SearchReq) returns (SearchCriteriaRes);
-
+  //热搜词
+  rpc SearchHotKey(HotKeysReq)returns(HotKeysRes);
+  //采购信息搜索
+  rpc PurchaseSearch(PurchaseReq)returns(PurchaseResp);
 }

+ 22 - 0
jyBXCore/rpc/bxcore/bxcore.go

@@ -17,6 +17,8 @@ type (
 	BidTypeReq               = bxcore.BidTypeReq
 	DetailData               = bxcore.DetailData
 	DetailDataRes            = bxcore.DetailDataRes
+	HotKeysReq               = bxcore.HotKeysReq
+	HotKeysRes               = bxcore.HotKeysRes
 	MenuList                 = bxcore.MenuList
 	PInfo                    = bxcore.PInfo
 	ParticipateActionReq     = bxcore.ParticipateActionReq
@@ -49,6 +51,10 @@ type (
 	ProjectDetailsReq        = bxcore.ProjectDetailsReq
 	ProjectStatisticsData    = bxcore.ProjectStatisticsData
 	ProjectStatisticsDataRes = bxcore.ProjectStatisticsDataRes
+	PurchaseData             = bxcore.PurchaseData
+	PurchaseList             = bxcore.PurchaseList
+	PurchaseReq              = bxcore.PurchaseReq
+	PurchaseResp             = bxcore.PurchaseResp
 	PushStatisticsData       = bxcore.PushStatisticsData
 	PushStatisticsDataRes    = bxcore.PushStatisticsDataRes
 	RemindRuleReq            = bxcore.RemindRuleReq
@@ -102,6 +108,10 @@ type (
 		PolymerizeSearch(ctx context.Context, in *PolymerizeSearchReq, opts ...grpc.CallOption) (*PolymerizeSearchResp, error)
 		ProjectDetails(ctx context.Context, in *ProjectDetailsReq, opts ...grpc.CallOption) (*DetailDataRes, error)
 		PropertySearchCriteria(ctx context.Context, in *SearchReq, opts ...grpc.CallOption) (*SearchCriteriaRes, error)
+		// 热搜词
+		SearchHotKey(ctx context.Context, in *HotKeysReq, opts ...grpc.CallOption) (*HotKeysRes, error)
+		// 采购信息搜索
+		PurchaseSearch(ctx context.Context, in *PurchaseReq, opts ...grpc.CallOption) (*PurchaseResp, error)
 	}
 
 	defaultBxCore struct {
@@ -208,3 +218,15 @@ func (m *defaultBxCore) PropertySearchCriteria(ctx context.Context, in *SearchRe
 	client := bxcore.NewBxCoreClient(m.cli.Conn())
 	return client.PropertySearchCriteria(ctx, in, opts...)
 }
+
+// 热搜词
+func (m *defaultBxCore) SearchHotKey(ctx context.Context, in *HotKeysReq, opts ...grpc.CallOption) (*HotKeysRes, error) {
+	client := bxcore.NewBxCoreClient(m.cli.Conn())
+	return client.SearchHotKey(ctx, in, opts...)
+}
+
+// 采购信息搜索
+func (m *defaultBxCore) PurchaseSearch(ctx context.Context, in *PurchaseReq, opts ...grpc.CallOption) (*PurchaseResp, error) {
+	client := bxcore.NewBxCoreClient(m.cli.Conn())
+	return client.PurchaseSearch(ctx, in, opts...)
+}

+ 3 - 3
jyBXCore/rpc/etc/bxcore.yaml

@@ -2,9 +2,7 @@ Name: bxcore.rpc
 ListenOn: 0.0.0.0:8004
 Etcd:
   Hosts:
-  - 192.168.3.207:2379
-  - 192.168.3.165:2379
-  - 192.168.3.204:2379
+    - 127.0.0.1:2379
   Key: bxcore.rpc
 Timeout: 12000
 WebRpcPort: 8016
@@ -83,3 +81,5 @@ Stages:
 SearchWinner:
   Switch: true
   RegWinner: ".+[司院厂所心处普行]$"
+PurchaseCode: ygzc_cgxx
+PurchaseDiffSwitch: false

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

@@ -61,6 +61,7 @@ func (r *ReqLimit) Limit(ctx context.Context) int {
 func (r *ReqLimit) Release() {
 	r.DoPool <- struct{}{}
 }
+
 func init() {
 	//基本配置
 	conf.MustLoad(*configFile, &C)

+ 2 - 0
jyBXCore/rpc/internal/config/config.go

@@ -68,6 +68,8 @@ type Config struct {
 		Switch    bool
 		RegWinner string
 	}
+	PurchaseCode       string
+	PurchaseDiffSwitch bool //付费和免费查询区分开关
 }
 type Db struct {
 	Mysql     entity.Mysql      `json:"mysql"`

+ 80 - 0
jyBXCore/rpc/internal/logic/purchasesearchlogic.go

@@ -0,0 +1,80 @@
+package logic
+
+import (
+	MC "app.yhyue.com/moapp/jybase/common"
+	IC "bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/init"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/internal/svc"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/service"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/type/bxcore"
+	"context"
+	"fmt"
+	"github.com/zeromicro/go-zero/core/logx"
+	"log"
+)
+
+type PurchaseSearchLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewPurchaseSearchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PurchaseSearchLogic {
+	return &PurchaseSearchLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+// 采购信息搜索
+func (l *PurchaseSearchLogic) PurchaseSearch(in *bxcore.PurchaseReq) (*bxcore.PurchaseResp, error) {
+	var (
+		res = &bxcore.PurchaseResp{
+			Data: &bxcore.PurchaseData{
+				List: []*bxcore.PurchaseList{},
+			},
+		}
+	)
+	ps := service.NewPurchase(in)
+	ps.FilterCriteriaFormat()
+	//更新历史记录
+	go ps.HistoryKeywords()
+	if IC.C.NoLoginSearch.Switch && ps.UserId == "" {
+		flag := IC.ReqLimitInit.Limit(context.Background())
+		if flag == 1 {
+			defer IC.ReqLimitInit.Release()
+		} else {
+			if flag == -2 {
+				log.Println("等待队列已满")
+			} else if flag == -1 {
+				log.Println("等待超时")
+			}
+		}
+		if flag < 0 {
+			log.Println("--并发队列--", fmt.Errorf("暂无数据"))
+			return &bxcore.PurchaseResp{}, nil
+		}
+	}
+	list, err := ps.GetPurchaseData()
+	if err == nil && len(list) > 0 {
+		res.Data.List = list
+	}
+	// 精准模式不足50条的非空标讯查询 匹配模糊查询数
+	if ps.Total < IC.C.PaySearchLimit.PrecisionNum && in.SearchMode == 0 && !ps.IsEmptySearch() {
+		ps.SearchMode = 1
+		ps.FilterCriteriaFormat()
+		res.Data.BCount = ps.GetPurchaseCount()
+		log.Println("精准查询数据不足 匹配模糊查询数:", res.Data.BCount)
+	}
+	res.Data.PageNum = ps.PageNum
+	res.Data.PageSize = ps.PageSize
+	res.Data.TipMsg = ps.TipMsg
+	res.Data.HighlightWords = ps.HighlightWords
+	res.Data.Total = ps.Total
+	res.Data.Count = ps.Count
+	res.Data.KeyWords = ps.HighlightWords
+	res.Data.InterceptLimit = int64(MC.IntAllDef(IC.C.KeywordsLimit, 35))
+	res.Data.InterceptKeywords = ps.InterceptKeyWords
+	res.Data.InterceptOtherWords = ps.TipMsg
+	return res, err
+}

+ 47 - 0
jyBXCore/rpc/internal/logic/searchhotkeylogic.go

@@ -0,0 +1,47 @@
+package logic
+
+import (
+	"app.yhyue.com/moapp/jybase/common"
+	IC "bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/init"
+	"context"
+	"strings"
+
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/internal/svc"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/type/bxcore"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type SearchHotKeyLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewSearchHotKeyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SearchHotKeyLogic {
+	return &SearchHotKeyLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+// 热搜词
+func (l *SearchHotKeyLogic) SearchHotKey(in *bxcore.HotKeysReq) (*bxcore.HotKeysRes, error) {
+	if in.Mold > 0 {
+		res := &bxcore.HotKeysRes{Keys: []string{}}
+		keyData := IC.BaseMysql.SelectBySql("SELECT name,vitality FROM search_hot_keyword shk WHERE shk.state  = 0 AND shk.classification = ? ORDER  BY  vitality DESC ", in.Mold)
+		if keyData != nil && len(*keyData) > 0 {
+			for _, keys := range *keyData {
+				name := common.InterfaceToStr(keys["name"])
+				if name == "" {
+					continue
+				}
+				res.Keys = append(res.Keys, strings.TrimSpace(name))
+			}
+			return res, nil
+		}
+	}
+
+	return &bxcore.HotKeysRes{}, nil
+}

+ 12 - 0
jyBXCore/rpc/internal/server/bxcoreserver.go

@@ -115,3 +115,15 @@ func (s *BxCoreServer) PropertySearchCriteria(ctx context.Context, in *bxcore.Se
 	l := logic.NewPropertySearchCriteriaLogic(ctx, s.svcCtx)
 	return l.PropertySearchCriteria(in)
 }
+
+// 热搜词
+func (s *BxCoreServer) SearchHotKey(ctx context.Context, in *bxcore.HotKeysReq) (*bxcore.HotKeysRes, error) {
+	l := logic.NewSearchHotKeyLogic(ctx, s.svcCtx)
+	return l.SearchHotKey(in)
+}
+
+// 采购信息搜索
+func (s *BxCoreServer) PurchaseSearch(ctx context.Context, in *bxcore.PurchaseReq) (*bxcore.PurchaseResp, error) {
+	l := logic.NewPurchaseSearchLogic(ctx, s.svcCtx)
+	return l.PurchaseSearch(in)
+}

+ 16 - 5
jyBXCore/rpc/model/es/es.go

@@ -12,13 +12,14 @@ import (
 
 const (
 	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}}`
+	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}}}]}}`
 	queryBoolMustScopeClass = `{"bool":{"should":[{"terms":{"s_subscopeclass":[%s]}},{"bool":{"must":[{"terms":{"s_topscopeclass":[%s]}},{"bool":{"must_not":[{"exists":{"field":"s_subscopeclass"}}]}}]}}],"minimum_should_match":1}}` //`{"bool":{"must":[{"terms":{"s_subscopeclass":[%s]}}]}}`
-	queryBoolMustTerm       = `{"bool": {"must": [{ "term": {"isValidFile": %t }}]}}`
-	queryBoolMustA          = `{"bool":{"must":[{"terms":{"%s":[%s]}}]}}`
+	QueryBoolMustTermBool   = `{"bool": {"must": [{ "term": {"%s": %t }}]}}`
+	QueryBoolMustTerm       = `{"bool": {"must": [{ "term": {"%s": "%s" }}]}}`
+	QueryBoolMustA          = `{"bool":{"must":[{"terms":{"%s":[%s]}}]}}`
 	queryExists             = `{"constant_score":{"filter":{"exists":{"field":"%s"}}}}`
 	gte                     = `"gte": %s`
 	lte                     = `"lte": %s`
@@ -40,6 +41,12 @@ const (
 	LoginTypePay     = 1            // 付费用户
 	LoginTypeFree    = 2            // 免费用户
 	LoginTypeNoLogin = 3            // 未登录用户
+	//直采-采购信息
+	PurchaseType              = "bidding_yg"
+	PurchaseIndex             = "bidding_yg"
+	PurchaseBaseField         = `"_id","source_id","title","area","city","district","buyerclass","publishtime","isValidFile","budget","bidamount","signendtime","deliver_area","deliver_city","deliver_district","buyer","buyertel","s_subscopeclass","public_type","purchasing","spidercode","purchasinglist","projectname","subtype"` //
+	PurchaseSearchSort        = `{"publishtime":-1}`
+	PurchaseBaseFieldForPayer = PurchaseBaseField + `,"buyerperson","agency","agencytel","agencyperson","s_winner","winnertel","winnerperson","bidendtime","projectinfo","entidlist"`
 )
 
 var (
@@ -53,6 +60,10 @@ var (
 		"拟建项目":   "拟建",
 		"采购意向":   "采购意向",
 	}
+	PurchasePublicType = []string{
+		"用户发布",
+		"平台发布",
+	}
 )
 
 type SearchByES struct {

+ 21 - 22
jyBXCore/rpc/model/es/search.go

@@ -68,7 +68,7 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 					findFields = strings.Replace(findFields, `,"title"`, ``, -1)
 				}
 			}
-			keyWordsMusts = append(keyWordsMusts, fmt.Sprintf(fmt.Sprintf(multiMatch, "%s", findFields), elastic.ReplaceYH(v)))
+			keyWordsMusts = append(keyWordsMusts, fmt.Sprintf(fmt.Sprintf(MultiMatch, "%s", findFields), elastic.ReplaceYH(v)))
 		}
 		//搜索关键词模式;默认0:包含所有,1:包含任意
 		if in.WordsMode == 1 {
@@ -103,7 +103,7 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 						findFields = strings.Replace(findFields, `,"title"`, ``, -1)
 					}
 				}
-				addWordsMust = append(addWordsMust, fmt.Sprintf(fmt.Sprintf(multiMatch, "%s", findFields), elastic.ReplaceYH(v)))
+				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...)
@@ -120,13 +120,13 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 	//搜索关键词模式;默认0:包含所有,1:包含任意
 	//包含任意一组
 	if len(wordsShould) > 0 {
-		musts = append(musts, fmt.Sprintf(queryBoolShould, strings.Join(wordsShould, ",")))
+		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)
+		notKeyMultiMatch := fmt.Sprintf(MultiMatch, "%s", findFields)
 		var notKeyMustNot []string
 		//多组排除词
 		for _, nks := range strings.Split(notKey, ",") {
@@ -139,17 +139,17 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 				if len([]rune(elastic.ReplaceYH(v))) == 1 {
 					//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
 					if DetailFileORTitle(findFields) {
-						notKeyMultiMatch = fmt.Sprintf(multiMatch, "%s", findFields+`,"title"`)
+						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, ",")))
+		mustNot = append(mustNot, fmt.Sprintf(QueryBoolShould, strings.Join(notKeyMustNot, ",")))
 	}
 	//行业
 	if in.Industry != "" && isLogin {
-		musts = append(musts, fmt.Sprintf(queryBoolMustA, "s_subscopeclass", `"`+strings.ReplaceAll(in.Industry, ",", `","`)+`"`))
+		musts = append(musts, fmt.Sprintf(QueryBoolMustA, "s_subscopeclass", `"`+strings.ReplaceAll(in.Industry, ",", `","`)+`"`))
 		//var (
 		//	topSC []string
 		//	topQT bool
@@ -171,7 +171,7 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 		//	//二级行业-其他
 		//	musts = append(musts, fmt.Sprintf(queryBoolMustScopeClass, `"`+strings.ReplaceAll(in.Industry, ",", `","`)+`"`, `"`+strings.Join(topSC, `","`)+`"`))
 		//} else {
-		//	musts = append(musts, fmt.Sprintf(queryBoolMustA, "s_subscopeclass", `"`+strings.ReplaceAll(in.Industry, ",", `","`)+`"`))
+		//	musts = append(musts, fmt.Sprintf(QueryBoolMustA, "s_subscopeclass", `"`+strings.ReplaceAll(in.Industry, ",", `","`)+`"`))
 		//}
 	}
 	//价格
@@ -203,7 +203,7 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 				sq += fmt.Sprintf(lte, maxPrice)
 			}
 			if minPrice != "" || maxPrice != "" {
-				query_price := fmt.Sprintf(queryBoolShould, fmt.Sprintf(queryBoolMustBoolShould, sq, sq))
+				query_price := fmt.Sprintf(QueryBoolShould, fmt.Sprintf(queryBoolMustBoolShould, sq, sq))
 				musts = append(musts, query_price)
 			}
 		}
@@ -228,20 +228,20 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 	}
 	//移动融创
 	if in.MobileTag != nil && len(in.MobileTag) > 0 && in.IsPay { //仅付费bidding表有此字段
-		musts = append(musts, fmt.Sprintf(queryBoolMustA, "mobile_tag", `"`+strings.Join(in.MobileTag, `","`)+`"`))
+		musts = append(musts, fmt.Sprintf(QueryBoolMustA, "mobile_tag", `"`+strings.Join(in.MobileTag, `","`)+`"`))
 	}
 	if isLogin { //需要登录
 		//电脑端 物业专版BI
 		if in.BidField == "BIProperty" {
 			if !entity.MobileReg.MatchString(in.UserAgent) {
-				musts = append(musts, fmt.Sprintf(queryBoolMustA, "tag_topinformation", `"情报_物业"`))
+				musts = append(musts, fmt.Sprintf(QueryBoolMustA, "tag_topinformation", `"情报_物业"`))
 				//物业业态
 				if in.PropertyForm != "" {
 					arr := []string{}
 					for _, v := range strings.Split(in.PropertyForm, ",") {
 						arr = append(arr, fmt.Sprintf(`"%s"`, v))
 					}
-					musts = append(musts, fmt.Sprintf(queryBoolShould, fmt.Sprintf(`{"terms":{"tag_set.wuye.property_form":[%s]}}`, strings.Join(arr, ","))))
+					musts = append(musts, fmt.Sprintf(QueryBoolShould, fmt.Sprintf(`{"terms":{"tag_set.wuye.property_form":[%s]}}`, strings.Join(arr, ","))))
 				}
 				//业务类型
 				if in.SubInformation != "" {
@@ -249,7 +249,7 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 					for _, v := range strings.Split(in.SubInformation, ",") {
 						arr = append(arr, fmt.Sprintf(`"%s"`, v))
 					}
-					musts = append(musts, fmt.Sprintf(queryBoolShould, fmt.Sprintf(`{"terms":{"tag_subinformation":[%s]}}`, strings.Join(arr, ","))))
+					musts = append(musts, fmt.Sprintf(QueryBoolShould, fmt.Sprintf(`{"terms":{"tag_subinformation":[%s]}}`, strings.Join(arr, ","))))
 				}
 				//价格区间
 				if in.Scale != "" {
@@ -257,7 +257,7 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 					for _, v := range strings.Split(in.Scale, ",") {
 						arr = append(arr, fmt.Sprintf(`"%s"`, v))
 					}
-					musts = append(musts, fmt.Sprintf(queryBoolShould, fmt.Sprintf(`{"terms":{"tag_set.wuye.scale":[%s]}}`, strings.Join(arr, ","))))
+					musts = append(musts, fmt.Sprintf(QueryBoolShould, fmt.Sprintf(`{"terms":{"tag_set.wuye.scale":[%s]}}`, strings.Join(arr, ","))))
 				}
 				//合同周期
 				if in.Period != "" {
@@ -265,7 +265,7 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 					for _, v := range strings.Split(in.Period, ",") {
 						arr = append(arr, fmt.Sprintf(`"%s"`, v))
 					}
-					musts = append(musts, fmt.Sprintf(queryBoolShould, fmt.Sprintf(`{"terms":{"tag_set.wuye.period":[%s]}}`, strings.Join(arr, ","))))
+					musts = append(musts, fmt.Sprintf(QueryBoolShould, fmt.Sprintf(`{"terms":{"tag_set.wuye.period":[%s]}}`, strings.Join(arr, ","))))
 				}
 				//换手率
 				if in.ChangeHand != 0 {
@@ -277,7 +277,7 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 				if in.FileExists != "" {
 					if in.FileExists == "1" {
 						//存在
-						musts = append(musts, fmt.Sprintf(queryBoolMustA, "tag_set.wuye.isfile", `"63"`))
+						musts = append(musts, fmt.Sprintf(QueryBoolMustA, "tag_set.wuye.isfile", `"63"`))
 					} else {
 						//不存在
 						mustNot = append(mustNot, fmt.Sprintf(queryExists, "tag_set.wuye.isfile"))
@@ -289,9 +289,9 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 			fileExists := in.FileExists
 			if !isFileSearch && fileExists != "" {
 				if fileExists == "1" { //有附件
-					musts = append(musts, fmt.Sprintf(queryBoolMustTerm, true))
+					musts = append(musts, fmt.Sprintf(QueryBoolMustTermBool, "isValidFile", true))
 				} else if fileExists == "-1" { //无附件
-					mustNot = append(mustNot, fmt.Sprintf(queryBoolMustTerm, true))
+					mustNot = append(mustNot, fmt.Sprintf(QueryBoolMustTermBool, "isValidFile", true))
 				}
 			}
 			if in.BidField == "medical" { // 如果是领域化数据则需要加标签
@@ -300,7 +300,7 @@ func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
 		}
 	}
 	//in.BidField  剑鱼默认招标信息搜索 此参数为空**
-	qstr = fmt.Sprintf(query, strings.Join(musts, ","), strings.Join(mustNot, ","))
+	qstr = fmt.Sprintf(Query, strings.Join(musts, ","), strings.Join(mustNot, ","))
 	log.Println("qstr:", qstr)
 	return
 }
@@ -350,10 +350,9 @@ func GetBidSearchQuery(in *bxcore.SearchReq) string {
 			queryBoolMustAndDistrict := `{"bool":{"must":[{"terms":{"city":["%s"]}},{"terms":{"district":["%s"]}}]}}`
 			query += fmt.Sprintf(queryBoolMustAndDistrict, cityName, districtName)
 		}
-
 	}
 	if query != "" {
-		query = fmt.Sprintf(queryBoolShould, query)
+		query = fmt.Sprintf(QueryBoolShould, query)
 	}
 	//发布时间
 	publishTime := in.PublishTime
@@ -447,7 +446,7 @@ func GetBidSearchQuery(in *bxcore.SearchReq) string {
 		if query != "" {
 			query += ","
 		}
-		query += fmt.Sprintf(queryBoolShould, allType)
+		query += fmt.Sprintf(QueryBoolShould, allType)
 	}
 	//采购单位类型
 	buyerClass := in.BuyerClass

+ 732 - 0
jyBXCore/rpc/service/purchase.go

@@ -0,0 +1,732 @@
+package service
+
+import (
+	MC "app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/encrypt"
+	elastic "app.yhyue.com/moapp/jybase/es"
+	"app.yhyue.com/moapp/jybase/redis"
+	"app.yhyue.com/moapp/jypkg/common/src/qfw/util/jy"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/entity"
+	IC "bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/init"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/model/es"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/type/bxcore"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/util"
+	"encoding/json"
+	"fmt"
+	"github.com/zeromicro/go-zero/core/logx"
+	"log"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type Purchase struct {
+	AppId             string ` json:"appId,omitempty"`            //剑鱼默认10000
+	UserId            string ` json:"userId,omitempty"`           //用户id
+	Phone             string ` json:"phone,omitempty"`            //手机号
+	BaseUserId        int64  ` json:"baseUserId,omitempty"`       //base_user_id 新用户id
+	EntId             int64  ` json:"entId,omitempty"`            //企业id 没有企业 企业id=0
+	EntUserId         int64  ` json:"entUserId,omitempty"`        //企业用户id  当前企业下的员工id 没有企业默认0
+	AccountId         int64  ` json:"accountId,omitempty"`        //账户id
+	EntAccountId      int64  ` json:"entAccountId,omitempty"`     //企业账户id
+	PositionType      int64  ` json:"positionType,omitempty"`     //职位类型 0个人 1企业
+	PositionId        int64  ` json:"positionId,omitempty"`       //职位id
+	MgoUserId         string ` json:"mgoUserId,omitempty"`        //原userId
+	PageNum           int64  ` json:"pageNum,omitempty"`          //当前页码
+	PageSize          int64  ` json:"pageSize,omitempty"`         //每页数量
+	PublishTime       string ` json:"publishTime,omitempty"`      //发布时间
+	SelectType        string ` json:"selectType,omitempty"`       //搜索范围:
+	DomainFirstType   string ` json:"domainFirstType,omitempty"`  //领域 一级
+	DomainSecondType  string ` json:"domainSecondType,omitempty"` //领域 二级
+	DomainThirdType   string ` json:"domainThirdType,omitempty"`  //领域 三级
+	DeadlineStatus    int64  ` json:"deadlineStatus,omitempty"`   //报名截止状态
+	DeadlineTime      string ` json:"deadlineTime,omitempty"`     //报名截止时间
+	DeadlineStart     int64  ` json:"deadlineStart,omitempty"`    //报名截止时间-开始
+	DeadlineEnd       int64  ` json:"deadlineEnd,omitempty"`      //报名截止时间-结束
+	DeliveryArea      string ` json:"deliveryArea,omitempty"`     //交付地点-省份
+	DeliveryCity      string ` json:"deliveryCity,omitempty"`     //交付地点-城市
+	DeliveryDistrict  string ` json:"deliveryDistrict,omitempty"` //交付地点-县区
+	ProjectArea       string ` json:"projectArea,omitempty"`      //项目地区-省份
+	ProjectCity       string ` json:"projectCity,omitempty"`      //项目地区-城市
+	ProjectDistrict   string ` json:"projectDistrict,omitempty"`  //项目地区-县区
+	Industry          string ` json:"industry,omitempty"`         //行业
+	FileExists        int64  ` json:"fileExists,omitempty"`       //是否有附件
+	Publisher         int64  ` json:"publisher,omitempty"`        //发布者:可选:全部、用户发布:1、平台发布:2。
+	KeyWords          string ` json:"keyWords,omitempty"`         //关键词:多个空格隔开(主)
+	AdditionalWords   string ` json:"additionalWords,omitempty"`  //关键词:附加关键词(副:五组,每组最多15个字符)
+	SearchMode        int64  ` json:"searchMode,omitempty"`       //搜索模式:0:精准搜索;1:模糊搜索
+	WordsMode         int64  ` json:"wordsMode,omitempty"`        //搜索关键词模式;默认0:包含所有,1:包含任意
+	UserAgent         string ` json:"userAgent,omitempty"`        //请求头信息
+	Platform          string ` json:"platform,omitempty"`         //请求平台
+	TipMsg            string `json:"tipMsg"`                      //关键词提示信息
+	HighlightWords    string `json:"highlightWords"`              //需要高亮的词,多个,号分割
+	Total             int64  `json:"total"`                       //数据总量
+	Count             int64  `json:"count"`                       //结果数据总量
+	IsPay             bool   `json:"isPay"`                       //是否是付费用户
+	IsPower           bool   `json:"isPower"`                     //是否有权限
+	InterceptKeyWords string `json:"interceptKeyWords"`
+}
+
+func NewPurchase(in *bxcore.PurchaseReq) *Purchase {
+	baseUserId, _ := strconv.ParseInt(in.NewUserId, 10, 64)
+	accountId, _ := strconv.ParseInt(in.AccountId, 10, 64)
+	positionId, _ := strconv.ParseInt(in.PositionId, 10, 64)
+	return &Purchase{
+		AppId:            in.AppId,
+		UserId:           in.UserId,
+		Phone:            in.Phone,
+		BaseUserId:       baseUserId,
+		EntId:            in.EntId,
+		EntUserId:        in.EntUserId,
+		AccountId:        accountId,
+		EntAccountId:     in.EntAccountId,
+		PositionType:     in.PositionType,
+		PositionId:       positionId,
+		MgoUserId:        in.MgoUserId,
+		PageNum:          in.PageNum,
+		PageSize:         in.PageSize,
+		PublishTime:      in.PublishTime,
+		SelectType:       in.SelectType,
+		DomainFirstType:  in.DomainFirstType,
+		DomainSecondType: in.DomainSecondType,
+		DomainThirdType:  in.DomainThirdType,
+		DeadlineStatus:   in.DeadlineStatus,
+		DeadlineTime:     in.DeadlineTime,
+		DeliveryArea:     in.DeliveryArea,
+		DeliveryCity:     in.DeliveryCity,
+		DeliveryDistrict: in.DeliveryDistrict,
+		ProjectArea:      in.ProjectArea,
+		ProjectCity:      in.ProjectCity,
+		ProjectDistrict:  in.ProjectDistrict,
+		Industry:         in.Industry,
+		FileExists:       in.FileExists,
+		Publisher:        in.Publisher,
+		KeyWords:         in.KeyWords,
+		AdditionalWords:  in.AdditionalWords,
+		SearchMode:       in.SearchMode,
+		WordsMode:        in.WordsMode,
+		UserAgent:        in.UserAgent,
+		Platform:         in.Platform,
+	}
+}
+
+var (
+	AreaLabelLink = "/list/%s/%s.html"
+	noPower       = "点击查看"
+)
+
+// 缓存
+func (p *Purchase) HistoryKeywords() {
+	var (
+		cacheKey         = fmt.Sprintf("history_purchase_v_%s", p.UserId)
+		keys             []string
+		code             = "other"
+		isExist          = map[string]bool{}
+		duplicateRemoval = func(values []string) (keys []string) {
+			for _, kv := range values {
+				kv = strings.TrimSpace(kv)
+				if isExist[kv] {
+					continue
+				}
+				isExist[kv] = true
+				keys = append(keys, kv)
+			}
+			return
+		}
+	)
+	values := redis.GetStr(code, cacheKey)
+	if values != "" {
+		keys = append(keys, duplicateRemoval(strings.Split(values, ","))...)
+	}
+	if p.KeyWords != "" {
+		keys = append(keys, duplicateRemoval(strings.Split(p.KeyWords, ","))...)
+	}
+	if p.AdditionalWords != "" {
+		keys = append(keys, duplicateRemoval(strings.Split(p.AdditionalWords, ","))...)
+	}
+	if len(keys) > 10 {
+		keys = keys[len(keys)-10:]
+	}
+	ok := redis.Put(code, cacheKey, strings.Join(keys, ","), -1)
+	if !ok {
+		logx.Info(" history keywords err:", keys)
+	}
+}
+
+var (
+	titleSuffix = "%s等"
+)
+
+// 格式化
+func (p *Purchase) PurchaseListFormat(res []map[string]interface{}) (list []*bxcore.PurchaseList) {
+	for _, rv := range res {
+		logx.Info("title:", MC.InterfaceToStr(rv["title"]))
+		id := MC.InterfaceToStr(rv["source_id"]) //拆分后 多条数据会来自一条bidding数据嘛,把bidding的id记一个source_id;mongo 库中bidding的_id
+		if id == "" {
+			continue
+		}
+		area := MC.InterfaceToStr(rv["area"])
+		city := MC.InterfaceToStr(rv["city"])
+		district := MC.InterfaceToStr(rv["district"])
+		title := MC.InterfaceToStr(rv["title"])
+		originalTitle := title
+		if len([]rune(title)) > 50 {
+			splitStr := "-"
+			titles := strings.Split(title, splitStr)
+			lastPart := ""
+			if len(titles) > 1 {
+				lastPart = titles[len(titles)-1]
+				if lastPart == city || lastPart == area || lastPart == district {
+					title = strings.Join(titles[:len(titles)-1], splitStr)
+				} else {
+					lastPart = ""
+				}
+			}
+			if len([]rune(title)) > 50 {
+				title = fmt.Sprintf(titleSuffix, string([]rune(title)[:50]))
+			}
+			if lastPart != "" {
+				title = fmt.Sprintf("%s%s%s", title, splitStr, lastPart)
+			}
+		}
+		publicType := MC.InterfaceToStr(rv["public_type"])
+		if publicType == "平台发布" && rv["purchasinglist"] != nil {
+			purchasingList := MC.ObjArrToMapArr(rv["purchasinglist"].([]interface{}))
+			if len(purchasingList) > 1 {
+				originalTitle = fmt.Sprintf(titleSuffix, originalTitle)
+			}
+		}
+		regionUrl := ""
+		if district != "" && IC.DistrictMap[district] != "" {
+			regionUrl = fmt.Sprintf(AreaLabelLink, "city", IC.DistrictMap[district])
+		} else if city != "" && IC.CityMap[city] != "" {
+			regionUrl = fmt.Sprintf(AreaLabelLink, "city", IC.CityMap[city])
+		} else if area != "" && IC.AreaMap[area] != "" {
+			regionUrl = fmt.Sprintf(AreaLabelLink, "area", IC.AreaMap[area])
+		}
+		var price int64
+		if budget, ok := rv["budget"].(float64); ok && budget > 0 { //预算
+			price = int64(budget)
+		}
+		if bidAmount, ok := rv["bidamount"].(float64); ok && bidAmount > 0 { //中标金额
+			price = int64(bidAmount)
+		}
+		//deliver_area  交付省份//deliver_city  交付城市//deliver_district  交付区县
+		deliveryLoc := fmt.Sprintf("%s%s%s", MC.InterfaceToStr(rv["deliver_area"]), MC.InterfaceToStr(rv["deliver_city"]), MC.InterfaceToStr(rv["deliver_district"]))
+		buyer := noPower
+		buyerTel := noPower
+		if p.IsPower {
+			buyer = MC.InterfaceToStr(rv["buyer"])
+			buyerTel = MC.InterfaceToStr(rv["buyertel"])
+		}
+		isValidFile, _ := rv["isValidFile"].(bool)
+		//buyerPerson := MC.InterfaceToStr(rv["buyerperson"])
+		//agency := MC.InterfaceToStr(rv["agency"])
+		//agencyTel := MC.InterfaceToStr(rv["agencytel"])
+		//agencyPerson := MC.InterfaceToStr(rv["agencyperson"])
+		//中标信息
+		var winnerInfo []*bxcore.WinnerInfo
+		winnerList := MC.ObjToString(rv["s_winner"]) //中标企业名称集合
+		if winnerList != "" && len(strings.Split(winnerList, ",")) > 0 {
+			for wk, wv := range strings.Split(winnerList, ",") {
+				var (
+					winnerId = ""
+				)
+				if rv["entidlist"] != nil {
+					if entIdList := MC.ObjArrToStringArr(rv["entidlist"].([]interface{})); len(entIdList) > wk { //中标企业id集合
+						winnerId = entIdList[wk]
+					}
+				}
+				if IC.C.SearchWinner.Switch && winnerId == "" {
+					continue
+				}
+				if entity.RegWinner.MatchString(wv) {
+					continue
+				}
+				winnerInfo = append(winnerInfo, &bxcore.WinnerInfo{
+					Winner:       wv,                                                                                                          //中标企业 需要单独处理
+					WinnerTel:    MC.ObjToString(rv["winnertel"]),                                                                             //中标企业联系电话
+					WinnerPerson: MC.ObjToString(rv["winnerperson"]),                                                                          //中标企业联系人
+					WinnerId:     MC.If(winnerId != "" && len([]rune(winnerId)) > 12, encrypt.EncodeArticleId2ByCheck(winnerId), "").(string), //中标企业加密id  存在winnerId 异常的情况
+				})
+			}
+		}
+		list = append(list, &bxcore.PurchaseList{
+			Id:            encrypt.EncodeArticleId2ByCheck(id),
+			Area:          MC.InterfaceToStr(rv["area"]),
+			City:          MC.InterfaceToStr(rv["city"]),
+			District:      MC.InterfaceToStr(rv["district"]),
+			RegionUrl:     regionUrl,
+			BuyerClass:    MC.InterfaceToStr(rv["buyerclass"]),
+			PublishTime:   MC.Int64All(rv["publishtime"]),
+			FileExists:    isValidFile,
+			Title:         title,
+			Price:         price,
+			Buyer:         buyer,
+			BuyerTel:      buyerTel,
+			SignEndTime:   MC.Int64All(rv["signendtime"]), //报名截止时间
+			DeliveryLoc:   deliveryLoc,
+			Industry:      util.IndustryFormat(p.Industry, strings.Trim(MC.ObjToString(rv["s_subscopeclass"]), ",")),
+			PublicType:    MC.InterfaceToStr(rv["public_type"]),
+			IsNew:         MC.Int64All(rv["is_yg_new"]), //is_yg_new==1 新的网站来源
+			OriginalTitle: originalTitle,
+			//BuyerPerson:  buyerPerson,
+			//Agency:       agency,
+			//AgencyTel:    agencyTel,
+			//AgencyPerson: agencyPerson,
+			//WinnerInfo:   winnerInfo,
+			//BidEndTime:   MC.Int64All(rv["bidendtime"]),
+			//BidOpenTime:  MC.Int64All(rv["bidopentime"]), //开标时间,
+		})
+	}
+	return
+}
+
+func (p *Purchase) PurchaseQuery() (query string) {
+	var (
+		wordsMusts, wordsShould, must, mustNot []string
+		selectTypeArr                          = strings.Split(p.SelectType, ",")
+		selectType                             = fmt.Sprintf(`"%s"`, strings.Join(selectTypeArr, "\",\""))
+	)
+	//发布时间
+	if len(strings.Split(p.PublishTime, "-")) > 1 {
+		var (
+			timeQuery          string
+			startTime, endTime = strings.Split(p.PublishTime, "-")[0], strings.Split(p.PublishTime, "-")[1]
+		)
+		if startTime != "" || endTime != "" {
+			timeQuery += `{"range":{"publishtime":{`
+			if startTime != "" {
+				timeQuery += `"gte":` + startTime
+			}
+			if startTime != "" && endTime != "" {
+				timeQuery += `,`
+			}
+			if endTime != "" {
+				timeQuery += `"lt":` + endTime
+			}
+			timeQuery += `}}}`
+		}
+		if timeQuery != "" {
+			must = append(must, timeQuery)
+		}
+	}
+	// 关键词
+	if p.KeyWords != "" {
+		var (
+			keyWordsMusts []string
+		)
+		for _, v := range strings.Split(p.KeyWords, IC.C.JYKeyMark) {
+			if elastic.ReplaceYH(v) == "" {
+				continue
+			}
+			keyWordsMusts = append(keyWordsMusts, fmt.Sprintf(fmt.Sprintf(es.MultiMatch, "%s", selectType), elastic.ReplaceYH(v)))
+		}
+		//搜索关键词模式;默认0:包含所有,1:包含任意
+		if p.WordsMode == 1 {
+			wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(keyWordsMusts, ",")))
+		} else {
+			wordsMusts = append(wordsMusts, keyWordsMusts...)
+		}
+	}
+	//附加词
+	if p.AdditionalWords != "" {
+		for _, aws := range strings.Split(p.AdditionalWords, ",") {
+			//多组附加词,每组间,号隔开。每组内如果关键词中间有空格,自动分词
+			var (
+				addWordsMusts []string
+			)
+			for _, v := range strings.Split(aws, IC.C.JYKeyMark) {
+				if elastic.ReplaceYH(v) == "" {
+					continue
+				}
+				addWordsStr := fmt.Sprintf(fmt.Sprintf(es.MultiMatch, "%s", selectType), elastic.ReplaceYH(v))
+				if p.WordsMode == 0 {
+					wordsMusts = append(wordsMusts, addWordsStr)
+				} else {
+					addWordsMusts = append(addWordsMusts, addWordsStr)
+				}
+			}
+			//搜索关键词模式;默认0:包含所有,1:包含任意
+			if len(addWordsMusts) > 0 {
+				wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(addWordsMusts, ",")))
+			}
+		}
+	}
+	//搜索关键词模式;默认0:包含所有,1:包含任意
+	//包含任意一组
+	if len(wordsShould) > 0 {
+		must = append(must, fmt.Sprintf(es.QueryBoolShould, strings.Join(wordsShould, ",")))
+	} else if len(wordsMusts) > 0 {
+		must = append(must, fmt.Sprintf(elastic.NgramMust, strings.Join(wordsMusts, ",")))
+	}
+	//行业
+	if p.Industry != "" {
+		must = append(must, fmt.Sprintf(es.QueryBoolMustA, "s_subscopeclass", `"`+strings.ReplaceAll(p.Industry, ",", `","`)+`"`))
+	}
+	//附件
+	if p.FileExists != 0 {
+		switch p.FileExists {
+		case 1: //有附件
+			must = append(must, fmt.Sprintf(es.QueryBoolMustTermBool, "isValidFile", true))
+		case -1: //无附件
+			mustNot = append(mustNot, fmt.Sprintf(es.QueryBoolMustTermBool, "isValidFile", true))
+		}
+	}
+	//项目地区
+	var (
+		areaQuery []string
+		areaTerms = `{"terms":{"%s":["%s"]}}`
+	)
+	if p.ProjectArea != "" {
+		areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "area", strings.ReplaceAll(p.ProjectArea, ",", "\",\"")))
+	}
+	if p.ProjectCity != "" {
+		areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "city", strings.ReplaceAll(p.ProjectCity, ",", "\",\"")))
+	}
+	if p.ProjectDistrict != "" {
+		for _, v := range strings.Split(p.ProjectDistrict, ",") {
+			if len(strings.Split(v, "_")) > 1 {
+				cityName := strings.Split(v, "_")[0]
+				districtName := strings.Split(v, "_")[1]
+				queryBoolMustAndDistrict := `{"bool":{"must":[{"terms":{"city":["%s"]}},{"terms":{"district":["%s"]}}]}}`
+				areaQuery = append(areaQuery, fmt.Sprintf(queryBoolMustAndDistrict, cityName, districtName))
+			}
+		}
+	}
+	if len(areaQuery) > 0 {
+		must = append(must, fmt.Sprintf(es.QueryBoolShould, strings.Join(areaQuery, ",")))
+	}
+	//交付地点
+	areaQuery = []string{}
+	if p.DeliveryArea != "" {
+		areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "deliver_area", strings.ReplaceAll(p.DeliveryArea, ",", "\",\"")))
+	}
+	if p.DeliveryCity != "" {
+		areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "deliver_city", strings.ReplaceAll(p.DeliveryCity, ",", "\",\"")))
+	}
+	if p.DeliveryDistrict != "" {
+		for _, v := range strings.Split(p.DeliveryDistrict, ",") {
+			if len(strings.Split(v, "_")) > 1 {
+				cityName := strings.Split(v, "_")[0]
+				districtName := strings.Split(v, "_")[1]
+				queryBoolMustAndDistrict := `{"bool":{"must":[{"terms":{"deliver_city":["%s"]}},{"terms":{"deliver_district":["%s"]}}]}}`
+				areaQuery = append(areaQuery, fmt.Sprintf(queryBoolMustAndDistrict, cityName, districtName))
+			}
+		}
+	}
+	if len(areaQuery) > 0 {
+		must = append(must, fmt.Sprintf(es.QueryBoolShould, strings.Join(areaQuery, ",")))
+	}
+	//发布方式
+	if p.Publisher > 0 {
+		must = append(must, fmt.Sprintf(es.QueryBoolMustTerm, "public_type", es.PurchasePublicType[p.Publisher-1]))
+	}
+	//截止时间
+	if p.DeadlineStart > 0 || p.DeadlineEnd > 0 {
+		var timeQuery string
+		timeQuery += `{"range":{"signendtime":{`
+		if p.DeadlineStart > 0 {
+			timeQuery += fmt.Sprintf(`"gte":%d`, p.DeadlineStart)
+		}
+		if p.DeadlineStart > 0 && p.DeadlineEnd > 0 {
+			timeQuery += `,`
+		}
+		if p.DeadlineEnd > 0 {
+			timeQuery += fmt.Sprintf(`"lt":%d`, p.DeadlineEnd)
+		}
+		timeQuery += `}}}`
+		must = append(must, timeQuery)
+	}
+	//领域
+	areaQuery = []string{}
+	if p.DomainFirstType != "" {
+		areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "domain_firsttype", strings.ReplaceAll(p.DomainFirstType, ",", "\",\"")))
+	}
+	if p.DomainSecondType != "" {
+		areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "domain_secondtype", strings.ReplaceAll(p.DomainSecondType, ",", "\",\"")))
+	}
+	if p.DomainThirdType != "" {
+		areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "domain_thirdtype", strings.ReplaceAll(p.DomainThirdType, ",", "\",\"")))
+	}
+	if len(areaQuery) > 0 {
+		must = append(must, fmt.Sprintf(es.QueryBoolShould, strings.Join(areaQuery, ",")))
+	}
+	//直采 采购信息 搜索
+	query = fmt.Sprintf(es.Query, strings.Join(must, ","), strings.Join(mustNot, ","))
+	log.Println("zc-query:", query)
+	return
+}
+
+func (p *Purchase) FindDataFromES() (int64, []map[string]interface{}, error) {
+	var (
+		start  = int((p.PageNum - 1) * p.PageSize)
+		total  int64
+		list   *[]map[string]interface{}
+		err    error
+		fields = es.PurchaseBaseFieldForPayer
+	)
+	if IC.C.PurchaseDiffSwitch {
+		if !p.IsPay {
+			fields = es.PurchaseBaseField
+		}
+	}
+	biddingSearch := es.SearchByES{
+		Index:      es.PurchaseIndex,
+		IType:      es.PurchaseType,
+		Query:      p.PurchaseQuery(),
+		FindFields: p.SelectType,
+		Order:      es.PurchaseSearchSort,
+		Fields:     fields,
+		Start:      start,
+		Limit:      int(p.PageSize),
+		Count:      0,     //高亮正文数量
+		HighLight:  false, //是否高亮正文
+	}
+	total, list = biddingSearch.GetAllByNgramWithCount(es.LoginTypePay)
+	if total == 0 || list == nil {
+		log.Println(fmt.Errorf("暂无数据"))
+		return 0, nil, nil
+	}
+	return total, *list, err
+}
+
+var (
+	redisCode             = "newother"
+	purchaseDataCacheKey  = "purchase_cache_data"
+	purchaseCountCacheKey = "purchase_cache_count"
+	purchaseCacheExpire   = 8 * 60 * 60
+)
+
+func (p *Purchase) GetPurchaseCount() (count int64) {
+	count, _, _ = p.FindDataFromES()
+	return
+}
+
+// 数据
+func (p *Purchase) GetPurchaseData() (list []*bxcore.PurchaseList, err error) {
+	var (
+		res   []map[string]interface{}
+		total int64
+	)
+	if p.IsEmptySearch() {
+		//查缓存
+		cacheBytes, err := redis.GetBytes(redisCode, purchaseDataCacheKey)
+		start := int((p.PageNum - 1) * p.PageSize)
+		end := int(p.PageNum * p.PageSize)
+		if err == nil && len(*cacheBytes) > start {
+			if end > len(*cacheBytes) {
+				end = len(*cacheBytes)
+			}
+			total = int64(redis.GetInt(redisCode, purchaseCountCacheKey))
+			err = json.Unmarshal(*cacheBytes, &res)
+		}
+		if len(res) == 0 {
+			p.PageNum = 1
+			pageSize := p.PageSize
+			start = int((p.PageNum - 1) * p.PageSize)
+			p.PageSize = int64(util.SearchPageSize * util.SearchMaxPageNum)
+			total, res, err = p.FindDataFromES()
+			if total > 0 && len(res) > 0 {
+				var b []byte
+				b, err = json.Marshal(res)
+				if err == nil && len(b) > 0 {
+					err = redis.PutBytes(redisCode, purchaseDataCacheKey, &b, purchaseCacheExpire)
+					redis.Put(redisCode, purchaseCountCacheKey, total, purchaseCacheExpire)
+				}
+				if end > len(res) {
+					end = len(res)
+				}
+			}
+			p.PageSize = pageSize
+		}
+		res = res[start:end]
+	} else {
+		//实时查询
+		total, res, err = p.FindDataFromES()
+	}
+	if len(res) > 0 {
+		p.Total = total
+		p.Count = int64(util.SearchPageSize * util.SearchMaxPageNum)
+		if p.Count > total {
+			p.Count = total
+		}
+		list = p.PurchaseListFormat(res)
+	}
+	return
+}
+
+// 关键词  附加词  行业
+func (p *Purchase) IsEmptySearch() bool {
+	if p.KeyWords != "" || p.AdditionalWords != "" || p.Industry != "" {
+		return false
+	}
+	return true
+}
+
+var (
+	purchaseSelectTypeMap = map[string]bool{
+		"title":      true,
+		"purchasing": true,
+	}
+	tipMsg = "“%s“及其后面的字词均被忽略,因为剑鱼标讯的查询限制在%d个汉字以内。"
+)
+
+// 筛选条件格式化
+func (p *Purchase) FilterCriteriaFormat() {
+	if p.UserId != "" {
+		//判断用户身份
+		userInfo := IC.Middleground.PowerCheckCenter.Check(p.AppId, p.MgoUserId, p.BaseUserId, p.AccountId, p.EntId, p.PositionType, p.PositionId)
+		if userInfo != nil {
+			p.IsPay = !userInfo.Free.IsFree
+		}
+		res := IC.Middleground.ResourceCenter.Haspowers(p.AccountId, p.EntAccountId, p.EntId, p.EntUserId)
+		if res != nil {
+			p.IsPower = strings.Contains(strings.Join(res.Powers, ","), IC.C.PurchaseCode)
+		}
+	}
+	//搜索范围
+	if p.SelectType != "" {
+		var selectTypes []string
+		for _, sv := range strings.Split(p.SelectType, ",") {
+			if purchaseSelectTypeMap[sv] {
+				selectTypes = append(selectTypes, sv)
+			}
+		}
+		if len(selectTypes) > 0 {
+			p.SelectType = strings.Join(selectTypes, ",")
+		}
+	}
+	if p.SelectType == "" {
+		p.SelectType = "title"
+	}
+	// p.SearchMode 搜索模式:0:精准搜索;1:模糊搜索
+	// 精准搜索:不分词,完全匹配;(中间带空格的关键词组自动分词)
+	// 模糊搜索:对用户输入的单个关键词进行分词处理,但必须都存在;
+	if p.SearchMode < 0 || p.SearchMode > 1 {
+		p.SearchMode = 0
+	}
+	// p.WordsMode 搜索关键词模式;默认0:包含所有,1:包含任意
+	if p.WordsMode < 0 || p.WordsMode > 1 {
+		p.WordsMode = 0
+	}
+	//发布时间--默认最近一年
+	if p.PublishTime == "" {
+		p.PublishTime = fmt.Sprintf("%d-%d", time.Now().AddDate(-1, 0, 0).Unix(), time.Now().Unix())
+	}
+
+	//默认每页数据量
+	if p.PageSize <= 0 || p.PageSize > 100 {
+		p.PageSize = 50
+	}
+	//第一页
+	if p.PageNum <= 0 || p.PageNum > int64(IC.C.DefaultBidInfo.Count)/p.PageSize {
+		p.PageNum = 1
+	}
+	//行业
+	if p.Industry != "" {
+		p.Industry = strings.TrimSpace(p.Industry)
+		//P510 行业:其它
+		if qt := jy.IndustryHandle(p.Industry); len(qt) > 0 {
+			p.Industry = fmt.Sprintf("%s,%s", p.Industry, strings.Join(qt, ","))
+		}
+	}
+	var (
+		searchWords []string
+	)
+	//关键词
+	if p.KeyWords != "" {
+		p.KeyWords = strings.TrimSpace(p.KeyWords)
+		p.InterceptKeyWords, p.TipMsg, p.KeyWords = util.InterceptSearchKW(p.KeyWords, MC.IntAllDef(IC.C.KeywordsLimit, 35), true)
+		//if p.TipMsg != "" {
+		//	p.TipMsg = fmt.Sprintf(tipMsg, p.TipMsg, MC.IntAllDef(IC.C.KeywordsLimit, 35))
+		//}
+		// in.SearchMode 搜索模式:0:精准搜索;1:模糊搜索
+		// 精准搜索:不分词,完全匹配;(中间带空格的关键词组自动分词)
+		// 模糊搜索:对用户输入的单个关键词进行分词处理,但必须都存在;
+		//主关键词词组
+		if p.SearchMode == 1 {
+			if ikWords := util.HttpEs(p.KeyWords, "ik_smart", IC.DB.Es.Addr); ikWords != "" {
+				p.KeyWords = jy.KeywordsProcessing(ikWords, IC.C.JYKeyMark)
+			}
+		}
+		searchWords = append(searchWords, p.KeyWords)
+	}
+	//附加词 每组附加词不能超过15个字符
+	if p.AdditionalWords != "" {
+		var additionalWords []string
+		for _, ak := range strings.Split(p.AdditionalWords, ",") {
+			if len([]rune(ak)) > 15 {
+				additionalWords = append(additionalWords, string([]rune(ak)[:15]))
+			} else {
+				additionalWords = append(additionalWords, ak)
+			}
+		}
+		p.AdditionalWords = strings.Join(additionalWords, ",") //分组不变
+		//多组附加词,每组间,号隔开。每组内如果关键词中间有空格,自动分词
+		if p.SearchMode == 1 {
+			var (
+				addWords []string
+			)
+			for _, awv := range strings.Split(p.AdditionalWords, ",") {
+				if strings.TrimSpace(awv) != "" {
+					if ikWords := util.HttpEs(awv, "ik_smart", IC.DB.Es.Addr); ikWords != "" {
+						addWords = append(addWords, jy.KeywordsProcessing(ikWords, IC.C.JYKeyMark))
+					}
+				}
+			}
+			if len(addWords) > 0 {
+				p.AdditionalWords = strings.Join(addWords, ",")
+			}
+		}
+		searchWords = append(searchWords, strings.Split(p.AdditionalWords, ",")...)
+	}
+	p.HighlightWords = strings.Join(searchWords, " ")
+	//报名截止
+	if p.DeadlineStatus < 0 || p.DeadlineStatus > 2 {
+		p.DeadlineStatus = 0
+	}
+	if len(strings.Split(p.DeadlineTime, "-")) > 1 {
+		p.DeadlineStart, _ = strconv.ParseInt(strings.Split(p.DeadlineTime, "-")[0], 10, 64)
+		p.DeadlineEnd, _ = strconv.ParseInt(strings.Split(p.DeadlineTime, "-")[1], 10, 64)
+		if p.DeadlineEnd < p.DeadlineStart {
+			var deadline = p.DeadlineStart
+			p.DeadlineStart = p.DeadlineEnd
+			p.DeadlineEnd = deadline
+		}
+	}
+	switch p.DeadlineStatus {
+	case 1: //未截止
+		if p.DeadlineEnd < time.Now().Unix() {
+			p.DeadlineStart = time.Now().Unix()
+			p.DeadlineEnd = 0
+		}
+	case 2: //已截止
+		if p.DeadlineEnd == 0 || p.DeadlineEnd > time.Now().Unix() {
+			p.DeadlineStart = 0
+			p.DeadlineEnd = time.Now().Unix()
+		}
+	}
+	//发布平台
+	if p.Publisher < 0 || p.Publisher > int64(len(es.PurchasePublicType)) {
+		p.Publisher = 0
+	}
+	//空搜索 其它筛选条件 无效
+	if p.IsEmptySearch() {
+		//
+		p.DomainFirstType = ""
+		p.DomainSecondType = ""
+		p.DomainThirdType = ""
+		p.DeadlineStatus = 0
+		p.DeadlineStart = 0
+		p.DeadlineEnd = 0
+		p.DeliveryArea = ""
+		p.DeliveryCity = ""
+		p.DeliveryDistrict = ""
+		p.ProjectArea = ""
+		p.ProjectCity = ""
+		p.ProjectDistrict = ""
+		p.FileExists = 0
+		p.Publisher = 0
+	}
+}

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 1112 - 78
jyBXCore/rpc/type/bxcore/bxcore.pb.go


+ 77 - 1
jyBXCore/rpc/type/bxcore/bxcore_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.19.4
+// - protoc             v3.15.5
 // source: bxcore.proto
 
 package bxcore
@@ -52,6 +52,10 @@ type BxCoreClient interface {
 	PolymerizeSearch(ctx context.Context, in *PolymerizeSearchReq, opts ...grpc.CallOption) (*PolymerizeSearchResp, error)
 	ProjectDetails(ctx context.Context, in *ProjectDetailsReq, opts ...grpc.CallOption) (*DetailDataRes, error)
 	PropertySearchCriteria(ctx context.Context, in *SearchReq, opts ...grpc.CallOption) (*SearchCriteriaRes, error)
+	//热搜词
+	SearchHotKey(ctx context.Context, in *HotKeysReq, opts ...grpc.CallOption) (*HotKeysRes, error)
+	//采购信息搜索
+	PurchaseSearch(ctx context.Context, in *PurchaseReq, opts ...grpc.CallOption) (*PurchaseResp, error)
 }
 
 type bxCoreClient struct {
@@ -206,6 +210,24 @@ func (c *bxCoreClient) PropertySearchCriteria(ctx context.Context, in *SearchReq
 	return out, nil
 }
 
+func (c *bxCoreClient) SearchHotKey(ctx context.Context, in *HotKeysReq, opts ...grpc.CallOption) (*HotKeysRes, error) {
+	out := new(HotKeysRes)
+	err := c.cc.Invoke(ctx, "/bxcore.BxCore/SearchHotKey", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *bxCoreClient) PurchaseSearch(ctx context.Context, in *PurchaseReq, opts ...grpc.CallOption) (*PurchaseResp, error) {
+	out := new(PurchaseResp)
+	err := c.cc.Invoke(ctx, "/bxcore.BxCore/PurchaseSearch", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 // BxCoreServer is the server API for BxCore service.
 // All implementations must embed UnimplementedBxCoreServer
 // for forward compatibility
@@ -240,6 +262,10 @@ type BxCoreServer interface {
 	PolymerizeSearch(context.Context, *PolymerizeSearchReq) (*PolymerizeSearchResp, error)
 	ProjectDetails(context.Context, *ProjectDetailsReq) (*DetailDataRes, error)
 	PropertySearchCriteria(context.Context, *SearchReq) (*SearchCriteriaRes, error)
+	//热搜词
+	SearchHotKey(context.Context, *HotKeysReq) (*HotKeysRes, error)
+	//采购信息搜索
+	PurchaseSearch(context.Context, *PurchaseReq) (*PurchaseResp, error)
 	mustEmbedUnimplementedBxCoreServer()
 }
 
@@ -295,6 +321,12 @@ func (UnimplementedBxCoreServer) ProjectDetails(context.Context, *ProjectDetails
 func (UnimplementedBxCoreServer) PropertySearchCriteria(context.Context, *SearchReq) (*SearchCriteriaRes, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method PropertySearchCriteria not implemented")
 }
+func (UnimplementedBxCoreServer) SearchHotKey(context.Context, *HotKeysReq) (*HotKeysRes, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SearchHotKey not implemented")
+}
+func (UnimplementedBxCoreServer) PurchaseSearch(context.Context, *PurchaseReq) (*PurchaseResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method PurchaseSearch not implemented")
+}
 func (UnimplementedBxCoreServer) mustEmbedUnimplementedBxCoreServer() {}
 
 // UnsafeBxCoreServer may be embedded to opt out of forward compatibility for this service.
@@ -596,6 +628,42 @@ func _BxCore_PropertySearchCriteria_Handler(srv interface{}, ctx context.Context
 	return interceptor(ctx, in, info, handler)
 }
 
+func _BxCore_SearchHotKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(HotKeysReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(BxCoreServer).SearchHotKey(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/bxcore.BxCore/SearchHotKey",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(BxCoreServer).SearchHotKey(ctx, req.(*HotKeysReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _BxCore_PurchaseSearch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(PurchaseReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(BxCoreServer).PurchaseSearch(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/bxcore.BxCore/PurchaseSearch",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(BxCoreServer).PurchaseSearch(ctx, req.(*PurchaseReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 // BxCore_ServiceDesc is the grpc.ServiceDesc for BxCore service.
 // It's only intended for direct use with grpc.RegisterService,
 // and not to be introspected or modified (even as a copy)
@@ -667,6 +735,14 @@ var BxCore_ServiceDesc = grpc.ServiceDesc{
 			MethodName: "PropertySearchCriteria",
 			Handler:    _BxCore_PropertySearchCriteria_Handler,
 		},
+		{
+			MethodName: "SearchHotKey",
+			Handler:    _BxCore_SearchHotKey_Handler,
+		},
+		{
+			MethodName: "PurchaseSearch",
+			Handler:    _BxCore_PurchaseSearch_Handler,
+		},
 	},
 	Streams:  []grpc.StreamDesc{},
 	Metadata: "bxcore.proto",

+ 9 - 11
jyBXCore/rpc/util/limitSearchText.go

@@ -142,14 +142,12 @@ func CheckLimit(userType int, userIdent string, isNew bool) (state int64, msg st
 	}
 	//同一用户 -- 请求频次 在IC.C.LimitSearchText.TimeOut内 不允许多次请求
 	if IC.C.LimitSearchText.TimeOut > 0 {
-		if isNew {
-			if limitCount <= IC.C.LimitSearchText.Count/2 {
-				timeLimit, _ := redis.Exists("other", fmt.Sprintf(IC.C.LimitSearchText.LimitKey, userIdent))
-				if timeLimit {
-					state = -1
-					msg = fmt.Sprintf("当前用户:%s \n招投标筛选在%d秒内请求频次过多,\n并发通道-\n总数:%d,\n未使用数量:%d", userIdent, IC.C.LimitSearchText.TimeOut, IC.C.LimitSearchText.Count, limitCount)
-					return
-				}
+		if isNew && limitCount <= IC.C.LimitSearchText.Count/2 {
+			timeLimit, _ := redis.Exists("other", fmt.Sprintf(IC.C.LimitSearchText.LimitKey, userIdent))
+			if timeLimit {
+				state = -1
+				msg = fmt.Sprintf("当前用户:%s \n招投标筛选在%d秒内请求频次过多,\n并发通道-\n总数:%d,\n未使用数量:%d", userIdent, IC.C.LimitSearchText.TimeOut, IC.C.LimitSearchText.Count, limitCount)
+				return
 			}
 		}
 		redis.Put("other", fmt.Sprintf(IC.C.LimitSearchText.LimitKey, userIdent), 1, IC.C.LimitSearchText.TimeOut)
@@ -173,7 +171,7 @@ func CheckLimit(userType int, userIdent string, isNew bool) (state int64, msg st
 					msg = ""
 				} else {
 					state = -1
-					msg = fmt.Sprintf("%s,\n总并发量的百分之%d", msg, IC.C.LimitSearchText.Percentage)
+					msg = fmt.Sprintf("%s,\n总并发量的百分之%d", msg, IC.C.LimitSearchText.Percentage)
 				}
 			case 3:
 				quota := limitCount * IC.C.LimitSearchText.NoLogin / 100
@@ -182,7 +180,7 @@ func CheckLimit(userType int, userIdent string, isNew bool) (state int64, msg st
 					msg = ""
 				} else {
 					state = -1
-					msg = fmt.Sprintf("%s,\n总并发量的百分之%d", msg, IC.C.LimitSearchText.NoLogin)
+					msg = fmt.Sprintf("%s,\n总并发量的百分之%d", msg, IC.C.LimitSearchText.NoLogin)
 				}
 			}
 		}
@@ -193,7 +191,7 @@ func CheckLimit(userType int, userIdent string, isNew bool) (state int64, msg st
 		state = -2
 	}
 	if msg != "" {
-		msg = fmt.Sprintf("%s,\n并发通道总数:%d,\n未使用数量:%d", msg, IC.C.LimitSearchText.Count, limitCount)
+		msg = fmt.Sprintf("%s,\n并发通道-\n总数:%d,\n未使用数量:%d", msg, IC.C.LimitSearchText.Count, limitCount)
 	}
 	return
 }

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно