Procházet zdrojové kódy

Merge branch 'master' of https://app.yhyue.com/moapp/jypkg into master

zhangxinlei1996 před 2 roky
rodič
revize
78393c1df8

+ 185 - 82
common/src/qfw/util/dataexport/dataexport.go

@@ -22,6 +22,18 @@ import (
 	"app.yhyue.com/moapp/jypkg/common/src/qfw/util/jy"
 )
 
+const (
+	SearchModeAccurate        = 0 // 搜索模式:0:精准搜索;
+	SearchModeFuzzy           = 1 // 搜索模式:1:模糊搜索
+	WordsModeAnd              = 0 // 搜索关键词模式;默认0:包含所有
+	WordsModeOr               = 1 // 搜索关键词模式;1:包含任意
+	SearchGroupAll            = 0 // 搜索分组:默认0:全部;
+	SearchGroupBidding        = 1 // 搜索分组:1:招标采购公告;2:超前项目
+	SearchGroupLeadingProject = 2 // 搜索分组:1:招标采购公告;2:超前项目
+	TopTypesBidding           = "招标预告,招标公告,招标结果,招标信用信息"
+	TopTypesLeadingProject    = "拟建项目,采购意向"
+)
+
 /*筛选条件--关键词*/
 type KeyWord struct {
 	Keyword  string   `json:"keyword"`  //关键词
@@ -55,6 +67,9 @@ type SieveCondition struct {
 	FileExists       string    `json:"fileExists"`       //是否有附件
 	SearchTypeSwitch bool      `json:"searchTypeSwitch"` //是否开启 正文 标题同时搜索只搜正文的开关
 	BidField         string    `json:"bid_field"`        // 领域化数据 0101-医疗行业
+	SearchGroup      int       `json:"searchGroup"`      // 搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+	SearchMode       int       `json:"searchMode"`       // 搜索模式:0:精准搜索;1:模糊搜索
+	WordsMode        int       `json:"wordsMode"`        // 搜索关键词模式;默认0:包含所有,1:包含任意
 }
 
 const (
@@ -99,12 +114,14 @@ func getDataExportSql(scd *SieveCondition) string {
 	query := `{"query":{"bool":{"must":[%s],"must_not":[%s],"should":[%s],"minimum_should_match": %d}}}`
 	//query := `{"query": {"function_score": {"query": {"bool": {"must": [%s],"must_not": [%s],"should": [%s],"minimum_should_match": %d}},"field_value_factor": {"field": "dataweight","modifier": "ln1p","missing": 0}}}}`
 	query_bool_should := `{"bool":{"should":[%s],"minimum_should_match": 1}}`
+	query_bool_should_and := `{"bool":{"should":[%s],"minimum_should_match": 1 %s}}`
 	query_price := `{"bool":{"must":[{"range":{"bidamount":{%s}}}]}},{"bool":{"must":[{"range":{"budget":{%s}}}],"must_not":[{"range":{"bidamount":{"gte":-1}}}]}}`
 	query_bool_must := `{"terms":{"%s":[%s]}}`
 	query_bool_must_and := `{"bool":{"must":[%s]%s}}`
 	query_missing := `{"constant_score":{"filter":{"missing":{"field":"%s"}}}}`
 	query_bool_must_term := `{"bool": {"must": [{ "term": {"isValidFile": %d }}]}}`
 	query_bool_must_term_bidField := `{"bool": {"must": [{ "term": {"bid_field": "%s" }}]}}` // 领域化数据类型
+
 	gte := `"gte": %s`
 	lte := `"lte": %s`
 
@@ -176,12 +193,17 @@ func getDataExportSql(scd *SieveCondition) string {
 	}
 	timequery += `}}}`
 	musts = append(musts, timequery)
-
+	if scd.Subtype == "" {
+		if scd.SearchGroup == SearchGroupBidding { // 搜索分组处理  招标采购公告 超前项目
+			scd.Subtype = TopTypesBidding
+		} else if scd.SearchGroup == SearchGroupLeadingProject {
+			scd.Subtype = TopTypesLeadingProject
+		}
+	}
 	if scd.Subtype != "" {
 		var subquery string
 		var topTypes []string
 		var subTypes []string
-
 		for _, v := range strings.Split(scd.Subtype, ",") {
 			if v1, ok := topType[v]; ok {
 				topTypes = append(topTypes, fmt.Sprintf(`"%s"`, v1))
@@ -284,27 +306,34 @@ func getDataExportSql(scd *SieveCondition) string {
 		for _, v := range scd.Keyword {
 			shoulds := []string{}
 			must_not := []string{}
+			keysShoulds := []string{}
 			if v.Keyword != "" {
 				if strings.Contains(v.Keyword, "+") {
 					for _, vk := range strings.Split(v.Keyword, "+") {
+						if len(vk) == 0 {
+							continue
+						}
 						//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
 						if scd.Comeinfrom == "supersearchPage" && DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(vk))) == 1 {
 							queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
 							shouldsKey := fmt.Sprintf(multi_match, "\""+vk+"\"", "\""+queryItem+"\"")
-							shoulds = append(shoulds, shouldsKey)
+							keysShoulds = append(keysShoulds, shouldsKey)
 						} else {
-							shoulds = append(shoulds, fmt.Sprintf(multi_match_new, "\""+vk+"\""))
+							keysShoulds = append(keysShoulds, fmt.Sprintf(multi_match_new, "\""+vk+"\""))
 						}
 					}
 				} else if strings.Contains(v.Keyword, " ") {
 					for _, vk := range strings.Split(v.Keyword, " ") {
+						if len(vk) == 0 {
+							continue
+						}
 						//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
 						if scd.Comeinfrom == "supersearchPage" && DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(vk))) == 1 {
 							queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
 							shouldsKey := fmt.Sprintf(multi_match, "\""+vk+"\"", "\""+queryItem+"\"")
-							shoulds = append(shoulds, shouldsKey)
+							keysShoulds = append(keysShoulds, shouldsKey)
 						} else {
-							shoulds = append(shoulds, fmt.Sprintf(multi_match_new, "\""+vk+"\""))
+							keysShoulds = append(keysShoulds, fmt.Sprintf(multi_match_new, "\""+vk+"\""))
 						}
 					}
 				} else {
@@ -312,28 +341,76 @@ func getDataExportSql(scd *SieveCondition) string {
 					if scd.Comeinfrom == "supersearchPage" && DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(v.Keyword))) == 1 {
 						queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
 						shouldsKey := fmt.Sprintf(multi_match, "\""+v.Keyword+"\"", "\""+queryItem+"\"")
-						shoulds = append(shoulds, shouldsKey)
+						keysShoulds = append(keysShoulds, shouldsKey)
 					} else {
-						shoulds = append(shoulds, fmt.Sprintf(multi_match_new, "\""+v.Keyword+"\""))
+						keysShoulds = append(keysShoulds, fmt.Sprintf(multi_match_new, "\""+v.Keyword+"\""))
 					}
 				}
+				// 单个关键词分词后都包含
+				shoulds = append(shoulds, fmt.Sprintf(query_bool_must_and, strings.Join(keysShoulds, ","), ""))
 			}
 
 			//附加词
 			for _, vv := range v.Appended {
-				shoulds = append(shoulds, fmt.Sprintf(multi_match_new, "\""+vv+"\""))
-			}
+				appendedShoulds := []string{}
+				if vv != "" {
+					// 附加词处理分词
+					if strings.Contains(vv, "+") {
+						for _, vk := range strings.Split(vv, "+") {
+							if len(vk) == 0 {
+								continue
+							}
+							//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
+							if scd.Comeinfrom == "supersearchPage" && DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(vk))) == 1 {
+								queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
+								shouldsKey := fmt.Sprintf(multi_match, "\""+vk+"\"", "\""+queryItem+"\"")
+								appendedShoulds = append(appendedShoulds, shouldsKey)
+							} else {
+								appendedShoulds = append(appendedShoulds, fmt.Sprintf(multi_match_new, "\""+vk+"\""))
+							}
+						}
+					} else if strings.Contains(vv, " ") {
+						for _, vk := range strings.Split(vv, " ") {
+							if len(vk) == 0 {
+								continue
+							}
 
+							//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
+							if scd.Comeinfrom == "supersearchPage" && DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(vk))) == 1 {
+								queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
+								shouldsKey := fmt.Sprintf(multi_match, "\""+vk+"\"", "\""+queryItem+"\"")
+								appendedShoulds = append(appendedShoulds, shouldsKey)
+							} else {
+								appendedShoulds = append(appendedShoulds, fmt.Sprintf(multi_match_new, "\""+vk+"\""))
+							}
+						}
+					} else {
+						appendedShoulds = append(appendedShoulds, fmt.Sprintf(multi_match_new, "\""+vv+"\""))
+
+					}
+					// 单个关键词分词后都包含
+					shoulds = append(shoulds, fmt.Sprintf(query_bool_must_and, strings.Join(appendedShoulds, ","), ""))
+				}
+			}
 			//排除词
 			for _, vv := range v.Exclude {
-				//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
-				if scd.Comeinfrom == "supersearchPage" && DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(vv))) == 1 {
-					queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
-					shouldsKey := fmt.Sprintf(multi_match, "\""+vv+"\"", "\""+queryItem+"\"")
-					shoulds = append(shoulds, shouldsKey)
-				} else {
-					must_not = append(must_not, fmt.Sprintf(multi_match_new, "\""+vv+"\""))
+				if len(strings.TrimSpace(vv)) == 0 {
+					continue
+				} // 处理每组里面的空格分词
+				for _, notKeySplit := range strings.Split(vv, " ") {
+					if len(notKeySplit) == 0 {
+						continue
+					}
+					//单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail  搜索的时候加上标题
+					if scd.Comeinfrom == "supersearchPage" && DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(notKeySplit))) == 1 {
+						queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
+						shouldsKey := fmt.Sprintf(multi_match, "\""+notKeySplit+"\"", "\""+queryItem+"\"")
+						must_not = append(must_not, shouldsKey)
+					} else {
+						must_not = append(must_not, fmt.Sprintf(multi_match_new, "\""+notKeySplit+"\""))
+					}
 				}
+
 			}
 
 			//添加
@@ -342,7 +419,11 @@ func getDataExportSql(scd *SieveCondition) string {
 				if len(must_not) > 0 {
 					notStr = fmt.Sprintf(`,"must_not":[%s]`, strings.Join(must_not, ","))
 				}
-				bools = append(bools, fmt.Sprintf(query_bool_must_and, strings.Join(shoulds, ","), notStr))
+				if scd.WordsMode == WordsModeOr { // 包含任意
+					bools = append(bools, fmt.Sprintf(query_bool_should_and, strings.Join(shoulds, ","), notStr))
+				} else {
+					bools = append(bools, fmt.Sprintf(query_bool_must_and, strings.Join(shoulds, ","), notStr))
+				}
 			}
 		}
 	}
@@ -374,9 +455,7 @@ func getDataExportSql(scd *SieveCondition) string {
 	}
 	// 如果是领域化数据则需要加标签
 	if scd.BidField != "" {
-
 		musts = append(musts, fmt.Sprintf(query_bool_must_term_bidField, scd.BidField))
-
 	}
 	qstr := fmt.Sprintf(query, strings.Join(musts, ","), strings.Join(must_not, ","), strings.Join(bools, ","), boolsNum)
 	return qstr
@@ -415,6 +494,9 @@ func GetSqlObjFromId(mongo mg.MongodbSim, _id string) *SieveCondition {
 		FileExists:       qutil.ObjToString((*query)["fileExists"]),
 		SearchTypeSwitch: searchTypeSwitch,
 		BidField:         qutil.ObjToString((*query)["bid_field"]), // 领域化数据
+		SearchGroup:      qutil.IntAll((*query)["searchGroup"]),    //搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+		SearchMode:       qutil.IntAll((*query)["searchMode"]),     // 搜索模式:0:精准搜索;1:模糊搜索
+		WordsMode:        qutil.IntAll((*query)["wordsMode"]),      // 搜索关键词模式;默认0:包含所有,1:包含任意
 	}
 }
 
@@ -430,41 +512,46 @@ func GetDataExportSearchCountByScdId(sim, bid mg.MongodbSim, biddingName, elasti
 }
 
 func GetDataExportSearchCountBySieveCondition(scd *SieveCondition, elasticAddress string) (count int) {
-	qstr := getDataExportSql(scd)
 	if isNullSearch(scd) {
 		return -1 //程序端返回最大值
 	}
-	log.Printf("GetDataExportSearchCountUseId-%s-sql:%s\n", scd.Id, qstr)
-	count = int(elastic.Count(INDEX, TYPE, qstr))
+	if scd.SearchMode == SearchModeAccurate {
+		qstr := getDataExportSql(scd)
+		log.Printf("GetDataExportSearchCountUseId-%s-sql:%s\n", scd.Id, qstr)
+		count = int(elastic.Count(INDEX, TYPE, qstr))
+	}
+	// 依据用户选择的搜索模式和搜索范围进行匹配,即不限制只能匹配标题,且不限制最多展示100条、针对输入的单个关键词分词后需要都包含
 	//超级搜索一致的检索(防止数据导出和超级搜索数据量不一致)
-	if scd.Comeinfrom == "supersearchPage" && (len(scd.Keyword) != 0 || len(scd.Industry) != 0) {
+	if scd.Comeinfrom == "supersearchPage" && (len(scd.Keyword) != 0 || len(scd.Industry) != 0) && scd.SearchMode == SearchModeFuzzy {
 		if len(scd.Keyword) != 0 {
+			// 关键词分词
 			searchTextSize := 0
 			if len(scd.Keyword) > 0 {
 				searchTextSize = len([]rune(scd.Keyword[0].Keyword))
 			}
-			if searchTextSize > 3 && count < 50 {
-				if strings.Index(scd.SelectType, "title") > -1 {
-					var res *[]map[string]interface{}
-					if count > 0 {
-						res = doSearch(qstr, 0, count, "")
-					}
-					if secondKWS := jy.HttpEs(scd.Keyword[0].Keyword, "ik_smart", elasticAddress); secondKWS != "" {
-						scd.Keyword[0].Keyword = secondKWS
-						scd.SelectType = "title"
-						qstr = getDataExportSql(scd)
-						res2 := doSearch(qstr, 0, 100, "")
-						result := len(*delRepeatMapArr(res, res2))
-						if result > 100 {
-							result = 100
-						}
-						log.Printf("GetDataExportSearchCountUseId-%s-count:%d-分词-sql:%s\n", scd.Id, result, qstr)
-						return result
+			if searchTextSize > 0 {
+				if secondKWS := jy.HttpEs(scd.Keyword[0].Keyword, "ik_smart", elasticAddress); secondKWS != "" {
+					scd.Keyword[0].Keyword = secondKWS
+				}
+			}
+			// 附加词分词
+			for i := 0; i < len(scd.Keyword[0].Appended); i++ {
+				appendTextSize := 0
+				if len(scd.Keyword[0].Appended[i]) > 0 {
+					appendTextSize = len([]rune(scd.Keyword[0].Appended[i]))
+				}
+				if appendTextSize > 0 {
+					if secondKWS := jy.HttpEs(scd.Keyword[0].Appended[i], "ik_smart", elasticAddress); secondKWS != "" {
+						scd.Keyword[0].Appended[i] = secondKWS
 					}
 				}
 			}
-			return
+
 		}
+		qstr := getDataExportSql(scd)
+		count = int(elastic.Count(INDEX, TYPE, qstr))
+		log.Printf("GetDataExportSearchCountUseId-%s-count:%d-分词-sql:%s\n", scd.Id, count, qstr)
+		return count
 	}
 	log.Printf("GetDataExportSearchCountUseId-%s-count:%d\n", scd.Id, count)
 	return
@@ -615,37 +702,44 @@ func GetDataExportIds(elasticAddress string, scd *SieveCondition, checkCount int
 	if scd.SelectIds != nil {
 		return scd.SelectIds, nil
 	}
-	//获取查询语句
-	qstr := getDataExportSql(scd)
-	log.Printf("GetDataExportIds-%s-sql:%s\n", scd.Id, qstr)
-
-	//数据导出数据查询
-	res := doSearchByBatch(qstr, "1", checkCount, fmt.Sprintf("%s-%s", "GetDataExportSearchResult", scd.Id))
+	var qstr string
+	if scd.SearchMode == SearchModeAccurate {
+		//获取查询语句
+		qstr = getDataExportSql(scd)
+		log.Printf("GetDataExportIds-%s-sql:%s\n", scd.Id, qstr)
+	}
 	//超级搜索一致的检索(防止数据导出和超级搜索数据量不一致)
-	if scd.Comeinfrom == "supersearchPage" && (len(scd.Keyword) != 0 || len(scd.Industry) != 0) && len(scd.SelectIds) == 0 {
+	// 依据用户选择的搜索模式和搜索范围进行匹配,即不限制只能匹配标题,且不限制最多展示100条、针对输入的单个关键词分词后需要都包含
+	if scd.Comeinfrom == "supersearchPage" && (len(scd.Keyword) != 0 || len(scd.Industry) != 0) && len(scd.SelectIds) == 0 && scd.SearchMode == SearchModeFuzzy {
 		if len(scd.Keyword) != 0 {
-			num := len(res)
 			searchTextSize := 0
+			// 关键词分词
 			if len(scd.Keyword) > 0 {
 				searchTextSize = len([]rune(scd.Keyword[0].Keyword))
 			}
-			if searchTextSize > 3 && num < 50 {
-				if strings.Index(scd.SelectType, "title") > -1 {
-					if secondKWS := jy.HttpEs(scd.Keyword[0].Keyword, "ik_smart", elasticAddress); secondKWS != "" {
-						scd.Keyword[0].Keyword = secondKWS
-						scd.SelectType = "title"
-						qstr = getDataExportSql(scd)
-						log.Printf("GetDataExportIds-%s-分词查询-sql:%s\n", scd.Id, qstr)
-						res2 := doSearch(qstr, 0, 100, "")
-						res = *delRepeatMapArr(&res, res2)
-						if len(res) > 100 {
-							res = res[:100]
-						}
+			if searchTextSize > 0 {
+				if secondKWS := jy.HttpEs(scd.Keyword[0].Keyword, "ik_smart", elasticAddress); secondKWS != "" {
+					scd.Keyword[0].Keyword = secondKWS
+				}
+			}
+			// 附加词分词
+			for i := 0; i < len(scd.Keyword[0].Appended); i++ {
+				appendTextSize := 0
+				if len(scd.Keyword[0].Appended[i]) > 0 {
+					appendTextSize = len([]rune(scd.Keyword[0].Appended[i]))
+				}
+				if appendTextSize > 0 {
+					if secondKWS := jy.HttpEs(scd.Keyword[0].Appended[i], "ik_smart", elasticAddress); secondKWS != "" {
+						scd.Keyword[0].Appended[i] = secondKWS
 					}
 				}
 			}
+
 		}
+		qstr = getDataExportSql(scd)
+		log.Printf("GetDataExportIds-%s-分词查询-sql:%s\n", scd.Id, qstr)
 	}
+	res := doSearchByBatch(qstr, "1", checkCount, fmt.Sprintf("%s-%s", "GetDataExportSearchResult", scd.Id))
 	//获取信息id
 	idArr := make([]string, 0, 0)
 	for _, v := range res {
@@ -676,36 +770,45 @@ func GetDataExportSearchResult(bid mg.MongodbSim, bidMgoDBName, elasticAddress s
 		return idSelectDates, idSelectErr
 	}
 	selectType := scd.SelectType
-	//获取查询语句
-	qstr := getDataExportSql(scd)
-	log.Printf("GetDataExportSearchResult-%s-sql:%s\n", scd.Id, qstr)
-
-	//数据导出数据查询
-	res := doSearchByBatch(qstr, dataType, checkCount, fmt.Sprintf("%s-%s", "GetDataExportSearchResult", scd.Id))
+	var qstr string
+	var res []map[string]interface{}
+	if scd.SearchMode == SearchModeAccurate { // 搜索模式为精确查找
+		//获取查询语句
+		qstr = getDataExportSql(scd)
+		log.Printf("GetDataExportSearchResult-%s-sql:%s\n", scd.Id, qstr)
+		//数据导出数据查询
+		res = doSearchByBatch(qstr, dataType, checkCount, fmt.Sprintf("%s-%s", "GetDataExportSearchResult", scd.Id))
+	}
 	//超级搜索一致的检索(防止数据导出和超级搜索数据量不一致)
-	if scd.Comeinfrom == "supersearchPage" && (len(scd.Keyword) != 0 || len(scd.Industry) != 0) && len(scd.SelectIds) == 0 {
+	if scd.Comeinfrom == "supersearchPage" && (len(scd.Keyword) != 0 || len(scd.Industry) != 0) && len(scd.SelectIds) == 0 && scd.SearchMode == SearchModeFuzzy {
 		if len(scd.Keyword) != 0 {
-			num := len(res)
 			searchTextSize := 0
+			// 关键词分词
 			if len(scd.Keyword) > 0 {
 				searchTextSize = len([]rune(scd.Keyword[0].Keyword))
 			}
-			if searchTextSize > 3 && num < 50 {
-				if strings.Index(scd.SelectType, "title") > -1 {
-					if secondKWS := jy.HttpEs(scd.Keyword[0].Keyword, "ik_smart", elasticAddress); secondKWS != "" {
-						scd.Keyword[0].Keyword = secondKWS
-						scd.SelectType = "title"
-						qstr = getDataExportSql(scd)
-						log.Printf("GetDataExportSearchResult-%s-分词查询-sql:%s\n", scd.Id, qstr)
-						res2 := doSearch(qstr, 0, 100, "")
-						res = *delRepeatMapArr(&res, res2)
-						if len(res) > 100 {
-							res = res[:100]
-						}
+			if searchTextSize > 0 {
+				if secondKWS := jy.HttpEs(scd.Keyword[0].Keyword, "ik_smart", elasticAddress); secondKWS != "" {
+					scd.Keyword[0].Keyword = secondKWS
+				}
+			}
+			// 附加词分词
+			for i := 0; i < len(scd.Keyword[0].Appended); i++ {
+				appendTextSize := 0
+				if len(scd.Keyword[0].Appended[i]) > 0 {
+					appendTextSize = len([]rune(scd.Keyword[0].Appended[i]))
+				}
+				if appendTextSize > 0 {
+					if secondKWS := jy.HttpEs(scd.Keyword[0].Appended[i], "ik_smart", elasticAddress); secondKWS != "" {
+						scd.Keyword[0].Appended[i] = secondKWS
 					}
 				}
 			}
+
 		}
+		qstr = getDataExportSql(scd)
+		log.Printf("GetDataExportSearchResult-%s-分词查询-sql:%s\n", scd.Id, qstr)
+		res = doSearchByBatch(qstr, dataType, checkCount, fmt.Sprintf("%s-%s", "GetDataExportSearchResult", scd.Id))
 	}
 	//校验数量
 	if checkCount != len(res) && checkCount != -1 {

+ 13 - 11
common/src/qfw/util/jy/bigVipPower.go

@@ -29,6 +29,7 @@ type BigVipBaseMsg struct {
 	HasTrial        bool                   `json:"has_trial"`       //是否试用过
 	Customers       int                    `json:"customers"`       //可关注客户数量
 	VipStatus       int                    `json:"vip_status"`      //超级订阅状态
+	VipStartDate    int64                  `json:"vipStartDate"`    //超级订阅开始时间
 	Vip_BuySet      BuySet                 `json:"vip_buyset"`      //超级订阅套餐内容
 	EntnicheStatus  int                    `json:"entniche_status"` //商机管理状态
 	IsUpgrade       bool                   `json:"isUpgrade"`       //是否是免费用户订阅升级用户 默认true
@@ -181,17 +182,18 @@ func GetBigVipUserBaseMsg(session *httpsession.Session, middleground middlegroun
 			isEnt = 1
 		}
 		userPower = BigVipBaseMsg{
-			Status:    qutil.IntAll(data.Member.Status),    //大会员状态
-			Used:      data.Member.Used,                    //是否首次使用大会员
-			PowerMap:  power,                               //权限列表
-			ProNum:    qutil.IntAll(data.Member.ProNum),    //可关注项目数量
-			EntNum:    qutil.IntAll(data.Member.EntNum),    //可关注企业数量(取企业情报监控和企业中标动态中最大的值)
-			DailyNum:  qutil.IntAll(data.Member.DailyNum),  //数据包导出数量
-			Pid:       data.Member.Pid,                     //若为子账号此处为父节点userid
-			Uid:       userId,                              //用户id
-			HasTrial:  data.Member.IsMemberTrial == 1,      //是否试用过
-			Customers: qutil.IntAll(data.Member.Customers), //可关注客户数量
-			VipStatus: qutil.IntAll(data.Vip.Status),       //超级订阅状态
+			Status:       qutil.IntAll(data.Member.Status),    //大会员状态
+			Used:         data.Member.Used,                    //是否首次使用大会员
+			PowerMap:     power,                               //权限列表
+			ProNum:       qutil.IntAll(data.Member.ProNum),    //可关注项目数量
+			EntNum:       qutil.IntAll(data.Member.EntNum),    //可关注企业数量(取企业情报监控和企业中标动态中最大的值)
+			DailyNum:     qutil.IntAll(data.Member.DailyNum),  //数据包导出数量
+			Pid:          data.Member.Pid,                     //若为子账号此处为父节点userid
+			Uid:          userId,                              //用户id
+			HasTrial:     data.Member.IsMemberTrial == 1,      //是否试用过
+			Customers:    qutil.IntAll(data.Member.Customers), //可关注客户数量
+			VipStatus:    qutil.IntAll(data.Vip.Status),       //超级订阅状态
+			VipStartDate: data.Vip.StartTime,
 			Vip_BuySet: BuySet{
 				Upgrade:         qutil.IntAll(data.Vip.Upgrade),
 				AreaCount:       qutil.IntAll(data.Vip.Areacount),

+ 7 - 3
common/src/qfw/util/jy/jy.go

@@ -52,6 +52,7 @@ func GetOldOpenid(s_m_openid, a_m_openid, s_phone string, mergeorder interface{}
 	return openid
 }
 
+var ClearHtml = regexp.MustCompile("<[^>]*>")
 var MatchSpace = regexp.MustCompile("\\s+")
 var filterReg_3 = regexp.MustCompile("(项目|公告|公示)$")
 var filterReg_2 = regexp.MustCompile("^[)\\)>》】\\]}}〕,,;;::'\"“”。.\\??、/+=\\_—*&……\\^%$¥@!!`~·(\\(<《【\\[{{〔]+$")
@@ -69,9 +70,12 @@ func FilteKey(k string) string {
 	return k
 }
 
-//超过20个字,截断
+// InterceptSearchKW 超过20个字,截断
 //返回截取后的字符串和截取掉中的前3个字
 func InterceptSearchKW(word string, keywordsLimit int, isFilter bool) (b_word, a_word, s_word string) {
+	if word == "" {
+		return
+	}
 	if isFilter {
 		word = FilteKey(word)
 	}
@@ -89,7 +93,7 @@ func InterceptSearchKW(word string, keywordsLimit int, isFilter bool) (b_word, a
 		b_word = word
 	}
 	a_word = strings.TrimSpace(a_word)
-	s_word = MatchSpace.ReplaceAllString(b_word, "+")
+	s_word = MatchSpace.ReplaceAllString(b_word, " ")
 	return
 }
 
@@ -123,7 +127,7 @@ func HttpEs(ques, analyzer, esAddress string) (res string) {
 			tokens := util.ObjArrToMapArr(resmap["tokens"].([]interface{}))
 			for _, v := range tokens {
 				token := util.ObjToString(v["token"])
-				if len([]rune(token)) == 1 && unicode.IsLetter([]rune(token)[0]) {
+				if len([]rune(token)) == 1 && !unicode.Is(unicode.Scripts["Han"], []rune(token)[0]) { //(P260保留单个汉字)
 					continue
 				}
 				if res != "" {

+ 9 - 3
common/src/qfw/util/jy/payUser.go

@@ -21,7 +21,10 @@ type VipState struct {
 	VipState     int   //超级订阅状态(1普通 2升级版)
 	BigMember    int   //大会员状态
 	EntMember    int   //商机管理用户状态
-	registerData int64 //注册时间
+	RegisterData int64 //注册时间
+	VipStartData int64 //超级订阅开始时间
+	IsNewEnt     bool  //新版商机管理
+	EntService   bool  //企业服务权限
 }
 
 func GetVipState(session *httpsession.Session, middleground middleground.Middleground, userId string) (vs *VipState) {
@@ -43,7 +46,10 @@ func GetVipState(session *httpsession.Session, middleground middleground.Middleg
 			vs.BigMember = qu.IntAll(i_member_status)
 		}
 		vs.EntMember = qu.IntAll(data.Data.Entniche.Status)
-		vs.registerData = data.Data.Free.Registedate
+		vs.RegisterData = data.Data.Free.Registedate
+		vs.VipStartData = data.VipStartDate
+		vs.IsNewEnt = data.EntIsNew
+		vs.EntService = data.IsEntService
 	}
 	return
 }
@@ -77,7 +83,7 @@ func (vs *VipState) GetQueryItems(selectType string, limitOldTime int64) (items
 		}
 		return
 	}
-	isOldUser := vs.registerData != 0 && vs.registerData < limitOldTime
+	isOldUser := vs.RegisterData != 0 && vs.RegisterData < limitOldTime
 	for _, t := range strings.Split(selectType, ",") {
 		if t == "winner" {
 			if isOldUser {

+ 47 - 22
public/dataexport.go

@@ -97,23 +97,27 @@ func GetPriceDes_SieveCondition(minPrice, maxPrice string) string {
 
 //招标数据导出筛选
 type BidSearchExport struct {
-	Keywords     string //搜索词
-	Publishtime  string //发布时间
-	Area         string //地区
-	Subtype      string //信息类型
-	Minprice     string //最低价格
-	Maxprice     string //最高价格
-	Industry     string //选中的行业
-	SelectType   string //标题 or 全文
-	Winner       string //中标单位
-	Buyerclass   string //采购单位行业
-	Hasbuyertel  string //是否有采购电话
-	Haswinnertel string //是否有中标电话
-	SelectIds    string //选择单条信息id
-	Notkey       string //排除词
-	FileExists   string //是否有附件
-	City         string //城市
-	BidField     string // 领域化数据: 0101 医疗
+	Keywords        string //搜索词
+	Publishtime     string //发布时间
+	Area            string //地区
+	Subtype         string //信息类型
+	Minprice        string //最低价格
+	Maxprice        string //最高价格
+	Industry        string //选中的行业
+	SelectType      string //标题 or 全文
+	Winner          string //中标单位
+	Buyerclass      string //采购单位行业
+	Hasbuyertel     string //是否有采购电话
+	Haswinnertel    string //是否有中标电话
+	SelectIds       string //选择单条信息id
+	Notkey          string //排除词 排除词(副:五组,每组最多15个字符)
+	FileExists      string //是否有附件
+	City            string //城市
+	BidField        string // 领域化数据: 0101 医疗
+	SearchGroup     int    // 搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+	SearchMode      int    // 搜索模式:0:精准搜索;1:模糊搜索
+	WordsMode       int    // 搜索关键词模式;默认0:包含所有,1:包含任意
+	AdditionalWords string // 关键词:附加关键词(副:五组,每组最多15个字符)
 }
 
 func (this *BidSearchExport) PassBidSearchExport(Sysconfig map[string]interface{}) (returnData map[string]interface{}) {
@@ -139,14 +143,32 @@ func (this *BidSearchExport) PassBidSearchExport(Sysconfig map[string]interface{
 	}
 
 	KeyWordSave := []dataexport.KeyWord{}
-	if len(this.Keywords) > 0 {
+	if len(this.Keywords) > 0 || len(this.AdditionalWords) > 0 {
 		_, _, keywords := jy.InterceptSearchKW(this.Keywords, util.IntAllDef(Sysconfig["keywordsLimit"], 35), len(this.Industry) == 0)
 		keywords = strings.Replace(keywords, "+", " ", -1)
-		excludes := []string{}
-		if this.Notkey != "" && len(strings.Split(this.Notkey, " ")) > 0 {
-			excludes = strings.Split(this.Notkey, " ")
+		excludes := []string{}    // 排除词
+		appendWords := []string{} // 附加词
+		//排除词  每组排除词不能超过15个字符
+		if this.Notkey != "" && len(strings.Split(this.Notkey, ",")) > 0 {
+			for _, ak := range strings.Split(this.Notkey, ",") {
+				if len([]rune(ak)) > 15 {
+					excludes = append(excludes, string([]rune(ak)[:15]))
+				} else {
+					excludes = append(excludes, ak)
+				}
+			}
+		}
+		//附加词 每组附加词不能超过15个字符
+		if this.AdditionalWords != "" && len(strings.Split(this.AdditionalWords, ",")) > 0 {
+			for _, ak := range strings.Split(this.AdditionalWords, ",") {
+				if len([]rune(ak)) > 15 {
+					appendWords = append(appendWords, string([]rune(ak)[:15]))
+				} else {
+					appendWords = append(appendWords, ak)
+				}
+			}
 		}
-		KeyWordSave = append(KeyWordSave, dataexport.KeyWord{Keyword: keywords, Exclude: excludes})
+		KeyWordSave = append(KeyWordSave, dataexport.KeyWord{Keyword: keywords, Exclude: excludes, Appended: appendWords})
 	}
 
 	//时间
@@ -187,6 +209,9 @@ func (this *BidSearchExport) PassBidSearchExport(Sysconfig map[string]interface{
 		"fileExists":   this.FileExists,
 		"comeintime":   now.Unix(),
 		"bid_field":    this.BidField,
+		"searchGroup":  this.SearchGroup,
+		"searchMode":   this.SearchMode,
+		"wordsMode":    this.WordsMode,
 	}
 	//选择信息id
 	if this.SelectIds != "" {