Ver Fonte

wip:直采 采购信息搜索

wangshan há 9 meses atrás
pai
commit
bd2e94838f

+ 51 - 1
jyBXCore/api/bxcore.api

@@ -8,6 +8,7 @@ info(
 )
 
 type (
+	commonReq struct{}
 	searchReq {
 		UserType        string   `path:"userType,optional"`
 		AppId           string   `header:"appId"`
@@ -259,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"`
+		EntUserId        int64  `header:"entUserId,optional"`
+		AccountId        string `header:"accountId,optional"`      //账户id
+		EntAccountId     int64  `header:"entAccountId,optional"`   //企业账户id
+		PositionType     string `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"`            //报名截止状态
+		DeadlineTime     string `json:"deadlineTime"`              //报名截止时间
+		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)
 }

+ 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"),
+	)
 }

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

@@ -0,0 +1,75 @@
+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,
+	}
+}
+
+func (l *PurchaseSearchLogic) PurchaseSearch(req *types.PurSearchReq) (resp *types.CommonResp, err error) {
+	defer common.Catch()
+	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:     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
+}

+ 39 - 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"`
@@ -222,3 +225,39 @@ type MobileHotWordReq struct {
 	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"`
+	EntUserId        int64  `header:"entUserId,optional"`
+	AccountId        string `header:"accountId,optional"`      //账户id
+	EntAccountId     int64  `header:"entAccountId,optional"`   //企业账户id
+	PositionType     string `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"`            //报名截止状态
+	DeadlineTime     string `json:"deadlineTime"`              //报名截止时间
+	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:包含任意
+}

+ 74 - 0
jyBXCore/rpc/bxcore.proto

@@ -640,6 +640,78 @@ 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
+  string 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;//搜索列表
+}
+
+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 deadlineTime = 13;//报名截止时间-展示年月日时分,例如:2024-10-01 10:00
+  string deliveryLoc = 14;//交付地点
+  string industry = 15;//行业标签
+}
+//
 service BxCore {
   //标讯搜索结果列表数据
   rpc GetSearchList(SearchReq) returns(SearchResp);
@@ -673,4 +745,6 @@ service BxCore {
   rpc PropertySearchCriteria(SearchReq) returns (SearchCriteriaRes);
   //热搜词
   rpc SearchHotKey(HotKeysReq)returns(HotKeysRes);
+  //采购信息搜索
+  rpc PurchaseSearch(PurchaseReq)returns(PurchaseResp);
 }

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

@@ -51,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
@@ -106,6 +110,8 @@ type (
 		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 {
@@ -218,3 +224,9 @@ func (m *defaultBxCore) SearchHotKey(ctx context.Context, in *HotKeysReq, opts .
 	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...)
+}

+ 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)

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

@@ -0,0 +1,62 @@
+package logic
+
+import (
+	IC "bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/init"
+	"bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/service"
+	"context"
+	"fmt"
+	"log"
+
+	"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 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) {
+	if IC.C.NoLoginSearch.Switch {
+		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 {
+			return &bxcore.PurchaseResp{}, fmt.Errorf("暂无数据")
+		}
+	}
+	var (
+		res = &bxcore.PurchaseResp{}
+	)
+	ps := service.NewPurchase(in)
+	ps.FilterCriteriaFormat()
+	list, err := ps.GetPurchaseData()
+	if err == nil && len(list) > 0 {
+		res.Data.List = list
+	}
+	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
+	return res, err
+}

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

@@ -121,3 +121,9 @@ func (s *BxCoreServer) SearchHotKey(ctx context.Context, in *bxcore.HotKeysReq)
 	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)
+}

+ 9 - 4
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]}}`
+	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}}`
+	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,10 @@ const (
 	LoginTypePay     = 1            // 付费用户
 	LoginTypeFree    = 2            // 免费用户
 	LoginTypeNoLogin = 3            // 未登录用户
+	//直采-采购信息
+	PurchaseIndex, PurchaseType = "bidding_yg", "bidding_yg"
+	PurchaseBaseField           = `"_id","title"`
+	PurchaseSearchSort          = `{"dataweight":-1,"publishtime":-1}`
 )
 
 var (

+ 20 - 21
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" { // 如果是领域化数据则需要加标签
@@ -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

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

@@ -0,0 +1,532 @@
+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"
+	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"
+	"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"`                       //数据总量
+}
+
+func NewPurchase(in *bxcore.PurchaseReq) *Purchase {
+	baseUserId, _ := strconv.ParseInt(in.NewUserId, 10, 64)
+	accountId, _ := strconv.ParseInt(in.AccountId, 10, 64)
+	positionType, _ := strconv.ParseInt(in.PositionType, 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:     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,
+	}
+}
+
+// 格式化
+func (p *Purchase) PurchaseListFormat(res *[]map[string]interface{}) (list []*bxcore.PurchaseList) {
+	for _, rv := range *res {
+		id := MC.InterfaceToStr(rv["id"])
+		list = append(list, &bxcore.PurchaseList{
+			Id:           encrypt.EncodeArticleId2ByCheck(id),
+			Area:         "",
+			City:         "",
+			District:     "",
+			RegionUrl:    "",
+			BuyerClass:   "",
+			PublishTime:  0,
+			FileExists:   false,
+			Title:        "",
+			Price:        0,
+			Buyer:        "",
+			BuyerTel:     "",
+			DeadlineTime: "",
+			DeliveryLoc:  "",
+			Industry:     "",
+		})
+	}
+	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.ProjectArea, ",", "\",\"")))
+	}
+	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", fmt.Sprintf("%d", p.Publisher)))
+	}
+	//截止时间
+	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 += `}}}`
+	}
+	//领域
+	areaQuery = []string{}
+	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(query, strings.Join(must, ","), strings.Join(mustNot, ","))
+	log.Println("zc-query:", query)
+	return
+}
+
+func (p *Purchase) FindDataFromES() (total int64, list *[]map[string]interface{}, err error) {
+	var (
+		start = int((p.PageNum - 1) * p.PageSize)
+	)
+	biddingSearch := es.SearchByES{
+		Index:      es.PurchaseIndex,
+		IType:      es.PurchaseType,
+		Query:      p.PurchaseQuery(),
+		FindFields: p.SelectType,
+		Order:      es.PurchaseSearchSort,
+		Fields:     es.PurchaseBaseField,
+		Start:      start,
+		Limit:      int(p.PageSize),
+		Count:      0,     //高亮正文数量
+		HighLight:  false, //是否高亮正文
+	}
+	total, list = biddingSearch.GetAllByNgramWithCount(es.LoginTypePay)
+	fmt.Println(total, "-------------------", *list)
+	p.Total = total
+	total = int64(util.SearchPageSize * util.SearchMaxPageNum)
+	if p.Total > total {
+		p.Total = total
+	}
+	return
+}
+
+var (
+	redisCode           = "newother"
+	purchaseCacheKey    = "purchase_cache_data"
+	purchaseCacheExpire = 4 * 60 * 60
+)
+
+func (p *Purchase) GetPurchaseData() (list []*bxcore.PurchaseList, err error) {
+	var (
+		res *[]map[string]interface{}
+	)
+	if p.IsEmptySearch() {
+		//查缓存
+		cacheBytes, err := redis.GetBytes(redisCode, purchaseCacheKey)
+		start := int((p.PageNum - 1) * p.PageSize)
+		pageSize := p.PageSize
+		if err == nil && len(*cacheBytes) > start {
+			end := int(p.PageNum * p.PageSize)
+			if end > len(*cacheBytes) {
+				end = len(*cacheBytes)
+			}
+			err = json.Unmarshal((*cacheBytes)[start:end], res)
+		}
+		if len(*res) == 0 {
+			p.PageNum = 1
+			p.PageSize = int64(util.SearchPageSize * util.SearchMaxPageNum)
+			_, res, err = p.FindDataFromES()
+			*cacheBytes, err = json.Marshal(res)
+			if err == nil && len(*cacheBytes) > 0 {
+				err = redis.PutBytes(redisCode, purchaseCacheKey, cacheBytes, purchaseCacheExpire)
+			}
+		}
+		*res = (*res)[start:pageSize]
+	} else {
+		//实时查询
+		//未登录查询 限制并发数
+		_, res, err = p.FindDataFromES()
+	}
+	if len(*res) > 0 {
+		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.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.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 > time.Now().Unix() {
+			p.DeadlineStart = 0
+			p.DeadlineEnd = time.Now().Unix()
+		}
+	}
+	//空搜索 其它筛选条件 无效
+	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
+	}
+}

Diff do ficheiro suprimidas por serem muito extensas
+ 879 - 121
jyBXCore/rpc/type/bxcore/bxcore.pb.go


+ 38 - 0
jyBXCore/rpc/type/bxcore/bxcore_grpc.pb.go

@@ -54,6 +54,8 @@ type BxCoreClient interface {
 	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 {
@@ -217,6 +219,15 @@ func (c *bxCoreClient) SearchHotKey(ctx context.Context, in *HotKeysReq, opts ..
 	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
@@ -253,6 +264,8 @@ type BxCoreServer interface {
 	PropertySearchCriteria(context.Context, *SearchReq) (*SearchCriteriaRes, error)
 	//热搜词
 	SearchHotKey(context.Context, *HotKeysReq) (*HotKeysRes, error)
+	//采购信息搜索
+	PurchaseSearch(context.Context, *PurchaseReq) (*PurchaseResp, error)
 	mustEmbedUnimplementedBxCoreServer()
 }
 
@@ -311,6 +324,9 @@ func (UnimplementedBxCoreServer) PropertySearchCriteria(context.Context, *Search
 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.
@@ -630,6 +646,24 @@ func _BxCore_SearchHotKey_Handler(srv interface{}, ctx context.Context, dec func
 	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)
@@ -705,6 +739,10 @@ var BxCore_ServiceDesc = grpc.ServiceDesc{
 			MethodName: "SearchHotKey",
 			Handler:    _BxCore_SearchHotKey_Handler,
 		},
+		{
+			MethodName: "PurchaseSearch",
+			Handler:    _BxCore_PurchaseSearch_Handler,
+		},
 	},
 	Streams:  []grpc.StreamDesc{},
 	Metadata: "bxcore.proto",

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff