search.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. package util
  2. import (
  3. MC "app.yhyue.com/moapp/jybase/common"
  4. ME "app.yhyue.com/moapp/jybase/encrypt"
  5. elastic "app.yhyue.com/moapp/jybase/esv1"
  6. "crypto/rand"
  7. "encoding/json"
  8. "fmt"
  9. "github.com/zeromicro/go-zero/core/logx"
  10. "io/ioutil"
  11. IC "jyBXCore/rpc/init"
  12. "jyBXCore/rpc/type/bxcore"
  13. "math/big"
  14. "net/http"
  15. "net/url"
  16. "regexp"
  17. "strconv"
  18. "strings"
  19. "time"
  20. "unicode"
  21. )
  22. var ClearHtml = regexp.MustCompile("<[^>]*>")
  23. var MatchSpace = regexp.MustCompile("\\s+")
  24. var filterReg_3 = regexp.MustCompile("(项目|公告|公示)$")
  25. var filterReg_2 = regexp.MustCompile("^[)\\)>》】\\]}}〕,,;;::'\"“”。.\\??、/+=\\_—*&……\\^%$¥@!!`~·(\\(<《【\\[{{〔]+$")
  26. var filterReg_1 = regexp.MustCompile("^([0-9]{1,3}|[零一二三四五六七八九十]{1,2}|联系人?|电话|地址|编号|采购|政府采购|成交|更正|招标|中标|变更|结果)$")
  27. var filterReg = regexp.MustCompile("^[的人号时元万公告项目地址电话邮编日期联系招标中结果成交项目项目采购采购项目政府采购公告更正公告]+$")
  28. var PhoneReg = regexp.MustCompile("^[1][3-9][0-9]{9}$")
  29. var EmailPattern = regexp.MustCompile("^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$")
  30. func SearchHistory(history, searchvalue string) (arrs []string) {
  31. if searchvalue != "" {
  32. arrs = strings.Split(history, ",")
  33. //新增历史记录
  34. if history == "" {
  35. arrs = make([]string, 0)
  36. }
  37. for k, v := range arrs {
  38. if v == strings.TrimSpace(searchvalue) {
  39. arrs = append(arrs[:k], arrs[k+1:]...)
  40. break
  41. }
  42. }
  43. arrs = append(arrs, searchvalue)
  44. if len(arrs) > 10 {
  45. arrs = arrs[1:11]
  46. }
  47. }
  48. return arrs
  49. }
  50. func FilteKey(k string) string {
  51. k = strings.TrimSpace(k)
  52. k = filterReg_3.ReplaceAllString(k, "")
  53. k = filterReg_2.ReplaceAllString(k, "")
  54. k = filterReg_1.ReplaceAllString(k, "")
  55. k = filterReg.ReplaceAllString(k, "")
  56. return k
  57. }
  58. //超过20个字,截断
  59. //返回截取后的字符串和截取掉中的前3个字
  60. func InterceptSearchKW(word string, isIntercept, isFilter bool) (b_word, a_word, s_word string) {
  61. if isFilter {
  62. word = FilteKey(word)
  63. }
  64. word = MatchSpace.ReplaceAllString(strings.TrimSpace(word), " ")
  65. words := []rune(word)
  66. if len(words) > 20 && isIntercept {
  67. b_word = string(words[:20])
  68. b_word = strings.TrimSpace(b_word)
  69. if len(words) > 23 {
  70. a_word = string(words[20:23])
  71. } else {
  72. a_word = string(words[20:])
  73. }
  74. } else {
  75. b_word = word
  76. }
  77. a_word = strings.TrimSpace(a_word)
  78. s_word = MatchSpace.ReplaceAllString(b_word, "+")
  79. return
  80. }
  81. func HttpEs(ques, analyzer, esAddress string) (res string) {
  82. var addrs []string
  83. surl := ""
  84. for _, s := range strings.Split(esAddress, ",") {
  85. addrs = append(addrs, s)
  86. }
  87. i, _ := rand.Int(rand.Reader, big.NewInt(int64(len(addrs)))) //随机
  88. surl = addrs[int(i.Int64())] + "/bidding/_analyze"
  89. URL, _ := url.Parse(surl)
  90. Q := URL.Query()
  91. Q.Add("text", ques)
  92. Q.Add("analyzer", analyzer)
  93. URL.RawQuery = Q.Encode()
  94. resp, err := http.Get(URL.String())
  95. if err != nil {
  96. logx.Info("es连接失败 err1:", err)
  97. resp, err = getesResp(ques, analyzer, addrs)
  98. if err != nil {
  99. return
  100. }
  101. }
  102. result, err := ioutil.ReadAll(resp.Body)
  103. if err == nil {
  104. defer resp.Body.Close()
  105. var resmap map[string]interface{}
  106. json.Unmarshal(result, &resmap)
  107. if resmap != nil && resmap["tokens"] != nil {
  108. tokens := MC.ObjArrToMapArr(resmap["tokens"].([]interface{}))
  109. for _, v := range tokens {
  110. token := MC.ObjToString(v["token"])
  111. if len([]rune(token)) == 1 && unicode.IsLetter([]rune(token)[0]) {
  112. continue
  113. }
  114. if res != "" {
  115. res += "+"
  116. }
  117. res += token
  118. }
  119. }
  120. }
  121. return
  122. }
  123. //
  124. func getesResp(ques, analyzer string, addrs []string) (resp *http.Response, err error) {
  125. for _, v := range addrs {
  126. surl := v + "/bidding/_analyze"
  127. URL, _ := url.Parse(surl)
  128. Q := URL.Query()
  129. Q.Add("text", ques)
  130. Q.Add("analyzer", analyzer)
  131. URL.RawQuery = Q.Encode()
  132. resp, err = http.Get(URL.String())
  133. if err == nil {
  134. break
  135. }
  136. }
  137. return resp, err
  138. }
  139. //pc、微信、app 招标信息搜索
  140. const (
  141. INDEX = "bidding"
  142. TYPE = "bidding"
  143. bidSearch_sort = `{"publishtime":-1}`
  144. RedisName = "other"
  145. //招标搜索分页--每页显示数量
  146. SearchPageSize = 50
  147. //招标搜索分页--最大页数
  148. SearchMaxPageNum = 10 //免费用户500条记录
  149. SearchMaxPageNum_PAYED = 100 //付费用户5000条记录
  150. bidSearch_field_1 = `"_id","title","publishtime","toptype","subtype","type","area","city","s_subscopeclass","bidamount","budget","buyerclass","spidercode","site"` //,"filetext"
  151. bidSearch_field = bidSearch_field_1 + `,"bidopentime","winner","buyer","projectname","projectcode","projectinfo"`
  152. bidSearch_field_file = `,"filetext"`
  153. query_bool_should = `{"bool":{"should":[%s],"minimum_should_match": 1}}`
  154. )
  155. //GetBidSearchData 标信息搜索
  156. func GetBidSearchData(in *bxcore.SearchReq) (count int64, list []*bxcore.SearchList) {
  157. t := time.Now()
  158. var hightlightContent bool = false //是否高亮正文
  159. var selectTypeArr = strings.Split(in.SelectType, ",")
  160. for _, v := range selectTypeArr {
  161. if v == "detail" {
  162. hightlightContent = true
  163. break
  164. }
  165. }
  166. qstr := GetSearchQuery(in, GetBidSearchQuery(in))
  167. var start = int((in.PageNum - 1) * in.PageSize)
  168. //首页
  169. if qstr != "" { //&& start == 0
  170. count = elastic.Count(INDEX, TYPE, qstr)
  171. }
  172. if count > 0 || start > 1 {
  173. field := bidSearch_field_1
  174. if start == 0 {
  175. field = bidSearch_field
  176. }
  177. if IC.C.FileSignBool {
  178. field = field + bidSearch_field_file
  179. }
  180. var repl *[]map[string]interface{}
  181. if hightlightContent {
  182. repl = elastic.GetAllByNgram(INDEX, TYPE, qstr, `"detail"`, bidSearch_sort, field, start, int(in.PageSize), 115, true)
  183. } else {
  184. repl = elastic.GetAllByNgram(INDEX, TYPE, qstr, ``, bidSearch_sort, field, start, int(in.PageSize), 0, false)
  185. }
  186. if repl != nil && *repl != nil && len(*repl) > 0 {
  187. BidListConvert(in.Industry, repl)
  188. list = searchListFormart(repl, true)
  189. }
  190. logx.Info("关键词 -1- 查询耗时:", time.Since(t).Seconds())
  191. MakeCollection(in.UserId, list)
  192. }
  193. logx.Info("关键词 查询耗时:", time.Since(t).Seconds())
  194. return
  195. }
  196. //
  197. var topTypeMap = map[string]string{
  198. "招标预告": "预告",
  199. "招标公告": "招标",
  200. "招标结果": "结果",
  201. "招标信用信息": "其它",
  202. "拟建项目": "拟建",
  203. "采购意向": "采购意向",
  204. }
  205. //
  206. func GetBidSearchQuery(in *bxcore.SearchReq) string {
  207. query := ``
  208. //省份
  209. area := in.Province
  210. if area != "" {
  211. query += `{"terms":{"area":[`
  212. for k, v := range strings.Split(area, ",") {
  213. if k > 0 {
  214. query += `,`
  215. }
  216. query += `"` + v + `"`
  217. }
  218. query += `]}}`
  219. }
  220. //
  221. city := in.City
  222. if city != "" {
  223. if len(query) > 0 {
  224. query += ","
  225. }
  226. query += `{"terms":{"city":[`
  227. for k, v := range strings.Split(city, ",") {
  228. if k > 0 {
  229. query += `,`
  230. }
  231. query += `"` + v + `"`
  232. }
  233. query += `]}}`
  234. }
  235. if query != "" {
  236. query = fmt.Sprintf(query_bool_should, query)
  237. }
  238. //发布时间
  239. publishtime := in.PublishTime
  240. if publishtime != "" && len(strings.Split(publishtime, "-")) > 1 {
  241. if len(query) > 0 {
  242. query += ","
  243. }
  244. starttime := strings.Split(publishtime, "-")[0]
  245. endtime := strings.Split(publishtime, "-")[1]
  246. query += `{"range":{"publishtime":{`
  247. if starttime != "" {
  248. query += `"gte":` + starttime
  249. }
  250. if starttime != "" && endtime != "" {
  251. query += `,`
  252. }
  253. if endtime != "" {
  254. query += `"lt":` + endtime
  255. }
  256. query += `}}}`
  257. }
  258. //信息类型-二级
  259. subtype := in.Subtype
  260. toptype := MC.If(in.Toptype != "", strings.Split(in.Toptype, ","), []string{}).([]string)
  261. alltype := ``
  262. //二级分类
  263. if subtype != "" {
  264. var typeInt = 0
  265. alltype += `{"terms":{"subtype":[`
  266. for k, v := range strings.Split(subtype, ",") {
  267. if ttype := MC.If(topTypeMap[v] != "" && in.Toptype == "", topTypeMap[v], "").(string); ttype != "" {
  268. toptype = append(toptype, ttype)
  269. typeInt += 1
  270. continue
  271. }
  272. if k > typeInt {
  273. alltype += `,`
  274. }
  275. alltype += `"` + v + `"`
  276. }
  277. alltype += `]}}`
  278. }
  279. //信息类型 一级分类
  280. logx.Info("toptype:", toptype)
  281. if len(toptype) > 0 {
  282. if alltype != "" {
  283. alltype += ","
  284. }
  285. alltype += `{"terms":{"toptype":[`
  286. for k, v := range toptype {
  287. if k > 0 {
  288. alltype += `,`
  289. }
  290. alltype += `"` + v + `"`
  291. }
  292. alltype += `]}}`
  293. }
  294. if alltype != "" {
  295. if query != "" {
  296. query += ","
  297. }
  298. query += fmt.Sprintf(query_bool_should, alltype)
  299. }
  300. //采购单位类型
  301. buyerclass := in.BuyerClass
  302. if buyerclass != "" {
  303. if len(query) > 0 {
  304. query += ","
  305. }
  306. query += `{"terms":{"buyerclass":[`
  307. for k, v := range strings.Split(buyerclass, ",") {
  308. if k > 0 {
  309. query += `,`
  310. }
  311. query += `"` + v + `"`
  312. }
  313. query += `]}}`
  314. }
  315. return query
  316. }
  317. func GetSearchQuery(in *bxcore.SearchReq, mustquery string) (qstr string) {
  318. multi_match := `{"multi_match": {"query": "%s","type": "phrase", "fields": [%s]}}`
  319. query := `{"query":{"bool":{"must":[%s],"must_not":[%s]}}}`
  320. query_bool_should := `{"bool":{"should":[%s],"minimum_should_match": 1}}`
  321. query_bools_must := `{"bool":{"must":[{"range":{"bidamount":{%s}}}]}},{"bool":{"must":[{"range":{"budget":{%s}}}],"must_not":[{"range":{"bidamount":{"gte":-1}}}]}}`
  322. query_bool_must := `{"bool":{"must":[{"terms":{"s_subscopeclass":[%s]}}]}}`
  323. query_missing := `{"constant_score":{"filter":{"missing":{"field":"%s"}}}}`
  324. gte := `"gte": %s`
  325. lte := `"lte": %s`
  326. musts, must_not := []string{}, []string{}
  327. if mustquery != "" {
  328. musts = append(musts, mustquery)
  329. }
  330. //搜索范围是否只有附件
  331. //搜索范围只选择附件,是否有附件条件无效;
  332. var isFileSearch bool = in.SelectType == "filetext"
  333. selectTypeArr := strings.Split(in.SelectType, ",")
  334. var findfields string
  335. if selectTypeArr == nil || len(selectTypeArr) == 0 {
  336. findfields = `"title"`
  337. } else {
  338. findfields = fmt.Sprintf(`"%s"`, strings.Join(selectTypeArr, "\",\""))
  339. }
  340. //此时关键词中间有+进行隔离
  341. if in.KeyWords != "" {
  342. shoulds := []string{}
  343. var switchBool = strings.Contains(findfields, "detail") && strings.Contains(findfields, "title") && IC.C.SearchTypeSwitch
  344. for _, v := range strings.Split(in.KeyWords, "+") {
  345. //标题 全文搜索 搜索类型开关打开 默认搜索全文;(全文包含标题)(单字排除)
  346. if switchBool && len([]rune(elastic.ReplaceYH(v))) > 1 {
  347. if strings.Contains(findfields, `"title",`) {
  348. findfields = strings.Replace(findfields, `"title",`, ``, -1)
  349. } else if strings.Contains(findfields, `,"title"`) {
  350. findfields = strings.Replace(findfields, `,"title"`, ``, -1)
  351. }
  352. }
  353. keyword_multi_match := fmt.Sprintf(multi_match, "%s", findfields)
  354. shoulds = append(shoulds, fmt.Sprintf(keyword_multi_match, elastic.ReplaceYH(v)))
  355. }
  356. musts = append(musts, fmt.Sprintf(elastic.NgramMust, strings.Join(shoulds, ",")))
  357. }
  358. if in.Industry != "" {
  359. industrys := strings.Split(in.Industry, ",")
  360. musts = append(musts, fmt.Sprintf(query_bool_must, `"`+strings.Join(industrys, `","`)+`"`))
  361. }
  362. //价格
  363. if in.Price != "" && len(strings.Split(in.Price, "-")) > 1 {
  364. minprice, maxprice := strings.Split(in.Price, "-")[0], strings.Split(in.Price, "-")[1]
  365. if minprice != "" || maxprice != "" {
  366. sq := ``
  367. if minprice != "" {
  368. min, _ := strconv.ParseFloat(minprice, 64)
  369. minprice = fmt.Sprintf("%.0f", min*10000)
  370. if minprice == "0" {
  371. minprice = ""
  372. }
  373. }
  374. if maxprice != "" {
  375. max, _ := strconv.ParseFloat(maxprice, 64)
  376. maxprice = fmt.Sprintf("%.0f", max*10000)
  377. if maxprice == "0" {
  378. maxprice = ""
  379. }
  380. }
  381. if minprice != "" {
  382. sq += fmt.Sprintf(gte, minprice)
  383. }
  384. if minprice != "" && maxprice != "" {
  385. sq += `,`
  386. }
  387. if maxprice != "" {
  388. sq += fmt.Sprintf(lte, maxprice)
  389. }
  390. if minprice != "" || maxprice != "" {
  391. query_price := fmt.Sprintf(query_bool_should, fmt.Sprintf(query_bools_must, sq, sq))
  392. musts = append(musts, query_price)
  393. }
  394. }
  395. }
  396. hasBuyerTel := in.BuyerTel
  397. if hasBuyerTel != "" {
  398. if hasBuyerTel == "y" {
  399. must_not = append(must_not, fmt.Sprintf(query_missing, "buyertel"))
  400. } else {
  401. musts = append(musts, fmt.Sprintf(query_missing, "buyertel"))
  402. }
  403. }
  404. hasWinnerTel := in.WinnerTel
  405. if hasWinnerTel != "" {
  406. if hasWinnerTel == "y" {
  407. must_not = append(must_not, fmt.Sprintf(query_missing, "winnertel"))
  408. } else {
  409. musts = append(musts, fmt.Sprintf(query_missing, "winnertel"))
  410. }
  411. }
  412. //排除词
  413. notkey := in.ExclusionWords
  414. if notkey = strings.TrimSpace(notkey); notkey != "" {
  415. notkey_multi_match := fmt.Sprintf(multi_match, "%s", findfields)
  416. notkey_must_not := []string{}
  417. for _, v := range strings.Split(notkey, " ") {
  418. v = strings.TrimSpace(v)
  419. if v == "" {
  420. continue
  421. }
  422. notkey_must_not = append(notkey_must_not, fmt.Sprintf(notkey_multi_match, elastic.ReplaceYH(v)))
  423. }
  424. must_not = append(must_not, fmt.Sprintf(query_bool_should, strings.Join(notkey_must_not, ",")))
  425. }
  426. //
  427. fileExists := in.FileExists
  428. if !isFileSearch && fileExists != "" {
  429. if fileExists == "1" { //有附件
  430. must_not = append(must_not, fmt.Sprintf(query_missing, "filetext"))
  431. } else if fileExists == "-1" { //无附件
  432. musts = append(musts, fmt.Sprintf(query_missing, "filetext"))
  433. }
  434. }
  435. qstr = fmt.Sprintf(query, strings.Join(musts, ","), strings.Join(must_not, ","))
  436. logx.Info(qstr)
  437. return
  438. }
  439. /*
  440. * 结果列表转换,目前只换行行业字段
  441. * 所有的招标搜索都要调用此方法,列表中有展示行业的也可以用
  442. * industry 搜索条件中的行业,默认为空
  443. */
  444. func BidListConvert(industry string, res *[]map[string]interface{}) {
  445. if res == nil {
  446. return
  447. }
  448. commonSubstring := func(v string) (value string) {
  449. bcs := strings.Split(v, "_")
  450. if len(bcs) == 1 {
  451. value = bcs[0]
  452. } else if len(bcs) == 2 {
  453. value = bcs[0]
  454. if strings.TrimSpace(value) == "" {
  455. value = bcs[0]
  456. }
  457. }
  458. return
  459. }
  460. for _, v := range *res {
  461. v["id"] = v["_id"]
  462. delete(v, "_id")
  463. budget, _ := v["budget"].(float64)
  464. bidamount, _ := v["bidamount"].(float64)
  465. if budget == 0 || strings.TrimSpace(fmt.Sprint(v["budget"])) == "" {
  466. delete(v, "budget")
  467. }
  468. if bidamount == 0 || strings.TrimSpace(fmt.Sprint(v["bidamount"])) == "" {
  469. delete(v, "bidamount")
  470. }
  471. value := ""
  472. subscopeclass, _ := v["s_subscopeclass"].(string)
  473. subscopeclass = strings.Trim(subscopeclass, ",")
  474. bct := strings.Split(subscopeclass, ",")
  475. if bct == nil || len(bct) == 0 {
  476. continue
  477. }
  478. //搜索条件中没有行业的话,取查询结果中第一个行业
  479. if industry == "" {
  480. value = commonSubstring(bct[0])
  481. } else { //搜索条件中有行业的话,取行业中和搜索条件相对应的第一个
  482. industrys := strings.Split(industry, ",")
  483. L:
  484. for _, bc := range bct {
  485. for _, is := range industrys {
  486. if bc == is {
  487. value = commonSubstring(bc)
  488. break L
  489. }
  490. }
  491. }
  492. }
  493. if strings.TrimSpace(value) == "" {
  494. continue
  495. }
  496. v["industry"] = value
  497. }
  498. }
  499. //是否收藏
  500. func MakeCollection(userId string, list []*bxcore.SearchList) {
  501. if list == nil || len(list) == 0 {
  502. return
  503. }
  504. param := []interface{}{userId}
  505. wh := []string{}
  506. for _, v := range list {
  507. array := ME.DecodeArticleId2ByCheck(v.Id)
  508. if len(array) == 1 && array[0] != "" {
  509. param = append(param, array[0])
  510. wh = append(wh, "?")
  511. }
  512. }
  513. if len(wh) > 0 {
  514. result := IC.MainMysql.SelectBySql(`select bid from bdcollection where userid=? and bid in (`+strings.Join(wh, ",")+`)`, param...)
  515. bid_map := map[string]bool{}
  516. if result != nil {
  517. for _, v := range *result {
  518. bid_map[ME.EncodeArticleId2ByCheck(MC.ObjToString(v["bid"]))] = true
  519. }
  520. }
  521. for _, v := range list {
  522. if bid_map[v.Id] {
  523. v.IsCollected = true
  524. }
  525. }
  526. }
  527. }
  528. //默认查询缓存数据
  529. func SearchCahcheData(in *bxcore.SearchReq) (count int64, list []*bxcore.SearchList) {
  530. //最新招标信息
  531. findfields := `"title"`
  532. qstr := GetSearchQuery(in, GetBidSearchQuery(in))
  533. //首页
  534. if in.PageNum == 1 {
  535. count = elastic.Count(INDEX, TYPE, qstr)
  536. }
  537. if count > 0 || in.PageNum > 1 {
  538. repl := elastic.GetAllByNgram(INDEX, TYPE, qstr, findfields, bidSearch_sort, bidSearch_field, int(in.PageNum), int(in.PageSize), 0, false)
  539. if repl != nil && *repl != nil && len(*repl) > 0 {
  540. BidListConvert(in.Industry, repl)
  541. list = searchListFormart(repl, false)
  542. }
  543. }
  544. return
  545. }
  546. //格式化数据
  547. func searchListFormart(repl *[]map[string]interface{}, b bool) (list []*bxcore.SearchList) {
  548. for _, v := range *repl {
  549. var searchList = &bxcore.SearchList{}
  550. if b {
  551. //正文匹配检索关键词
  552. highlight, _ := v["highlight"].(map[string][]string)
  553. detail := ""
  554. for _, val := range highlight["detail"] {
  555. detail += ClearHtml.ReplaceAllString(val, "")
  556. }
  557. searchList.Detail = detail
  558. }
  559. searchList.Area = MC.ObjToString(v["area"])
  560. searchList.AreaUrl = IC.LabelMap[searchList.Area].Url
  561. searchList.BuyerClass = MC.ObjToString(v["buyerclass"])
  562. searchList.City = MC.ObjToString(v["city"])
  563. searchList.FileExists = v["filetext"] != nil
  564. searchList.Id = ME.EncodeArticleId2ByCheck(MC.ObjToString(v["id"]))
  565. searchList.Industry = MC.ObjToString(v["industry"])
  566. searchList.IndustryUrl = IC.LabelMap[searchList.Industry].Url
  567. searchList.PublishTime = MC.Int64All(v["publishtime"])
  568. searchList.Subtype = MC.ObjToString(v["subtype"])
  569. searchList.SubtypeUrl = IC.LabelMap[searchList.Subtype].Url
  570. searchList.Title = MC.ObjToString(v["title"])
  571. searchList.Budget = MC.Int64All(v["budget"])
  572. searchList.Bidamount = MC.Int64All(v["bidamount"])
  573. searchList.ProjectName = MC.ObjToString(v["projectname"])
  574. searchList.ProjectCode = MC.ObjToString(v["projectcode"])
  575. searchList.ProjectInfo = &bxcore.PInfo{}
  576. if v["projectinfo"] != nil {
  577. pinfo := MC.ObjToMap(v["projectinfo"])
  578. searchList.ProjectInfo.ApproveCode = MC.ObjToString((*pinfo)["approvecode"])
  579. searchList.ProjectInfo.ApproveContent = MC.ObjToString((*pinfo)["approvecontent"])
  580. searchList.ProjectInfo.ApproveDept = MC.ObjToString((*pinfo)["approvedept"])
  581. searchList.ProjectInfo.ApproveStatus = MC.ObjToString((*pinfo)["approvestatus"])
  582. searchList.ProjectInfo.ProjectType = MC.ObjToString((*pinfo)["projecttype"])
  583. searchList.ProjectInfo.ApproveNumber = MC.ObjToString((*pinfo)["approvenumber"])
  584. searchList.ProjectInfo.ApproveTime = MC.ObjToString((*pinfo)["approvetime"])
  585. }
  586. searchList.Winner = MC.ObjToString(v["winner"])
  587. searchList.Buyer = MC.ObjToString(v["buyer"])
  588. searchList.BidopenTime = MC.Int64All(v["bidopentime"])
  589. searchList.Site = MC.ObjToString(v["site"])
  590. searchList.SpiderCode = MC.ObjToString(v["spidercode"])
  591. list = append(list, searchList)
  592. }
  593. return
  594. }
  595. //合并map数据,去重,排序
  596. func DelRepeatSearchData(resOne, resTwo []*bxcore.SearchList) []*bxcore.SearchList {
  597. if len(resOne) > 0 && len(resTwo) > 0 {
  598. for _, v := range resOne {
  599. for n, m := range resTwo {
  600. if v.Id == m.Id {
  601. resTwo = append(resTwo[0:n], resTwo[n+1:]...)
  602. break
  603. }
  604. }
  605. }
  606. resOne = append(resOne, resTwo...)
  607. } else {
  608. resOne = append(resOne, resTwo...)
  609. }
  610. //sort.Slice(resOne, func(i, j int) bool {
  611. // return resOne[i].PublishTime > resOne[j].PublishTime
  612. //})
  613. return resOne
  614. }