purchase.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. package service
  2. import (
  3. MC "app.yhyue.com/moapp/jybase/common"
  4. "app.yhyue.com/moapp/jybase/encrypt"
  5. elastic "app.yhyue.com/moapp/jybase/es"
  6. "app.yhyue.com/moapp/jybase/redis"
  7. "app.yhyue.com/moapp/jypkg/common/src/qfw/util/jy"
  8. "bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/entity"
  9. IC "bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/init"
  10. "bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/model/es"
  11. "bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/type/bxcore"
  12. "bp.jydev.jianyu360.cn/BaseService/jyMicroservices/jyBXCore/rpc/util"
  13. "encoding/json"
  14. "fmt"
  15. "github.com/zeromicro/go-zero/core/logx"
  16. "log"
  17. "strconv"
  18. "strings"
  19. "time"
  20. )
  21. type Purchase struct {
  22. AppId string ` json:"appId,omitempty"` //剑鱼默认10000
  23. UserId string ` json:"userId,omitempty"` //用户id
  24. Phone string ` json:"phone,omitempty"` //手机号
  25. BaseUserId int64 ` json:"baseUserId,omitempty"` //base_user_id 新用户id
  26. EntId int64 ` json:"entId,omitempty"` //企业id 没有企业 企业id=0
  27. EntUserId int64 ` json:"entUserId,omitempty"` //企业用户id 当前企业下的员工id 没有企业默认0
  28. AccountId int64 ` json:"accountId,omitempty"` //账户id
  29. EntAccountId int64 ` json:"entAccountId,omitempty"` //企业账户id
  30. PositionType int64 ` json:"positionType,omitempty"` //职位类型 0个人 1企业
  31. PositionId int64 ` json:"positionId,omitempty"` //职位id
  32. MgoUserId string ` json:"mgoUserId,omitempty"` //原userId
  33. PageNum int64 ` json:"pageNum,omitempty"` //当前页码
  34. PageSize int64 ` json:"pageSize,omitempty"` //每页数量
  35. PublishTime string ` json:"publishTime,omitempty"` //发布时间
  36. SelectType string ` json:"selectType,omitempty"` //搜索范围:
  37. DomainFirstType string ` json:"domainFirstType,omitempty"` //领域 一级
  38. DomainSecondType string ` json:"domainSecondType,omitempty"` //领域 二级
  39. DomainThirdType string ` json:"domainThirdType,omitempty"` //领域 三级
  40. DeadlineStatus int64 ` json:"deadlineStatus,omitempty"` //报名截止状态
  41. DeadlineTime string ` json:"deadlineTime,omitempty"` //报名截止时间
  42. DeadlineStart int64 ` json:"deadlineStart,omitempty"` //报名截止时间-开始
  43. DeadlineEnd int64 ` json:"deadlineEnd,omitempty"` //报名截止时间-结束
  44. DeliveryArea string ` json:"deliveryArea,omitempty"` //交付地点-省份
  45. DeliveryCity string ` json:"deliveryCity,omitempty"` //交付地点-城市
  46. DeliveryDistrict string ` json:"deliveryDistrict,omitempty"` //交付地点-县区
  47. ProjectArea string ` json:"projectArea,omitempty"` //项目地区-省份
  48. ProjectCity string ` json:"projectCity,omitempty"` //项目地区-城市
  49. ProjectDistrict string ` json:"projectDistrict,omitempty"` //项目地区-县区
  50. Industry string ` json:"industry,omitempty"` //行业
  51. FileExists int64 ` json:"fileExists,omitempty"` //是否有附件
  52. Publisher int64 ` json:"publisher,omitempty"` //发布者:可选:全部、用户发布:1、平台发布:2。
  53. KeyWords string ` json:"keyWords,omitempty"` //关键词:多个空格隔开(主)
  54. AdditionalWords string ` json:"additionalWords,omitempty"` //关键词:附加关键词(副:五组,每组最多15个字符)
  55. SearchMode int64 ` json:"searchMode,omitempty"` //搜索模式:0:精准搜索;1:模糊搜索
  56. WordsMode int64 ` json:"wordsMode,omitempty"` //搜索关键词模式;默认0:包含所有,1:包含任意
  57. UserAgent string ` json:"userAgent,omitempty"` //请求头信息
  58. Platform string ` json:"platform,omitempty"` //请求平台
  59. TipMsg string `json:"tipMsg"` //关键词提示信息
  60. HighlightWords string `json:"highlightWords"` //需要高亮的词,多个,号分割
  61. Total int64 `json:"total"` //数据总量
  62. Count int64 `json:"count"` //结果数据总量
  63. IsPay bool `json:"isPay"` //是否是付费用户
  64. IsPower bool `json:"isPower"` //是否有权限
  65. InterceptKeyWords string `json:"interceptKeyWords"`
  66. }
  67. func NewPurchase(in *bxcore.PurchaseReq) *Purchase {
  68. baseUserId, _ := strconv.ParseInt(in.NewUserId, 10, 64)
  69. accountId, _ := strconv.ParseInt(in.AccountId, 10, 64)
  70. positionId, _ := strconv.ParseInt(in.PositionId, 10, 64)
  71. return &Purchase{
  72. AppId: in.AppId,
  73. UserId: in.UserId,
  74. Phone: in.Phone,
  75. BaseUserId: baseUserId,
  76. EntId: in.EntId,
  77. EntUserId: in.EntUserId,
  78. AccountId: accountId,
  79. EntAccountId: in.EntAccountId,
  80. PositionType: in.PositionType,
  81. PositionId: positionId,
  82. MgoUserId: in.MgoUserId,
  83. PageNum: in.PageNum,
  84. PageSize: in.PageSize,
  85. PublishTime: in.PublishTime,
  86. SelectType: in.SelectType,
  87. DomainFirstType: in.DomainFirstType,
  88. DomainSecondType: in.DomainSecondType,
  89. DomainThirdType: in.DomainThirdType,
  90. DeadlineStatus: in.DeadlineStatus,
  91. DeadlineTime: in.DeadlineTime,
  92. DeliveryArea: in.DeliveryArea,
  93. DeliveryCity: in.DeliveryCity,
  94. DeliveryDistrict: in.DeliveryDistrict,
  95. ProjectArea: in.ProjectArea,
  96. ProjectCity: in.ProjectCity,
  97. ProjectDistrict: in.ProjectDistrict,
  98. Industry: in.Industry,
  99. FileExists: in.FileExists,
  100. Publisher: in.Publisher,
  101. KeyWords: in.KeyWords,
  102. AdditionalWords: in.AdditionalWords,
  103. SearchMode: in.SearchMode,
  104. WordsMode: in.WordsMode,
  105. UserAgent: in.UserAgent,
  106. Platform: in.Platform,
  107. }
  108. }
  109. var (
  110. AreaLabelLink = "/list/%s/%s.html"
  111. noPower = "点击查看"
  112. )
  113. // 缓存
  114. func (p *Purchase) HistoryKeywords() {
  115. var (
  116. cacheKey = fmt.Sprintf("history_purchase_v_%s", p.UserId)
  117. keys []string
  118. code = "other"
  119. isExist = map[string]bool{}
  120. duplicateRemoval = func(values []string) (keys []string) {
  121. for _, kv := range values {
  122. kv = strings.TrimSpace(kv)
  123. if isExist[kv] {
  124. continue
  125. }
  126. isExist[kv] = true
  127. keys = append(keys, kv)
  128. }
  129. return
  130. }
  131. )
  132. values := redis.GetStr(code, cacheKey)
  133. if values != "" {
  134. keys = append(keys, duplicateRemoval(strings.Split(values, ","))...)
  135. }
  136. if p.KeyWords != "" {
  137. keys = append(keys, duplicateRemoval(strings.Split(p.KeyWords, ","))...)
  138. }
  139. if p.AdditionalWords != "" {
  140. keys = append(keys, duplicateRemoval(strings.Split(p.AdditionalWords, ","))...)
  141. }
  142. if len(keys) > 10 {
  143. keys = keys[len(keys)-10:]
  144. }
  145. ok := redis.Put(code, cacheKey, strings.Join(keys, ","), -1)
  146. if !ok {
  147. logx.Info(" history keywords err:", keys)
  148. }
  149. }
  150. var (
  151. titleSuffix = "%s等"
  152. )
  153. // 格式化
  154. func (p *Purchase) PurchaseListFormat(res []map[string]interface{}) (list []*bxcore.PurchaseList) {
  155. for _, rv := range res {
  156. logx.Info("title:", MC.InterfaceToStr(rv["title"]))
  157. id := MC.InterfaceToStr(rv["source_id"]) //拆分后 多条数据会来自一条bidding数据嘛,把bidding的id记一个source_id;mongo 库中bidding的_id
  158. if id == "" {
  159. continue
  160. }
  161. area := MC.InterfaceToStr(rv["area"])
  162. city := MC.InterfaceToStr(rv["city"])
  163. district := MC.InterfaceToStr(rv["district"])
  164. title := MC.InterfaceToStr(rv["title"])
  165. originalTitle := title
  166. if len([]rune(title)) > 50 {
  167. splitStr := "-"
  168. titles := strings.Split(title, splitStr)
  169. lastPart := ""
  170. if len(titles) > 1 {
  171. lastPart = titles[len(titles)-1]
  172. if lastPart == city || lastPart == area || lastPart == district {
  173. title = strings.Join(titles[:len(titles)-1], splitStr)
  174. } else {
  175. lastPart = ""
  176. }
  177. }
  178. if len([]rune(title)) > 50 {
  179. title = fmt.Sprintf(titleSuffix, string([]rune(title)[:50]))
  180. }
  181. if lastPart != "" {
  182. title = fmt.Sprintf("%s%s%s", title, splitStr, lastPart)
  183. }
  184. }
  185. publicType := MC.InterfaceToStr(rv["public_type"])
  186. if publicType == "平台发布" && rv["purchasinglist"] != nil {
  187. purchasingList := MC.ObjArrToMapArr(rv["purchasinglist"].([]interface{}))
  188. if len(purchasingList) > 1 {
  189. originalTitle = fmt.Sprintf(titleSuffix, originalTitle)
  190. }
  191. }
  192. regionUrl := ""
  193. if district != "" && IC.DistrictMap[district] != "" {
  194. regionUrl = fmt.Sprintf(AreaLabelLink, "city", IC.DistrictMap[district])
  195. } else if city != "" && IC.CityMap[city] != "" {
  196. regionUrl = fmt.Sprintf(AreaLabelLink, "city", IC.CityMap[city])
  197. } else if area != "" && IC.AreaMap[area] != "" {
  198. regionUrl = fmt.Sprintf(AreaLabelLink, "area", IC.AreaMap[area])
  199. }
  200. var price int64
  201. if budget, ok := rv["budget"].(float64); ok && budget > 0 { //预算
  202. price = int64(budget)
  203. }
  204. if bidAmount, ok := rv["bidamount"].(float64); ok && bidAmount > 0 { //中标金额
  205. price = int64(bidAmount)
  206. }
  207. //deliver_area 交付省份//deliver_city 交付城市//deliver_district 交付区县
  208. deliveryLoc := fmt.Sprintf("%s%s%s", MC.InterfaceToStr(rv["deliver_area"]), MC.InterfaceToStr(rv["deliver_city"]), MC.InterfaceToStr(rv["deliver_district"]))
  209. buyer := noPower
  210. buyerTel := noPower
  211. if p.IsPower {
  212. buyer = MC.InterfaceToStr(rv["buyer"])
  213. buyerTel = MC.InterfaceToStr(rv["buyertel"])
  214. }
  215. isValidFile, _ := rv["isValidFile"].(bool)
  216. //buyerPerson := MC.InterfaceToStr(rv["buyerperson"])
  217. //agency := MC.InterfaceToStr(rv["agency"])
  218. //agencyTel := MC.InterfaceToStr(rv["agencytel"])
  219. //agencyPerson := MC.InterfaceToStr(rv["agencyperson"])
  220. //中标信息
  221. var winnerInfo []*bxcore.WinnerInfo
  222. winnerList := MC.ObjToString(rv["s_winner"]) //中标企业名称集合
  223. if winnerList != "" && len(strings.Split(winnerList, ",")) > 0 {
  224. var isExists = map[string]bool{}
  225. for wk, wv := range strings.Split(winnerList, ",") {
  226. var (
  227. winnerId = ""
  228. )
  229. if rv["entidlist"] != nil {
  230. if entIdList := MC.ObjArrToStringArr(rv["entidlist"].([]interface{})); len(entIdList) > wk { //中标企业id集合
  231. winnerId = entIdList[wk]
  232. }
  233. }
  234. if IC.C.SearchWinner.Switch && winnerId == "" {
  235. continue
  236. }
  237. if entity.RegWinner.MatchString(wv) {
  238. continue
  239. }
  240. if isExists[wv] {
  241. continue
  242. }
  243. isExists[wv] = true
  244. winnerInfo = append(winnerInfo, &bxcore.WinnerInfo{
  245. Winner: wv, //中标企业 需要单独处理
  246. WinnerTel: MC.ObjToString(rv["winnertel"]), //中标企业联系电话
  247. WinnerPerson: MC.ObjToString(rv["winnerperson"]), //中标企业联系人
  248. WinnerId: MC.If(winnerId != "" && len([]rune(winnerId)) > 12, encrypt.EncodeArticleId2ByCheck(winnerId), "").(string), //中标企业加密id 存在winnerId 异常的情况
  249. })
  250. }
  251. }
  252. list = append(list, &bxcore.PurchaseList{
  253. Id: encrypt.EncodeArticleId2ByCheck(id),
  254. Area: MC.InterfaceToStr(rv["area"]),
  255. City: MC.InterfaceToStr(rv["city"]),
  256. District: MC.InterfaceToStr(rv["district"]),
  257. RegionUrl: regionUrl,
  258. BuyerClass: MC.InterfaceToStr(rv["buyerclass"]),
  259. PublishTime: MC.Int64All(rv["publishtime"]),
  260. FileExists: isValidFile,
  261. Title: title,
  262. Price: price,
  263. Buyer: buyer,
  264. BuyerTel: buyerTel,
  265. SignEndTime: MC.Int64All(rv["signendtime"]), //报名截止时间
  266. DeliveryLoc: deliveryLoc,
  267. Industry: util.IndustryFormat(p.Industry, strings.Trim(MC.ObjToString(rv["s_subscopeclass"]), ",")),
  268. PublicType: MC.InterfaceToStr(rv["public_type"]),
  269. IsNew: MC.Int64All(rv["is_yg_new"]), //is_yg_new==1 新的网站来源
  270. OriginalTitle: originalTitle,
  271. //BuyerPerson: buyerPerson,
  272. //Agency: agency,
  273. //AgencyTel: agencyTel,
  274. //AgencyPerson: agencyPerson,
  275. //WinnerInfo: winnerInfo,
  276. //BidEndTime: MC.Int64All(rv["bidendtime"]),
  277. //BidOpenTime: MC.Int64All(rv["bidopentime"]), //开标时间,
  278. })
  279. }
  280. return
  281. }
  282. func (p *Purchase) PurchaseQuery() (query string) {
  283. var (
  284. wordsMusts, wordsShould, must, mustNot []string
  285. selectTypeArr = strings.Split(p.SelectType, ",")
  286. selectType = fmt.Sprintf(`"%s"`, strings.Join(selectTypeArr, "\",\""))
  287. )
  288. //发布时间
  289. if len(strings.Split(p.PublishTime, "-")) > 1 {
  290. var (
  291. timeQuery string
  292. startTime, endTime = strings.Split(p.PublishTime, "-")[0], strings.Split(p.PublishTime, "-")[1]
  293. )
  294. if startTime != "" || endTime != "" {
  295. timeQuery += `{"range":{"publishtime":{`
  296. if startTime != "" {
  297. timeQuery += `"gte":` + startTime
  298. }
  299. if startTime != "" && endTime != "" {
  300. timeQuery += `,`
  301. }
  302. if endTime != "" {
  303. timeQuery += `"lt":` + endTime
  304. }
  305. timeQuery += `}}}`
  306. }
  307. if timeQuery != "" {
  308. must = append(must, timeQuery)
  309. }
  310. }
  311. // 关键词
  312. if p.KeyWords != "" {
  313. var (
  314. keyWordsMusts []string
  315. )
  316. for _, v := range strings.Split(p.KeyWords, IC.C.JYKeyMark) {
  317. if elastic.ReplaceYH(v) == "" {
  318. continue
  319. }
  320. keyWordsMusts = append(keyWordsMusts, fmt.Sprintf(fmt.Sprintf(es.MultiMatch, "%s", selectType), elastic.ReplaceYH(v)))
  321. }
  322. //搜索关键词模式;默认0:包含所有,1:包含任意
  323. if p.WordsMode == 1 {
  324. wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(keyWordsMusts, ",")))
  325. } else {
  326. wordsMusts = append(wordsMusts, keyWordsMusts...)
  327. }
  328. }
  329. //附加词
  330. if p.AdditionalWords != "" {
  331. for _, aws := range strings.Split(p.AdditionalWords, ",") {
  332. //多组附加词,每组间,号隔开。每组内如果关键词中间有空格,自动分词
  333. var (
  334. addWordsMusts []string
  335. )
  336. for _, v := range strings.Split(aws, IC.C.JYKeyMark) {
  337. if elastic.ReplaceYH(v) == "" {
  338. continue
  339. }
  340. addWordsStr := fmt.Sprintf(fmt.Sprintf(es.MultiMatch, "%s", selectType), elastic.ReplaceYH(v))
  341. if p.WordsMode == 0 {
  342. wordsMusts = append(wordsMusts, addWordsStr)
  343. } else {
  344. addWordsMusts = append(addWordsMusts, addWordsStr)
  345. }
  346. }
  347. //搜索关键词模式;默认0:包含所有,1:包含任意
  348. if len(addWordsMusts) > 0 {
  349. wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(addWordsMusts, ",")))
  350. }
  351. }
  352. }
  353. //搜索关键词模式;默认0:包含所有,1:包含任意
  354. //包含任意一组
  355. if len(wordsShould) > 0 {
  356. must = append(must, fmt.Sprintf(es.QueryBoolShould, strings.Join(wordsShould, ",")))
  357. } else if len(wordsMusts) > 0 {
  358. must = append(must, fmt.Sprintf(elastic.NgramMust, strings.Join(wordsMusts, ",")))
  359. }
  360. //行业
  361. if p.Industry != "" {
  362. must = append(must, fmt.Sprintf(es.QueryBoolMustA, "s_subscopeclass", `"`+strings.ReplaceAll(p.Industry, ",", `","`)+`"`))
  363. }
  364. //附件
  365. if p.FileExists != 0 {
  366. switch p.FileExists {
  367. case 1: //有附件
  368. must = append(must, fmt.Sprintf(es.QueryBoolMustTermBool, "isValidFile", true))
  369. case -1: //无附件
  370. mustNot = append(mustNot, fmt.Sprintf(es.QueryBoolMustTermBool, "isValidFile", true))
  371. }
  372. }
  373. //项目地区
  374. var (
  375. areaQuery []string
  376. areaTerms = `{"terms":{"%s":["%s"]}}`
  377. )
  378. if p.ProjectArea != "" {
  379. areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "area", strings.ReplaceAll(p.ProjectArea, ",", "\",\"")))
  380. }
  381. if p.ProjectCity != "" {
  382. areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "city", strings.ReplaceAll(p.ProjectCity, ",", "\",\"")))
  383. }
  384. if p.ProjectDistrict != "" {
  385. for _, v := range strings.Split(p.ProjectDistrict, ",") {
  386. if len(strings.Split(v, "_")) > 1 {
  387. cityName := strings.Split(v, "_")[0]
  388. districtName := strings.Split(v, "_")[1]
  389. queryBoolMustAndDistrict := `{"bool":{"must":[{"terms":{"city":["%s"]}},{"terms":{"district":["%s"]}}]}}`
  390. areaQuery = append(areaQuery, fmt.Sprintf(queryBoolMustAndDistrict, cityName, districtName))
  391. }
  392. }
  393. }
  394. if len(areaQuery) > 0 {
  395. must = append(must, fmt.Sprintf(es.QueryBoolShould, strings.Join(areaQuery, ",")))
  396. }
  397. //交付地点
  398. areaQuery = []string{}
  399. if p.DeliveryArea != "" {
  400. areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "deliver_area", strings.ReplaceAll(p.DeliveryArea, ",", "\",\"")))
  401. }
  402. if p.DeliveryCity != "" {
  403. areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "deliver_city", strings.ReplaceAll(p.DeliveryCity, ",", "\",\"")))
  404. }
  405. if p.DeliveryDistrict != "" {
  406. for _, v := range strings.Split(p.DeliveryDistrict, ",") {
  407. if len(strings.Split(v, "_")) > 1 {
  408. cityName := strings.Split(v, "_")[0]
  409. districtName := strings.Split(v, "_")[1]
  410. queryBoolMustAndDistrict := `{"bool":{"must":[{"terms":{"deliver_city":["%s"]}},{"terms":{"deliver_district":["%s"]}}]}}`
  411. areaQuery = append(areaQuery, fmt.Sprintf(queryBoolMustAndDistrict, cityName, districtName))
  412. }
  413. }
  414. }
  415. if len(areaQuery) > 0 {
  416. must = append(must, fmt.Sprintf(es.QueryBoolShould, strings.Join(areaQuery, ",")))
  417. }
  418. //发布方式
  419. if p.Publisher > 0 {
  420. must = append(must, fmt.Sprintf(es.QueryBoolMustTerm, "public_type", es.PurchasePublicType[p.Publisher-1]))
  421. }
  422. //截止时间
  423. if p.DeadlineStart > 0 || p.DeadlineEnd > 0 {
  424. var timeQuery string
  425. timeQuery += `{"range":{"signendtime":{`
  426. if p.DeadlineStart > 0 {
  427. timeQuery += fmt.Sprintf(`"gte":%d`, p.DeadlineStart)
  428. }
  429. if p.DeadlineStart > 0 && p.DeadlineEnd > 0 {
  430. timeQuery += `,`
  431. }
  432. if p.DeadlineEnd > 0 {
  433. timeQuery += fmt.Sprintf(`"lt":%d`, p.DeadlineEnd)
  434. }
  435. timeQuery += `}}}`
  436. must = append(must, timeQuery)
  437. }
  438. //领域
  439. areaQuery = []string{}
  440. if p.DomainFirstType != "" {
  441. areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "domain_firsttype", strings.ReplaceAll(p.DomainFirstType, ",", "\",\"")))
  442. }
  443. if p.DomainSecondType != "" {
  444. areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "domain_secondtype", strings.ReplaceAll(p.DomainSecondType, ",", "\",\"")))
  445. }
  446. if p.DomainThirdType != "" {
  447. areaQuery = append(areaQuery, fmt.Sprintf(areaTerms, "domain_thirdtype", strings.ReplaceAll(p.DomainThirdType, ",", "\",\"")))
  448. }
  449. if len(areaQuery) > 0 {
  450. must = append(must, fmt.Sprintf(es.QueryBoolShould, strings.Join(areaQuery, ",")))
  451. }
  452. //直采 采购信息 搜索
  453. query = fmt.Sprintf(es.Query, strings.Join(must, ","), strings.Join(mustNot, ","))
  454. log.Println("zc-query:", query)
  455. return
  456. }
  457. func (p *Purchase) FindDataFromES() (int64, []map[string]interface{}, error) {
  458. var (
  459. start = int((p.PageNum - 1) * p.PageSize)
  460. total int64
  461. list *[]map[string]interface{}
  462. err error
  463. fields = es.PurchaseBaseFieldForPayer
  464. )
  465. if IC.C.PurchaseDiffSwitch {
  466. if !p.IsPay {
  467. fields = es.PurchaseBaseField
  468. }
  469. }
  470. biddingSearch := es.SearchByES{
  471. Index: es.PurchaseIndex,
  472. IType: es.PurchaseType,
  473. Query: p.PurchaseQuery(),
  474. FindFields: p.SelectType,
  475. Order: es.PurchaseSearchSort,
  476. Fields: fields,
  477. Start: start,
  478. Limit: int(p.PageSize),
  479. Count: 0, //高亮正文数量
  480. HighLight: false, //是否高亮正文
  481. }
  482. total, list = biddingSearch.GetAllByNgramWithCount(es.LoginTypePay)
  483. if total == 0 || list == nil {
  484. log.Println(fmt.Errorf("暂无数据"))
  485. return 0, nil, nil
  486. }
  487. return total, *list, err
  488. }
  489. var (
  490. redisCode = "newother"
  491. purchaseDataCacheKey = "purchase_cache_data"
  492. purchaseCountCacheKey = "purchase_cache_count"
  493. purchaseCacheExpire = 8 * 60 * 60
  494. )
  495. func (p *Purchase) GetPurchaseCount() (count int64) {
  496. count, _, _ = p.FindDataFromES()
  497. return
  498. }
  499. // 数据
  500. func (p *Purchase) GetPurchaseData() (list []*bxcore.PurchaseList, err error) {
  501. var (
  502. res []map[string]interface{}
  503. total int64
  504. )
  505. if p.IsEmptySearch() {
  506. //查缓存
  507. cacheBytes, err := redis.GetBytes(redisCode, purchaseDataCacheKey)
  508. start := int((p.PageNum - 1) * p.PageSize)
  509. end := int(p.PageNum * p.PageSize)
  510. if err == nil && len(*cacheBytes) > start {
  511. if end > len(*cacheBytes) {
  512. end = len(*cacheBytes)
  513. }
  514. total = int64(redis.GetInt(redisCode, purchaseCountCacheKey))
  515. err = json.Unmarshal(*cacheBytes, &res)
  516. }
  517. if len(res) == 0 {
  518. p.PageNum = 1
  519. pageSize := p.PageSize
  520. start = int((p.PageNum - 1) * p.PageSize)
  521. p.PageSize = int64(util.SearchPageSize * util.SearchMaxPageNum)
  522. total, res, err = p.FindDataFromES()
  523. if total > 0 && len(res) > 0 {
  524. var b []byte
  525. b, err = json.Marshal(res)
  526. if err == nil && len(b) > 0 {
  527. err = redis.PutBytes(redisCode, purchaseDataCacheKey, &b, purchaseCacheExpire)
  528. redis.Put(redisCode, purchaseCountCacheKey, total, purchaseCacheExpire)
  529. }
  530. if end > len(res) {
  531. end = len(res)
  532. }
  533. }
  534. p.PageSize = pageSize
  535. }
  536. res = res[start:end]
  537. } else {
  538. //实时查询
  539. total, res, err = p.FindDataFromES()
  540. }
  541. if len(res) > 0 {
  542. p.Total = total
  543. p.Count = int64(util.SearchPageSize * util.SearchMaxPageNum)
  544. if p.Count > total {
  545. p.Count = total
  546. }
  547. list = p.PurchaseListFormat(res)
  548. }
  549. return
  550. }
  551. // 关键词 附加词 行业
  552. func (p *Purchase) IsEmptySearch() bool {
  553. if p.KeyWords != "" || p.AdditionalWords != "" || p.Industry != "" {
  554. return false
  555. }
  556. return true
  557. }
  558. var (
  559. purchaseSelectTypeMap = map[string]bool{
  560. "title": true,
  561. "purchasing": true,
  562. }
  563. tipMsg = "“%s“及其后面的字词均被忽略,因为剑鱼标讯的查询限制在%d个汉字以内。"
  564. )
  565. // 筛选条件格式化
  566. func (p *Purchase) FilterCriteriaFormat() {
  567. if p.UserId != "" {
  568. //判断用户身份
  569. userInfo := IC.Middleground.PowerCheckCenter.Check(p.AppId, p.MgoUserId, p.BaseUserId, p.AccountId, p.EntId, p.PositionType, p.PositionId)
  570. if userInfo != nil {
  571. p.IsPay = !userInfo.Free.IsFree
  572. }
  573. res := IC.Middleground.ResourceCenter.Haspowers(p.AccountId, p.EntAccountId, p.EntId, p.EntUserId)
  574. if res != nil {
  575. p.IsPower = strings.Contains(strings.Join(res.Powers, ","), IC.C.PurchaseCode)
  576. }
  577. }
  578. //搜索范围
  579. if p.SelectType != "" {
  580. var selectTypes []string
  581. for _, sv := range strings.Split(p.SelectType, ",") {
  582. if purchaseSelectTypeMap[sv] {
  583. selectTypes = append(selectTypes, sv)
  584. }
  585. }
  586. if len(selectTypes) > 0 {
  587. p.SelectType = strings.Join(selectTypes, ",")
  588. }
  589. }
  590. if p.SelectType == "" {
  591. p.SelectType = "title"
  592. }
  593. // p.SearchMode 搜索模式:0:精准搜索;1:模糊搜索
  594. // 精准搜索:不分词,完全匹配;(中间带空格的关键词组自动分词)
  595. // 模糊搜索:对用户输入的单个关键词进行分词处理,但必须都存在;
  596. if p.SearchMode < 0 || p.SearchMode > 1 {
  597. p.SearchMode = 0
  598. }
  599. // p.WordsMode 搜索关键词模式;默认0:包含所有,1:包含任意
  600. if p.WordsMode < 0 || p.WordsMode > 1 {
  601. p.WordsMode = 0
  602. }
  603. //发布时间--默认最近一年
  604. if p.PublishTime == "" {
  605. p.PublishTime = fmt.Sprintf("%d-%d", time.Now().AddDate(-1, 0, 0).Unix(), time.Now().Unix())
  606. }
  607. //默认每页数据量
  608. if p.PageSize <= 0 || p.PageSize > 100 {
  609. p.PageSize = 50
  610. }
  611. //第一页
  612. if p.PageNum <= 0 || p.PageNum > int64(IC.C.DefaultBidInfo.Count)/p.PageSize {
  613. p.PageNum = 1
  614. }
  615. //行业
  616. if p.Industry != "" {
  617. p.Industry = strings.TrimSpace(p.Industry)
  618. //P510 行业:其它
  619. if qt := jy.IndustryHandle(p.Industry); len(qt) > 0 {
  620. p.Industry = fmt.Sprintf("%s,%s", p.Industry, strings.Join(qt, ","))
  621. }
  622. }
  623. var (
  624. searchWords []string
  625. )
  626. //关键词
  627. if p.KeyWords != "" {
  628. p.KeyWords = strings.TrimSpace(p.KeyWords)
  629. p.InterceptKeyWords, p.TipMsg, p.KeyWords = util.InterceptSearchKW(p.KeyWords, MC.IntAllDef(IC.C.KeywordsLimit, 35), true)
  630. //if p.TipMsg != "" {
  631. // p.TipMsg = fmt.Sprintf(tipMsg, p.TipMsg, MC.IntAllDef(IC.C.KeywordsLimit, 35))
  632. //}
  633. // in.SearchMode 搜索模式:0:精准搜索;1:模糊搜索
  634. // 精准搜索:不分词,完全匹配;(中间带空格的关键词组自动分词)
  635. // 模糊搜索:对用户输入的单个关键词进行分词处理,但必须都存在;
  636. //主关键词词组
  637. if p.SearchMode == 1 {
  638. if ikWords := util.HttpEs(p.KeyWords, "ik_smart", IC.DB.Es.Addr); ikWords != "" {
  639. p.KeyWords = jy.KeywordsProcessing(ikWords, p.KeyWords, IC.C.JYKeyMark)
  640. }
  641. }
  642. searchWords = append(searchWords, p.KeyWords)
  643. }
  644. //附加词 每组附加词不能超过15个字符
  645. if p.AdditionalWords != "" {
  646. var additionalWords []string
  647. for _, ak := range strings.Split(p.AdditionalWords, ",") {
  648. if len([]rune(ak)) > 15 {
  649. additionalWords = append(additionalWords, string([]rune(ak)[:15]))
  650. } else {
  651. additionalWords = append(additionalWords, ak)
  652. }
  653. }
  654. p.AdditionalWords = strings.Join(additionalWords, ",") //分组不变
  655. //多组附加词,每组间,号隔开。每组内如果关键词中间有空格,自动分词
  656. if p.SearchMode == 1 {
  657. var (
  658. addWords []string
  659. )
  660. for _, awv := range strings.Split(p.AdditionalWords, ",") {
  661. if strings.TrimSpace(awv) != "" {
  662. if ikWords := util.HttpEs(awv, "ik_smart", IC.DB.Es.Addr); ikWords != "" {
  663. addWords = append(addWords, jy.KeywordsProcessing(ikWords, awv, IC.C.JYKeyMark))
  664. }
  665. }
  666. }
  667. if len(addWords) > 0 {
  668. p.AdditionalWords = strings.Join(addWords, ",")
  669. }
  670. }
  671. searchWords = append(searchWords, strings.Split(p.AdditionalWords, ",")...)
  672. }
  673. p.HighlightWords = strings.Join(searchWords, " ")
  674. //报名截止
  675. if p.DeadlineStatus < 0 || p.DeadlineStatus > 2 {
  676. p.DeadlineStatus = 0
  677. }
  678. if len(strings.Split(p.DeadlineTime, "-")) > 1 {
  679. p.DeadlineStart, _ = strconv.ParseInt(strings.Split(p.DeadlineTime, "-")[0], 10, 64)
  680. p.DeadlineEnd, _ = strconv.ParseInt(strings.Split(p.DeadlineTime, "-")[1], 10, 64)
  681. if p.DeadlineEnd < p.DeadlineStart {
  682. var deadline = p.DeadlineStart
  683. p.DeadlineStart = p.DeadlineEnd
  684. p.DeadlineEnd = deadline
  685. }
  686. }
  687. switch p.DeadlineStatus {
  688. case 1: //未截止
  689. if p.DeadlineEnd < time.Now().Unix() {
  690. p.DeadlineStart = time.Now().Unix()
  691. p.DeadlineEnd = 0
  692. }
  693. case 2: //已截止
  694. if p.DeadlineEnd == 0 || p.DeadlineEnd > time.Now().Unix() {
  695. p.DeadlineStart = 0
  696. p.DeadlineEnd = time.Now().Unix()
  697. }
  698. }
  699. //发布平台
  700. if p.Publisher < 0 || p.Publisher > int64(len(es.PurchasePublicType)) {
  701. p.Publisher = 0
  702. }
  703. //空搜索 其它筛选条件 无效
  704. if p.IsEmptySearch() {
  705. //
  706. p.DomainFirstType = ""
  707. p.DomainSecondType = ""
  708. p.DomainThirdType = ""
  709. p.DeadlineStatus = 0
  710. p.DeadlineStart = 0
  711. p.DeadlineEnd = 0
  712. p.DeliveryArea = ""
  713. p.DeliveryCity = ""
  714. p.DeliveryDistrict = ""
  715. p.ProjectArea = ""
  716. p.ProjectCity = ""
  717. p.ProjectDistrict = ""
  718. p.FileExists = 0
  719. p.Publisher = 0
  720. }
  721. }