buyerListBYEs.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. package model
  2. import (
  3. "app.yhyue.com/moapp/jybase/redis"
  4. "encoding/json"
  5. "fmt"
  6. IC "jyBXBuyer/rpc/init"
  7. "jyBXBuyer/rpc/type/bxbuyer"
  8. "log"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. "time"
  13. MC "app.yhyue.com/moapp/jybase/common"
  14. "app.yhyue.com/moapp/jybase/encrypt"
  15. elastic "app.yhyue.com/moapp/jybase/es"
  16. "github.com/zeromicro/go-zero/core/logx"
  17. )
  18. const (
  19. HasContact = 1 // 采购单位是否有联系方式筛选项 1-有联系方式
  20. NoContact = 2 // 无联系方式
  21. )
  22. type BScope struct {
  23. Keyword []string `json:"keyword"`
  24. AdditionalWords []string `json:"additionalWords"`
  25. ExcludedWords []string `json:"excludedWords"`
  26. }
  27. type supplyDataStruct struct {
  28. ProjectCount int64
  29. BidCount int64
  30. BidAmountCount float32
  31. ContactCount int64
  32. }
  33. // 获取采购单位查询query
  34. func BuyerListQuery(in *bxbuyer.BuyerListReq) (qstr string, CountQstr string) {
  35. query := `{%s "query":{"bool":{"must":[%s],"must_not": [{"term": {"buyer_name": ""}}],"should":[%s],"minimum_should_match": %d}} %s}`
  36. //21.1.20 为和画像保持一致 数据组要求 budget 改成 bidamount
  37. query_bool_should := `{"bool":{"should":[%s],"minimum_should_match": 1}}`
  38. sort := ""
  39. bools := []string{}
  40. musts := []string{}
  41. musts_should := []string{}
  42. //省份
  43. if len(in.Province) > 0 {
  44. musts_should = append(musts_should, fmt.Sprintf(`{"terms":{"province":["%s"]}}`, strings.Join(in.Province, "\",\"")))
  45. }
  46. //城市
  47. if len(in.City) > 0 {
  48. musts_should = append(musts_should, fmt.Sprintf(`{"terms":{"city":["%s"]}}`, strings.Join(in.City, "\",\"")))
  49. }
  50. if len(musts_should) > 0 {
  51. musts = append(musts, fmt.Sprintf(query_bool_should, strings.Join(musts_should, ",")))
  52. }
  53. //采购单位名称
  54. if in.BuyerName != "" {
  55. entNameQuery := fmt.Sprintf(`{"multi_match": {"query": "%s","type": "phrase", "fields": ["name"]}}`, in.BuyerName)
  56. musts = append(musts, entNameQuery)
  57. } else {
  58. sort = `,"sort":[{"updatetime":"desc"}]` // 仅无关键词时再
  59. }
  60. //采购单位类型
  61. buyerclass := in.BuyerClass
  62. if len(buyerclass) > 0 {
  63. Buyerclass := `{"terms":{"buyerclass":[`
  64. for k, v := range buyerclass {
  65. if k > 0 {
  66. Buyerclass += `,`
  67. }
  68. Buyerclass += `"` + v + `"`
  69. }
  70. Buyerclass += `]}}`
  71. musts = append(musts, Buyerclass)
  72. }
  73. // 采购单位联系方式 0-不限 1-有联系人 2-无联系人
  74. if in.IsContact != 0 {
  75. isContact := MC.If(in.IsContact == int64(HasContact), true, false)
  76. isContactStr := `{"term":{"is_contact":` + fmt.Sprint(isContact) + `}}`
  77. musts = append(musts, isContactStr)
  78. }
  79. boolsNum := 0
  80. qstr = fmt.Sprintf(query, fmt.Sprintf(`"from":%d,"size": %d,`, (in.PageNum-1)*in.PageSize, in.PageSize), strings.Join(musts, ","), strings.Join(bools, ","), boolsNum, sort)
  81. CountQstr = fmt.Sprintf(query, "", strings.Join(musts, ","), strings.Join(bools, ","), boolsNum, "")
  82. return
  83. }
  84. // 采购单位补充采购规模、项目数量、招标动态数量
  85. func SupplyDataQuery(buyerList []string) (query string) {
  86. // 查近两年的数据 因为bigmember BuyerMiniPortrait 查的默认是两年
  87. q := `{"size":0,"query": { "bool": { "must": [ {"terms": { "buyer": ["` + strings.Join(buyerList, "\",\"") + `"] }},{"range": {"jgtime": {"gte": %d,"lt": %d} }} ]}}, "aggs": { "buyerBuckets": {"terms": {"field": "buyer"
  88. },"aggs": {"bidAmountCount": {"sum": {"field": "bidamount"}}}}}}`
  89. start, end := getTimeRange()
  90. return fmt.Sprintf(q, start.Unix(), end.Unix())
  91. }
  92. func getTimeRange() (st, et time.Time) {
  93. now := time.Now()
  94. eYear := now.Year()
  95. sYear := now.Year() - 2
  96. //返回默认时间
  97. sTimeStamp := time.Date(sYear, 1, 1, 0, 0, 0, 0, time.Local)
  98. eTimeStamp := time.Date(eYear, now.Month(), now.Day(), now.Hour(), now.Minute(), 0, 0, time.Local)
  99. return sTimeStamp, eTimeStamp
  100. }
  101. const (
  102. P_INDEX = "projectset"
  103. P_TYPE = "projectset"
  104. P_redis_time = 7 * 24 * 60 * 60 //redis存7天
  105. P_redis_key = "buyerListCache" // 存缓存 100条数据
  106. BuyerIndex = "buyer" // 采购单位index
  107. BuyerType = "buyer"
  108. biddingIndex = "bidding"
  109. biddingType = "bidding"
  110. BuyerSupplyInfoRedisKey = "BuyerSupplyInfo_%s" // 采购单位补充信息缓存
  111. BuyerSupplyInfoRedisTime = 2 * 60 * 60 // 采购单位补充信息缓存时间 一个小时
  112. BuyerProjectInfoRedisKey = "BuyerProjectInfo_%s" // 采购单位补充项目信息缓存Key (项目数量采购规模)
  113. BuyerProjectInfoRedisTime = 24 * 60 * 60 // 采购单位补充项目信息缓存时间
  114. )
  115. // GetBuyerList 查询采购单位列表
  116. func GetBuyerList(qstr string, CountQuery string, isCache bool) (buyerNames []string, resp *bxbuyer.BuyerListResp) {
  117. t1 := time.Now()
  118. total := elastic.Count(BuyerIndex, BuyerType, CountQuery) // 总数
  119. logx.Info("耗时1:", time.Since(t1))
  120. resp = &bxbuyer.BuyerListResp{
  121. Data: &bxbuyer.BuyerData{
  122. Count: total,
  123. List: []*bxbuyer.BuyerList{},
  124. },
  125. }
  126. if total == 0 {
  127. return
  128. }
  129. start := time.Now()
  130. rs := elastic.Get(BuyerIndex, BuyerType, qstr) // 采购单位列表
  131. logx.Info("采购单位列表 es get查询耗时", time.Since(start))
  132. if rs == nil || len(*rs) == 0 {
  133. return
  134. }
  135. for i := 0; i < len(*rs); i++ {
  136. tmp := &bxbuyer.BuyerList{
  137. SeoId: MC.ObjToString((*rs)[i]["seo_id"]),
  138. Buyer: MC.ObjToString((*rs)[i]["name"]),
  139. Province: MC.ObjToString((*rs)[i]["province"]),
  140. City: MC.ObjToString((*rs)[i]["city"]),
  141. BuyerClass: MC.ObjToString((*rs)[i]["buyerclass"]),
  142. }
  143. buyerNames = append(buyerNames, tmp.Buyer)
  144. resp.Data.List = append(resp.Data.List, tmp)
  145. }
  146. logx.Info("耗时;", time.Since(t1).Seconds(), "秒--", time.Since(t1).Microseconds())
  147. return
  148. }
  149. // BuyerListRedisCache 空搜索 1.查询项目数量最多的前200个 2.然后 再查buyer里确认数据有效 100个 3.项目数量和采购规模单独存缓存 1天
  150. //
  151. // func BuyerListRedisCache(query string, in *bxbuyer.BuyerListReq) (buyerNames []string, resp *bxbuyer.BuyerListResp) {
  152. // //获取缓存数据
  153. // resp = &bxbuyer.BuyerListResp{
  154. // Data: &bxbuyer.BuyerData{
  155. // List: []*bxbuyer.BuyerList{},
  156. // },
  157. // }
  158. // t1 := time.Now()
  159. // logx.Info("耗时1:", time.Since(t1))
  160. // aggs := GetAggs(P_INDEX, P_TYPE, query)
  161. // logx.Info("查询语句:", query)
  162. // logx.Info("BuyerListRedisCache:", time.Since(t1))
  163. // type BuyerAggStruct struct {
  164. // Buckets []struct {
  165. // Key string `json:"key,omitempty"`
  166. // Doc_count int64 `json:"doc_count,omitempty"`
  167. // BidAmountCount struct {
  168. // Value float32 `json:"value,omitempty"`
  169. // } `json:"bidAmountCount"`
  170. // } `json:"buckets"`
  171. // }
  172. // var buyerBuckets = BuyerAggStruct{}
  173. // saveBuyerList := []*bxbuyer.BuyerList{} //100条数据 最后存起来
  174. // // 处理成map 用于后面格式化数据
  175. // if aggs == nil || aggs["buyerBuckets"] == nil {
  176. // return
  177. // }
  178. // bs, err := aggs["buyerBuckets"].MarshalJSON()
  179. // if err != nil {
  180. // resp.ErrCode = -1
  181. // resp.ErrMsg = "获取数据异常"
  182. // return
  183. // }
  184. // if len(bs) == 0 {
  185. // resp.ErrMsg = "暂无数据"
  186. // return
  187. // }
  188. // err = json.Unmarshal(bs, &buyerBuckets)
  189. // if err != nil || len(buyerBuckets.Buckets) == 0 {
  190. // resp.ErrMsg = "暂无数据"
  191. // return
  192. // }
  193. // for i := 0; i < len(buyerBuckets.Buckets); i++ {
  194. // if len(saveBuyerList) == int(IC.C.BuyerSearchLimit) {
  195. // break
  196. // }
  197. // // 查buyer 确认数据存在 补充 buyerclass 省份 城市信息
  198. // rs := GetBuyer(buyerBuckets.Buckets[i].Key)
  199. // if rs != nil && len(*rs) > 0 { // 存在 则追加
  200. // tmpBuyerInfo := (*rs)[0]
  201. // buyerInfo := &bxbuyer.BuyerList{
  202. // Buyer: buyerBuckets.Buckets[i].Key,
  203. // Province: MC.ObjToString(tmpBuyerInfo["province"]),
  204. // City: MC.ObjToString(tmpBuyerInfo["city"]),
  205. // BuyerClass: MC.ObjToString(tmpBuyerInfo["buyerclass"]),
  206. // }
  207. // saveBuyerList = append(saveBuyerList, buyerInfo)
  208. // buyerNames = append(buyerNames, buyerInfo.Buyer)
  209. // // 项目数量和采购规模存缓存 1天
  210. // projectCacheData := supplyDataStruct{
  211. // ProjectCount: buyerBuckets.Buckets[i].Doc_count,
  212. // BidAmountCount: buyerBuckets.Buckets[i].BidAmountCount.Value,
  213. // }
  214. // go func(buyer string, data supplyDataStruct) {
  215. // b, err := json.Marshal(data)
  216. // if err == nil {
  217. // redis.PutBytes("other", fmt.Sprintf(BuyerProjectInfoRedisKey, buyer), &b, BuyerProjectInfoRedisTime+GetRand(60))
  218. // }
  219. // }(buyerBuckets.Buckets[i].Key, projectCacheData)
  220. //
  221. // }
  222. // }
  223. // if len(saveBuyerList) > 0 {
  224. // // 100 列表存redis 7天
  225. // go func(data []*bxbuyer.BuyerList) {
  226. // b, err := json.Marshal(data)
  227. // if err == nil {
  228. // redis.PutBytes("other", fmt.Sprintf(P_redis_key), &b, P_redis_time)
  229. // }
  230. // }(saveBuyerList)
  231. // } else {
  232. // return
  233. // }
  234. //
  235. // // 根据页码返回数据
  236. // start := in.PageSize * (in.PageNum - 1)
  237. // end := in.PageSize * in.PageNum
  238. // resp.Data.Count = int64(len(saveBuyerList))
  239. // if end > int64(len(saveBuyerList)-1) {
  240. // end = int64(len(saveBuyerList) - 1)
  241. // }
  242. // resp.Data.List = saveBuyerList[start:end]
  243. // return
  244. // }
  245. func BuyerListRedisCache(query string, in *bxbuyer.BuyerListReq) (buyerNames []string, resp *bxbuyer.BuyerListResp) {
  246. //获取缓存数据
  247. resp = &bxbuyer.BuyerListResp{
  248. Data: &bxbuyer.BuyerData{
  249. List: []*bxbuyer.BuyerList{},
  250. },
  251. }
  252. t1 := time.Now()
  253. rs := elastic.Get(BuyerIndex, BuyerType, query) // 采购单位列表
  254. logx.Info("空搜索采购单位列表 es get查询耗时", time.Since(t1))
  255. if rs == nil || len(*rs) == 0 {
  256. return
  257. }
  258. saveBuyerList := []*bxbuyer.BuyerList{} //最后缓存起来
  259. for i := 0; i < len(*rs); i++ {
  260. tmp := &bxbuyer.BuyerList{
  261. SeoId: MC.ObjToString((*rs)[i]["seo_id"]),
  262. Buyer: MC.ObjToString((*rs)[i]["name"]),
  263. Province: MC.ObjToString((*rs)[i]["province"]),
  264. City: MC.ObjToString((*rs)[i]["city"]),
  265. BuyerClass: MC.ObjToString((*rs)[i]["buyerclass"]),
  266. }
  267. buyerNames = append(buyerNames, tmp.Buyer)
  268. saveBuyerList = append(saveBuyerList, tmp)
  269. }
  270. if len(saveBuyerList) > 0 {
  271. // 100 列表存redis 7天
  272. go func(data []*bxbuyer.BuyerList) {
  273. b, err := json.Marshal(data)
  274. if err == nil {
  275. redis.PutBytes("other", fmt.Sprintf(P_redis_key), &b, P_redis_time)
  276. }
  277. }(saveBuyerList)
  278. } else {
  279. return
  280. }
  281. // 根据页码返回数据
  282. start := in.PageSize * (in.PageNum - 1)
  283. end := in.PageSize * in.PageNum
  284. resp.Data.Count = int64(len(saveBuyerList))
  285. if end > int64(len(saveBuyerList)) {
  286. end = int64(len(saveBuyerList))
  287. }
  288. resp.Data.List = saveBuyerList[start:end]
  289. logx.Info("空搜索整体耗时;", time.Since(t1).Seconds(), "秒--", time.Since(t1).Microseconds())
  290. return
  291. }
  292. // GetBuyer 查采购单位表 确认采购单位存在
  293. func GetBuyer(buyerName string) *[]map[string]interface{} {
  294. q := `{"size":1,"_source":["buyerclass","province","city"],"query":{"bool":{"must":[{"term":{"buyer_name":"%s"}}]}}}`
  295. rs := elastic.Get(BuyerIndex, BuyerType, fmt.Sprintf(q, buyerName))
  296. return rs
  297. }
  298. // SupplyFollowInfo 补充是否关注信息
  299. func SupplyFollowInfo(in *bxbuyer.BuyerListReq, buyerNames []string, resp *bxbuyer.BuyerListResp) *bxbuyer.BuyerListResp {
  300. //省份和城市 是否查询已关注信息 是否查询已领取信息
  301. //企业信用库qyxy_std 和es buyer库 查询省份和城市
  302. //客户领取
  303. t2 := time.Now()
  304. isRws := map[string]string{}
  305. if in.IsCheckReceive {
  306. isRws = IsReceived(buyerNames, in.EntUserId)
  307. }
  308. logx.Info("客户领取耗时:", time.Since(t2))
  309. //客户关注
  310. t3 := time.Now()
  311. isFws := map[string]bool{}
  312. if in.IsCheckFollow {
  313. isFws = IsFollowd(buyerNames, in.UserId)
  314. }
  315. logx.Info("采购单位关注耗时:", time.Since(t3))
  316. for _, bv := range resp.Data.List {
  317. if in.IsCheckReceive {
  318. if isRws[bv.Buyer] != "" {
  319. bv.IsReceived = true
  320. bv.RecId = isRws[bv.Buyer]
  321. }
  322. }
  323. if in.IsCheckFollow {
  324. if isFws[bv.Buyer] {
  325. bv.IsFollowed = true
  326. }
  327. }
  328. }
  329. return resp
  330. }
  331. // SupplyBuyerListData 补充字段 招标动态数量 项目数量 历史联系人数量 采购单位规模
  332. func SupplyBuyerListData(buyerNames []string, resp *bxbuyer.BuyerListResp) *bxbuyer.BuyerListResp {
  333. //buyerNames 是否存在缓存 数据
  334. //如果没有 放到一个新的 []string
  335. needSearchBuyer := []string{}
  336. cacheMap := map[string]supplyDataStruct{}
  337. for i := 0; i < len(buyerNames); i++ {
  338. bs, err := redis.GetBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, buyerNames[i]))
  339. if err == nil && bs != nil && len(*bs) > 0 {
  340. tmp := supplyDataStruct{}
  341. if err := json.Unmarshal(*bs, &tmp); err == nil {
  342. cacheMap[buyerNames[i]] = tmp // 拿到缓存的数据
  343. } else {
  344. needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查
  345. }
  346. } else {
  347. needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查
  348. }
  349. }
  350. start := time.Now()
  351. t1 := time.Now()
  352. buyerMap := map[string]supplyDataStruct{} // 聚合的数据
  353. if len(needSearchBuyer) > 0 {
  354. query := SupplyDataQuery(needSearchBuyer) // 项目数量、采购规模
  355. // 聚合查
  356. aggs := GetAggs(P_INDEX, P_TYPE, query)
  357. logx.Info("查询语句:", query)
  358. logx.Info("项目数量采购规模查询耗时:", time.Since(t1))
  359. type BuyerAggStruct struct {
  360. Buckets []struct {
  361. Key string `json:"key,omitempty"`
  362. Doc_count int64 `json:"doc_count,omitempty"`
  363. BidAmountCount struct {
  364. Value float32 `json:"value,omitempty"`
  365. } `json:"bidAmountCount"`
  366. } `json:"buckets"`
  367. }
  368. var buyerBuckets = BuyerAggStruct{}
  369. // 处理成map 用于后面格式化数据
  370. if aggs != nil && aggs["buyerBuckets"] != nil {
  371. bs, err := aggs["buyerBuckets"].MarshalJSON()
  372. if err != nil {
  373. resp.ErrCode = -1
  374. resp.ErrMsg = "获取数据异常"
  375. } else {
  376. if len(bs) == 0 {
  377. resp.ErrMsg = "暂无数据"
  378. } else {
  379. err := json.Unmarshal(bs, &buyerBuckets)
  380. logx.Info(err)
  381. if len(buyerBuckets.Buckets) > 0 {
  382. for _, v := range buyerBuckets.Buckets {
  383. buyerMap[v.Key] = supplyDataStruct{
  384. BidAmountCount: v.BidAmountCount.Value,
  385. ProjectCount: v.Doc_count,
  386. }
  387. }
  388. }
  389. }
  390. }
  391. }
  392. }
  393. ch := make(chan int, 10)
  394. ch2 := make(chan int, 10)
  395. wg := &sync.WaitGroup{}
  396. for i := 0; i < len(resp.Data.List); i++ {
  397. buyer := resp.Data.List[i].Buyer
  398. // 先查缓存
  399. if cacheData, ok := cacheMap[buyer]; ok {
  400. resp.Data.List[i].BidAmountCount = cacheData.BidAmountCount
  401. resp.Data.List[i].ProjectCount = cacheData.ProjectCount
  402. resp.Data.List[i].BiddingCount = cacheData.BidCount
  403. resp.Data.List[i].ContactCount = cacheData.ContactCount
  404. continue
  405. }
  406. // 缓存里没有的再查数据补充
  407. if supplyData, ok := buyerMap[buyer]; ok {
  408. resp.Data.List[i].BidAmountCount = supplyData.BidAmountCount
  409. resp.Data.List[i].ProjectCount = supplyData.ProjectCount
  410. }
  411. ch2 <- 1
  412. wg.Add(1)
  413. go func(list *bxbuyer.BuyerList, buyer string) {
  414. defer func() {
  415. <-ch2
  416. wg.Done()
  417. }()
  418. list.ContactCount = GetProjectContactCount(buyer) // 补充联系人字段
  419. }(resp.Data.List[i], buyer)
  420. ch <- 1
  421. wg.Add(1)
  422. go func(list *bxbuyer.BuyerList, buyer string) {
  423. defer func() {
  424. <-ch
  425. wg.Done()
  426. }()
  427. list.BiddingCount = GetNewBiddingCount(buyer)
  428. }(resp.Data.List[i], buyer)
  429. }
  430. wg.Wait()
  431. logx.Info("SupplyBuyerListData 整体耗时:", time.Since(start))
  432. //得到所有数据,包括 redis里的,再存一下
  433. go func(respList []*bxbuyer.BuyerList) {
  434. for i := 0; i < len(respList); i++ {
  435. tmp := supplyDataStruct{
  436. ContactCount: respList[i].ContactCount,
  437. BidCount: respList[i].BiddingCount,
  438. ProjectCount: respList[i].ProjectCount,
  439. BidAmountCount: respList[i].BidAmountCount,
  440. }
  441. // 存redis
  442. b, err := json.Marshal(tmp)
  443. if err == nil {
  444. redis.PutBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, respList[i].Buyer), &b, BuyerSupplyInfoRedisTime+GetRand(60))
  445. }
  446. }
  447. }(resp.Data.List)
  448. return resp
  449. }
  450. // 获取项目数量 采购单位规模
  451. func getBuyerProjectCache(buyer string) (rs *supplyDataStruct) {
  452. bs, err := redis.GetBytes("other", fmt.Sprintf(BuyerProjectInfoRedisKey, buyer))
  453. if err == nil && bs != nil && len(*bs) > 0 {
  454. if err := json.Unmarshal(*bs, &rs); err != nil {
  455. logx.Info("获取redis缓存,序列化异常")
  456. } else {
  457. return rs
  458. }
  459. }
  460. return
  461. }
  462. // BuyerSupplyInfo 补充字段
  463. func BuyerSupplyInfo(buyerNames []string) (resp *bxbuyer.BuyerSupplyResp) {
  464. resp = &bxbuyer.BuyerSupplyResp{}
  465. start := time.Now()
  466. // buyerNames
  467. //buyerNames 是否存在缓存 数据
  468. //如果没有 放到一个新的 []string
  469. needSearchBuyer := []string{}
  470. cacheMap := map[string]supplyDataStruct{}
  471. buyerMap := map[string]supplyDataStruct{}
  472. for i := 0; i < len(buyerNames); i++ {
  473. bs, err := redis.GetBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, buyerNames[i]))
  474. if err == nil && bs != nil && len(*bs) > 0 {
  475. tmp := supplyDataStruct{}
  476. if err := json.Unmarshal(*bs, &tmp); err == nil {
  477. cacheMap[buyerNames[i]] = tmp // 拿到缓存的数据 采购规模 项目数量 联系人数量 招标动态数量
  478. } else {
  479. // 查缓存
  480. cacheProject := getBuyerProjectCache(buyerNames[i])
  481. if cacheProject != nil {
  482. buyerMap[buyerNames[i]] = *cacheProject
  483. } else {
  484. needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查采购规模和项目数量
  485. }
  486. }
  487. } else {
  488. // 查缓存
  489. cacheProject := getBuyerProjectCache(buyerNames[i])
  490. if cacheProject != nil {
  491. buyerMap[buyerNames[i]] = *cacheProject
  492. } else {
  493. needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查采购规模和项目数量
  494. }
  495. }
  496. }
  497. if len(needSearchBuyer) > 0 {
  498. t1 := time.Now()
  499. query := SupplyDataQuery(buyerNames) // 项目数量、采购规模
  500. // 聚合查
  501. aggs := GetAggs(P_INDEX, P_TYPE, query)
  502. logx.Info("查询语句:", query)
  503. logx.Info("项目数量采购规模查询耗时:", time.Since(t1))
  504. type BuyerAggStruct struct {
  505. Buckets []struct {
  506. Key string `json:"key,omitempty"`
  507. Doc_count int64 `json:"doc_count,omitempty"`
  508. BidAmountCount struct {
  509. Value float32 `json:"value,omitempty"`
  510. } `json:"bidAmountCount"`
  511. } `json:"buckets"`
  512. }
  513. var buyerBuckets = BuyerAggStruct{}
  514. // 处理成map 用于后面格式化数据
  515. if aggs != nil && aggs["buyerBuckets"] != nil {
  516. bs, err := aggs["buyerBuckets"].MarshalJSON()
  517. if err != nil {
  518. resp.ErrCode = -1
  519. resp.ErrMsg = "获取数据异常"
  520. } else {
  521. if len(bs) == 0 {
  522. resp.ErrMsg = "暂无数据"
  523. } else {
  524. err := json.Unmarshal(bs, &buyerBuckets)
  525. logx.Info(err)
  526. if len(buyerBuckets.Buckets) > 0 {
  527. for _, v := range buyerBuckets.Buckets {
  528. buyerMap[v.Key] = supplyDataStruct{
  529. BidAmountCount: v.BidAmountCount.Value,
  530. ProjectCount: v.Doc_count,
  531. }
  532. }
  533. }
  534. }
  535. }
  536. }
  537. }
  538. ch := make(chan int, 10)
  539. ch2 := make(chan int, 10)
  540. wg := &sync.WaitGroup{}
  541. for i := 0; i < len(buyerNames); i++ {
  542. buyer := buyerNames[i]
  543. resp.Data = append(resp.Data, &bxbuyer.SupplyData{
  544. Buyer: buyer,
  545. })
  546. // 先查缓存
  547. if cacheData, ok := cacheMap[buyer]; ok {
  548. resp.Data[i].BidAmountCount = cacheData.BidAmountCount
  549. resp.Data[i].ProjectCount = cacheData.ProjectCount
  550. resp.Data[i].BiddingCount = cacheData.BidCount
  551. resp.Data[i].ContactCount = cacheData.ContactCount
  552. continue
  553. }
  554. // 缓存里没有的再取查数据补充
  555. // 补充字段
  556. if supplyData, ok := buyerMap[buyer]; ok {
  557. resp.Data[i].BidAmountCount = supplyData.BidAmountCount
  558. resp.Data[i].ProjectCount = supplyData.ProjectCount
  559. }
  560. ch2 <- 1
  561. wg.Add(1)
  562. go func(list *bxbuyer.SupplyData, buyer string) {
  563. defer func() {
  564. <-ch2
  565. wg.Done()
  566. }()
  567. list.ContactCount = GetProjectContactCount(buyer) // 补充联系人字段
  568. }(resp.Data[i], buyer)
  569. ch <- 1
  570. wg.Add(1)
  571. go func(list *bxbuyer.SupplyData, buyer string) {
  572. defer func() {
  573. <-ch
  574. wg.Done()
  575. }()
  576. list.BiddingCount = GetNewBiddingCount(buyer)
  577. }(resp.Data[i], buyer)
  578. }
  579. wg.Wait()
  580. logx.Info(" 整体耗时:", time.Since(start))
  581. //得到所有数据,包括 redis里的,再存一下
  582. go func(respList []*bxbuyer.SupplyData) {
  583. for i := 0; i < len(respList); i++ {
  584. tmp := supplyDataStruct{
  585. ContactCount: respList[i].ContactCount,
  586. BidCount: respList[i].BiddingCount,
  587. ProjectCount: respList[i].ProjectCount,
  588. BidAmountCount: respList[i].BidAmountCount,
  589. }
  590. // 存redis
  591. b, err := json.Marshal(tmp)
  592. if err == nil {
  593. redis.PutBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, respList[i].Buyer), &b, BuyerSupplyInfoRedisTime+GetRand(60))
  594. }
  595. }
  596. }(resp.Data)
  597. return
  598. }
  599. func GetProjectContactCount(buyerName string) int64 {
  600. start := time.Now()
  601. list := []string{}
  602. searchSql := fmt.Sprintf(`{"query":{"bool":{"filter":[{"term":{"buyer":"%s"}}]}},"_source":["list.buyerperson","list.buyertel"],"sort":[{"zbtime":"desc"}],"size":500}`, buyerName)
  603. projectList := elastic.Get(P_INDEX, P_TYPE, searchSql)
  604. logx.Info("GetProjectContactCount esget 耗时", time.Since(start), searchSql)
  605. if projectList == nil || len(*projectList) == 0 {
  606. return 0
  607. }
  608. //根据联系人和联系方式展示
  609. //多个项目同一个联系人;只展示最新项目
  610. //一个项目多个联系人;拆分展示
  611. repeatContacts := map[string]bool{}
  612. for _, rowData := range *projectList {
  613. mapList, ok := rowData["list"].([]interface{})
  614. if !ok || len(mapList) == 0 {
  615. continue
  616. }
  617. for i := len(mapList) - 1; i >= 0; i-- {
  618. thisMsg, ok := mapList[i].(map[string]interface{})
  619. if !ok || len(thisMsg) == 0 {
  620. continue
  621. }
  622. thisPhone, thisPerson := "", ""
  623. if thisPhone, _ = thisMsg["buyertel"].(string); thisPhone != "" {
  624. thisPerson, _ = thisMsg["buyerperson"].(string)
  625. }
  626. if thisPhone == "" { //联系人为空则不展示 dev4.7.3联系人为空展示此记录
  627. continue
  628. }
  629. //一个项目只选取一条公告联系人
  630. thisAddPerson := false
  631. //名字中多个联系人拆分
  632. for _, name := range strings.Split(thisPerson, ",") {
  633. thisName := strings.TrimSpace(name)
  634. if thisName == "" && thisAddPerson { //联系人为空则不展示
  635. continue
  636. }
  637. thisAddPerson = true
  638. repeatKey := fmt.Sprintf("%s_%s", thisName, thisPhone)
  639. if repeatContacts[repeatKey] {
  640. continue
  641. }
  642. repeatContacts[repeatKey] = true
  643. list = append(list, thisPhone)
  644. }
  645. if thisAddPerson {
  646. break
  647. }
  648. }
  649. }
  650. logx.Info("GetProjectContactCount 单次耗时:", time.Since(start))
  651. return int64(len(list))
  652. }
  653. func GetNewBiddingCount(buyer string) int64 {
  654. start := time.Now()
  655. if buyer == "" {
  656. return 0
  657. }
  658. var mustQuery []string
  659. st, et := getTimeRange()
  660. mustQuery = append(mustQuery, fmt.Sprintf(`{"range":{"publishtime":{"gte":%d,"lte":%d}}}`, st.Unix(), et.Unix()))
  661. mustQuery = append(mustQuery, fmt.Sprintf(`{"term": {"buyer": "%s"}}`, buyer))
  662. aa := fmt.Sprintf(`{"query":{"bool":{"must":[%s]}}}`, strings.Join(mustQuery, ","))
  663. count := elastic.Count(biddingIndex, biddingType, aa)
  664. logx.Info("GetNewBiddingCount 单次耗时:", buyer, time.Since(start))
  665. return count
  666. }
  667. // 聚合查询
  668. func GetAggs(index, itype, query string) (aggs map[string]json.RawMessage) {
  669. aggs, _, _ = elastic.GetAggs(index, itype, query)
  670. return
  671. }
  672. type buyerInfo struct {
  673. Province string
  674. City string
  675. }
  676. // 潜在客户 获取省份和城市
  677. func GetBuyerInfo(buyerNames []string) (infoMap map[string]buyerInfo) {
  678. var buyerInfoQuery = `{"query": {"bool": {"must": [{"terms": {"%s": [%s]}}],"must_not": [],"should": []}},"from": 0,"size": 50,"sort": []}`
  679. query := fmt.Sprintf(buyerInfoQuery, "buyer_name", `"`+strings.Join(buyerNames, `","`)+`"`)
  680. list := *elastic.Get("buyer", "buyer", query)
  681. if list != nil {
  682. if len(list) > 0 {
  683. infoMap = map[string]buyerInfo{}
  684. for _, v := range list {
  685. infoMap[v["name"].(string)] = buyerInfo{
  686. Province: MC.If(v["province"] != nil, MC.ObjToString(v["province"]), "").(string),
  687. City: MC.If(v["city"] != nil, MC.ObjToString(v["city"]), "").(string),
  688. }
  689. }
  690. }
  691. } else {
  692. logx.Info("采购单位获取地区信息异常")
  693. }
  694. return
  695. }
  696. var fc = "follow_customer" //关注客户表
  697. // 采购单位是否作为客户已被关注
  698. func IsFollowd(buyerNames []string, userId string) (isFws map[string]bool) {
  699. queryMap := map[string]interface{}{
  700. "userId": userId,
  701. "name": map[string]interface{}{
  702. "$in": buyerNames,
  703. },
  704. }
  705. list, ok := IC.Mgo.Find(fc, queryMap, `{"_id":1}`, nil, false, -1, -1)
  706. if ok && len(*list) > 0 {
  707. isFws = map[string]bool{}
  708. for _, lv := range *list {
  709. if MC.ObjToString(lv["name"]) != "" {
  710. isFws[MC.ObjToString(lv["name"])] = true
  711. }
  712. }
  713. } else {
  714. logx.Info("采购单位是否已关注信息异常 or 未查到数据")
  715. }
  716. return
  717. }
  718. var (
  719. Entniche_customer = "entniche_customer"
  720. Entniche_user_customer = "entniche_user_customer"
  721. )
  722. // 领取状态
  723. func IsReceived(buyerNames []string, entUserId string) (isRws map[string]string) {
  724. //新加领取的客户id----保证领取的唯一性
  725. aa := fmt.Sprintf("SELECT ecn.id, ecn.name FROM %s ecn,%s euu WHERE ecn.id = euu.customer_id AND euu.user_id =? AND ecn.`name` IN ('%s') AND (euu.source_type =1 or euu.source_type=4)", Entniche_customer, Entniche_user_customer, strings.Join(buyerNames, "','"))
  726. log.Println(aa)
  727. receInfos := IC.MainMysql.SelectBySql(fmt.Sprintf("SELECT ecn.id, ecn.name FROM %s ecn,%s euu WHERE ecn.id = euu.customer_id AND euu.user_id =? AND ecn.`name` IN ('%s') AND (euu.source_type =1 or euu.source_type=4)", Entniche_customer, Entniche_user_customer, strings.Join(buyerNames, "','")), entUserId)
  728. if receInfos != nil {
  729. if len(*receInfos) > 0 {
  730. isRws = map[string]string{}
  731. for _, rv := range *receInfos {
  732. if MC.ObjToString(rv["name"]) != "" && strconv.Itoa(MC.IntAll(rv["id"])) != "" {
  733. isRws[MC.ObjToString(rv["name"])] = encrypt.SE.Encode2HexByCheck(strconv.Itoa(MC.IntAll(rv["id"])))
  734. }
  735. }
  736. }
  737. } else {
  738. logx.Info("采购单位是否已领取信息异常")
  739. }
  740. return
  741. }
  742. // 是否为空请求
  743. func CheckEmpty(in *bxbuyer.BuyerListReq) bool {
  744. if in.BuyerName == "" && len(in.BuyerClass) == 0 && len(in.Province) == 0 && len(in.City) == 0 && in.IsContact == 0 {
  745. return true
  746. }
  747. return false
  748. }
  749. //缓存数据查询
  750. // 获取采购单位查询query
  751. func BuyerListRedisCacheQuery() (qstr string) {
  752. qstr = `{"size":%d,"query":{"bool":{"must":[],"must_not":[{"term":{"buyer_name":""}}]}},"sort":[{"updatetime":"desc"}]}`
  753. return fmt.Sprintf(qstr, IC.C.BuyerSearchLimit)
  754. }