buyerListBYEs.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  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. entIdInt, _ := strconv.Atoi(in.EntId)
  313. powerCheck := IC.Middleground.PowerCheckCenter.Check(in.AppId, in.MgoUserId, in.NewUserId, in.AccountId, int64(entIdInt), in.PositionType, in.PositionId)
  314. if powerCheck != nil && (*powerCheck).Member.Pid != "" {
  315. in.UserId = (*powerCheck).Member.Pid
  316. }
  317. if in.IsCheckFollow {
  318. isFws = IsFollowd(buyerNames, in.UserId)
  319. }
  320. logx.Info("采购单位关注耗时:", time.Since(t3))
  321. for _, bv := range resp.Data.List {
  322. if in.IsCheckReceive {
  323. if isRws[bv.Buyer] != "" {
  324. bv.IsReceived = true
  325. bv.RecId = isRws[bv.Buyer]
  326. }
  327. }
  328. if in.IsCheckFollow {
  329. if isFws[bv.Buyer] {
  330. bv.IsFollowed = true
  331. }
  332. }
  333. }
  334. return resp
  335. }
  336. // SupplyBuyerListData 补充字段 招标动态数量 项目数量 历史联系人数量 采购单位规模
  337. func SupplyBuyerListData(buyerNames []string, resp *bxbuyer.BuyerListResp) *bxbuyer.BuyerListResp {
  338. //buyerNames 是否存在缓存 数据
  339. //如果没有 放到一个新的 []string
  340. needSearchBuyer := []string{}
  341. cacheMap := map[string]supplyDataStruct{}
  342. for i := 0; i < len(buyerNames); i++ {
  343. bs, err := redis.GetBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, buyerNames[i]))
  344. if err == nil && bs != nil && len(*bs) > 0 {
  345. tmp := supplyDataStruct{}
  346. if err := json.Unmarshal(*bs, &tmp); err == nil {
  347. cacheMap[buyerNames[i]] = tmp // 拿到缓存的数据
  348. } else {
  349. needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查
  350. }
  351. } else {
  352. needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查
  353. }
  354. }
  355. start := time.Now()
  356. t1 := time.Now()
  357. buyerMap := map[string]supplyDataStruct{} // 聚合的数据
  358. if len(needSearchBuyer) > 0 {
  359. query := SupplyDataQuery(needSearchBuyer) // 项目数量、采购规模
  360. // 聚合查
  361. aggs := GetAggs(P_INDEX, P_TYPE, query)
  362. logx.Info("查询语句:", query)
  363. logx.Info("项目数量采购规模查询耗时:", time.Since(t1))
  364. type BuyerAggStruct struct {
  365. Buckets []struct {
  366. Key string `json:"key,omitempty"`
  367. Doc_count int64 `json:"doc_count,omitempty"`
  368. BidAmountCount struct {
  369. Value float32 `json:"value,omitempty"`
  370. } `json:"bidAmountCount"`
  371. } `json:"buckets"`
  372. }
  373. var buyerBuckets = BuyerAggStruct{}
  374. // 处理成map 用于后面格式化数据
  375. if aggs != nil && aggs["buyerBuckets"] != nil {
  376. bs, err := aggs["buyerBuckets"].MarshalJSON()
  377. if err != nil {
  378. resp.ErrCode = -1
  379. resp.ErrMsg = "获取数据异常"
  380. } else {
  381. if len(bs) == 0 {
  382. resp.ErrMsg = "暂无数据"
  383. } else {
  384. err := json.Unmarshal(bs, &buyerBuckets)
  385. logx.Info(err)
  386. if len(buyerBuckets.Buckets) > 0 {
  387. for _, v := range buyerBuckets.Buckets {
  388. buyerMap[v.Key] = supplyDataStruct{
  389. BidAmountCount: v.BidAmountCount.Value,
  390. ProjectCount: v.Doc_count,
  391. }
  392. }
  393. }
  394. }
  395. }
  396. }
  397. }
  398. ch := make(chan int, 10)
  399. ch2 := make(chan int, 10)
  400. wg := &sync.WaitGroup{}
  401. for i := 0; i < len(resp.Data.List); i++ {
  402. buyer := resp.Data.List[i].Buyer
  403. // 先查缓存
  404. if cacheData, ok := cacheMap[buyer]; ok {
  405. resp.Data.List[i].BidAmountCount = cacheData.BidAmountCount
  406. resp.Data.List[i].ProjectCount = cacheData.ProjectCount
  407. resp.Data.List[i].BiddingCount = cacheData.BidCount
  408. resp.Data.List[i].ContactCount = cacheData.ContactCount
  409. continue
  410. }
  411. // 缓存里没有的再查数据补充
  412. if supplyData, ok := buyerMap[buyer]; ok {
  413. resp.Data.List[i].BidAmountCount = supplyData.BidAmountCount
  414. resp.Data.List[i].ProjectCount = supplyData.ProjectCount
  415. }
  416. ch2 <- 1
  417. wg.Add(1)
  418. go func(list *bxbuyer.BuyerList, buyer string) {
  419. defer func() {
  420. <-ch2
  421. wg.Done()
  422. }()
  423. list.ContactCount = GetProjectContactCount(buyer) // 补充联系人字段
  424. }(resp.Data.List[i], buyer)
  425. ch <- 1
  426. wg.Add(1)
  427. go func(list *bxbuyer.BuyerList, buyer string) {
  428. defer func() {
  429. <-ch
  430. wg.Done()
  431. }()
  432. list.BiddingCount = GetNewBiddingCount(buyer)
  433. }(resp.Data.List[i], buyer)
  434. }
  435. wg.Wait()
  436. logx.Info("SupplyBuyerListData 整体耗时:", time.Since(start))
  437. //得到所有数据,包括 redis里的,再存一下
  438. go func(respList []*bxbuyer.BuyerList) {
  439. for i := 0; i < len(respList); i++ {
  440. tmp := supplyDataStruct{
  441. ContactCount: respList[i].ContactCount,
  442. BidCount: respList[i].BiddingCount,
  443. ProjectCount: respList[i].ProjectCount,
  444. BidAmountCount: respList[i].BidAmountCount,
  445. }
  446. // 存redis
  447. b, err := json.Marshal(tmp)
  448. if err == nil {
  449. redis.PutBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, respList[i].Buyer), &b, BuyerSupplyInfoRedisTime+GetRand(60))
  450. }
  451. }
  452. }(resp.Data.List)
  453. return resp
  454. }
  455. // 获取项目数量 采购单位规模
  456. func getBuyerProjectCache(buyer string) (rs *supplyDataStruct) {
  457. bs, err := redis.GetBytes("other", fmt.Sprintf(BuyerProjectInfoRedisKey, buyer))
  458. if err == nil && bs != nil && len(*bs) > 0 {
  459. if err := json.Unmarshal(*bs, &rs); err != nil {
  460. logx.Info("获取redis缓存,序列化异常")
  461. } else {
  462. return rs
  463. }
  464. }
  465. return
  466. }
  467. // BuyerSupplyInfo 补充字段
  468. func BuyerSupplyInfo(buyerNames []string) (resp *bxbuyer.BuyerSupplyResp) {
  469. resp = &bxbuyer.BuyerSupplyResp{}
  470. start := time.Now()
  471. // buyerNames
  472. //buyerNames 是否存在缓存 数据
  473. //如果没有 放到一个新的 []string
  474. needSearchBuyer := []string{}
  475. cacheMap := map[string]supplyDataStruct{}
  476. buyerMap := map[string]supplyDataStruct{}
  477. for i := 0; i < len(buyerNames); i++ {
  478. bs, err := redis.GetBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, buyerNames[i]))
  479. if err == nil && bs != nil && len(*bs) > 0 {
  480. tmp := supplyDataStruct{}
  481. if err := json.Unmarshal(*bs, &tmp); err == nil {
  482. cacheMap[buyerNames[i]] = tmp // 拿到缓存的数据 采购规模 项目数量 联系人数量 招标动态数量
  483. } else {
  484. // 查缓存
  485. cacheProject := getBuyerProjectCache(buyerNames[i])
  486. if cacheProject != nil {
  487. buyerMap[buyerNames[i]] = *cacheProject
  488. } else {
  489. needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查采购规模和项目数量
  490. }
  491. }
  492. } else {
  493. // 查缓存
  494. cacheProject := getBuyerProjectCache(buyerNames[i])
  495. if cacheProject != nil {
  496. buyerMap[buyerNames[i]] = *cacheProject
  497. } else {
  498. needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查采购规模和项目数量
  499. }
  500. }
  501. }
  502. if len(needSearchBuyer) > 0 {
  503. t1 := time.Now()
  504. query := SupplyDataQuery(buyerNames) // 项目数量、采购规模
  505. // 聚合查
  506. aggs := GetAggs(P_INDEX, P_TYPE, query)
  507. logx.Info("查询语句:", query)
  508. logx.Info("项目数量采购规模查询耗时:", time.Since(t1))
  509. type BuyerAggStruct struct {
  510. Buckets []struct {
  511. Key string `json:"key,omitempty"`
  512. Doc_count int64 `json:"doc_count,omitempty"`
  513. BidAmountCount struct {
  514. Value float32 `json:"value,omitempty"`
  515. } `json:"bidAmountCount"`
  516. } `json:"buckets"`
  517. }
  518. var buyerBuckets = BuyerAggStruct{}
  519. // 处理成map 用于后面格式化数据
  520. if aggs != nil && aggs["buyerBuckets"] != nil {
  521. bs, err := aggs["buyerBuckets"].MarshalJSON()
  522. if err != nil {
  523. resp.ErrCode = -1
  524. resp.ErrMsg = "获取数据异常"
  525. } else {
  526. if len(bs) == 0 {
  527. resp.ErrMsg = "暂无数据"
  528. } else {
  529. err := json.Unmarshal(bs, &buyerBuckets)
  530. logx.Info(err)
  531. if len(buyerBuckets.Buckets) > 0 {
  532. for _, v := range buyerBuckets.Buckets {
  533. buyerMap[v.Key] = supplyDataStruct{
  534. BidAmountCount: v.BidAmountCount.Value,
  535. ProjectCount: v.Doc_count,
  536. }
  537. }
  538. }
  539. }
  540. }
  541. }
  542. }
  543. ch := make(chan int, 10)
  544. ch2 := make(chan int, 10)
  545. wg := &sync.WaitGroup{}
  546. for i := 0; i < len(buyerNames); i++ {
  547. buyer := buyerNames[i]
  548. resp.Data = append(resp.Data, &bxbuyer.SupplyData{
  549. Buyer: buyer,
  550. })
  551. // 先查缓存
  552. if cacheData, ok := cacheMap[buyer]; ok {
  553. resp.Data[i].BidAmountCount = cacheData.BidAmountCount
  554. resp.Data[i].ProjectCount = cacheData.ProjectCount
  555. resp.Data[i].BiddingCount = cacheData.BidCount
  556. resp.Data[i].ContactCount = cacheData.ContactCount
  557. continue
  558. }
  559. // 缓存里没有的再取查数据补充
  560. // 补充字段
  561. if supplyData, ok := buyerMap[buyer]; ok {
  562. resp.Data[i].BidAmountCount = supplyData.BidAmountCount
  563. resp.Data[i].ProjectCount = supplyData.ProjectCount
  564. }
  565. ch2 <- 1
  566. wg.Add(1)
  567. go func(list *bxbuyer.SupplyData, buyer string) {
  568. defer func() {
  569. <-ch2
  570. wg.Done()
  571. }()
  572. list.ContactCount = GetProjectContactCount(buyer) // 补充联系人字段
  573. }(resp.Data[i], buyer)
  574. ch <- 1
  575. wg.Add(1)
  576. go func(list *bxbuyer.SupplyData, buyer string) {
  577. defer func() {
  578. <-ch
  579. wg.Done()
  580. }()
  581. list.BiddingCount = GetNewBiddingCount(buyer)
  582. }(resp.Data[i], buyer)
  583. }
  584. wg.Wait()
  585. logx.Info(" 整体耗时:", time.Since(start))
  586. //得到所有数据,包括 redis里的,再存一下
  587. go func(respList []*bxbuyer.SupplyData) {
  588. for i := 0; i < len(respList); i++ {
  589. tmp := supplyDataStruct{
  590. ContactCount: respList[i].ContactCount,
  591. BidCount: respList[i].BiddingCount,
  592. ProjectCount: respList[i].ProjectCount,
  593. BidAmountCount: respList[i].BidAmountCount,
  594. }
  595. // 存redis
  596. b, err := json.Marshal(tmp)
  597. if err == nil {
  598. redis.PutBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, respList[i].Buyer), &b, BuyerSupplyInfoRedisTime+GetRand(60))
  599. }
  600. }
  601. }(resp.Data)
  602. return
  603. }
  604. func GetProjectContactCount(buyerName string) int64 {
  605. start := time.Now()
  606. list := []string{}
  607. searchSql := fmt.Sprintf(`{"query":{"bool":{"filter":[{"term":{"buyer":"%s"}}]}},"_source":["list.buyerperson","list.buyertel"],"sort":[{"zbtime":"desc"}],"size":500}`, buyerName)
  608. projectList := elastic.Get(P_INDEX, P_TYPE, searchSql)
  609. logx.Info("GetProjectContactCount esget 耗时", time.Since(start), searchSql)
  610. if projectList == nil || len(*projectList) == 0 {
  611. return 0
  612. }
  613. //根据联系人和联系方式展示
  614. //多个项目同一个联系人;只展示最新项目
  615. //一个项目多个联系人;拆分展示
  616. repeatContacts := map[string]bool{}
  617. for _, rowData := range *projectList {
  618. mapList, ok := rowData["list"].([]interface{})
  619. if !ok || len(mapList) == 0 {
  620. continue
  621. }
  622. for i := len(mapList) - 1; i >= 0; i-- {
  623. thisMsg, ok := mapList[i].(map[string]interface{})
  624. if !ok || len(thisMsg) == 0 {
  625. continue
  626. }
  627. thisPhone, thisPerson := "", ""
  628. if thisPhone, _ = thisMsg["buyertel"].(string); thisPhone != "" {
  629. thisPerson, _ = thisMsg["buyerperson"].(string)
  630. }
  631. if thisPhone == "" { //联系人为空则不展示 dev4.7.3联系人为空展示此记录
  632. continue
  633. }
  634. //一个项目只选取一条公告联系人
  635. thisAddPerson := false
  636. //名字中多个联系人拆分
  637. for _, name := range strings.Split(thisPerson, ",") {
  638. thisName := strings.TrimSpace(name)
  639. if thisName == "" && thisAddPerson { //联系人为空则不展示
  640. continue
  641. }
  642. thisAddPerson = true
  643. repeatKey := fmt.Sprintf("%s_%s", thisName, thisPhone)
  644. if repeatContacts[repeatKey] {
  645. continue
  646. }
  647. repeatContacts[repeatKey] = true
  648. list = append(list, thisPhone)
  649. }
  650. if thisAddPerson {
  651. break
  652. }
  653. }
  654. }
  655. logx.Info("GetProjectContactCount 单次耗时:", time.Since(start))
  656. return int64(len(list))
  657. }
  658. func GetNewBiddingCount(buyer string) int64 {
  659. start := time.Now()
  660. if buyer == "" {
  661. return 0
  662. }
  663. var mustQuery []string
  664. st, et := getTimeRange()
  665. mustQuery = append(mustQuery, fmt.Sprintf(`{"range":{"publishtime":{"gte":%d,"lte":%d}}}`, st.Unix(), et.Unix()))
  666. mustQuery = append(mustQuery, fmt.Sprintf(`{"term": {"buyer": "%s"}}`, buyer))
  667. aa := fmt.Sprintf(`{"query":{"bool":{"must":[%s]}}}`, strings.Join(mustQuery, ","))
  668. count := elastic.Count(biddingIndex, biddingType, aa)
  669. logx.Info("GetNewBiddingCount 单次耗时:", buyer, time.Since(start))
  670. return count
  671. }
  672. // 聚合查询
  673. func GetAggs(index, itype, query string) (aggs map[string]json.RawMessage) {
  674. aggs, _, _ = elastic.GetAggs(index, itype, query)
  675. return
  676. }
  677. type buyerInfo struct {
  678. Province string
  679. City string
  680. }
  681. // 潜在客户 获取省份和城市
  682. func GetBuyerInfo(buyerNames []string) (infoMap map[string]buyerInfo) {
  683. var buyerInfoQuery = `{"query": {"bool": {"must": [{"terms": {"%s": [%s]}}],"must_not": [],"should": []}},"from": 0,"size": 50,"sort": []}`
  684. query := fmt.Sprintf(buyerInfoQuery, "buyer_name", `"`+strings.Join(buyerNames, `","`)+`"`)
  685. list := *elastic.Get("buyer", "buyer", query)
  686. if list != nil {
  687. if len(list) > 0 {
  688. infoMap = map[string]buyerInfo{}
  689. for _, v := range list {
  690. infoMap[v["name"].(string)] = buyerInfo{
  691. Province: MC.If(v["province"] != nil, MC.ObjToString(v["province"]), "").(string),
  692. City: MC.If(v["city"] != nil, MC.ObjToString(v["city"]), "").(string),
  693. }
  694. }
  695. }
  696. } else {
  697. logx.Info("采购单位获取地区信息异常")
  698. }
  699. return
  700. }
  701. var fc = "follow_customer" //关注客户表
  702. // 采购单位是否作为客户已被关注
  703. func IsFollowd(buyerNames []string, userId string) (isFws map[string]bool) {
  704. queryMap := map[string]interface{}{
  705. "userId": userId,
  706. "name": map[string]interface{}{
  707. "$in": buyerNames,
  708. },
  709. }
  710. log.Println("IsFollowd query:", fc, queryMap)
  711. list, ok := IC.Mgo.Find(fc, queryMap, `{"_id":1}`, nil, false, -1, -1)
  712. if ok && len(*list) > 0 {
  713. isFws = map[string]bool{}
  714. for _, lv := range *list {
  715. if MC.ObjToString(lv["name"]) != "" {
  716. isFws[MC.ObjToString(lv["name"])] = true
  717. }
  718. }
  719. } else {
  720. logx.Info("采购单位是否已关注信息异常 or 未查到数据", ok)
  721. }
  722. return
  723. }
  724. var (
  725. Entniche_customer = "entniche_customer"
  726. Entniche_user_customer = "entniche_user_customer"
  727. )
  728. // 领取状态
  729. func IsReceived(buyerNames []string, entUserId string) (isRws map[string]string) {
  730. //新加领取的客户id----保证领取的唯一性
  731. 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, "','"))
  732. log.Println(aa)
  733. 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)
  734. if receInfos != nil {
  735. if len(*receInfos) > 0 {
  736. isRws = map[string]string{}
  737. for _, rv := range *receInfos {
  738. if MC.ObjToString(rv["name"]) != "" && strconv.Itoa(MC.IntAll(rv["id"])) != "" {
  739. isRws[MC.ObjToString(rv["name"])] = encrypt.SE.Encode2HexByCheck(strconv.Itoa(MC.IntAll(rv["id"])))
  740. }
  741. }
  742. }
  743. } else {
  744. logx.Info("采购单位是否已领取信息异常")
  745. }
  746. return
  747. }
  748. // 是否为空请求
  749. func CheckEmpty(in *bxbuyer.BuyerListReq) bool {
  750. if in.BuyerName == "" && len(in.BuyerClass) == 0 && len(in.Province) == 0 && len(in.City) == 0 && in.IsContact == 0 {
  751. return true
  752. }
  753. return false
  754. }
  755. //缓存数据查询
  756. // 获取采购单位查询query
  757. func BuyerListRedisCacheQuery() (qstr string) {
  758. qstr = `{"size":%d,"query":{"bool":{"must":[],"must_not":[{"term":{"buyer_name":""}}]}},"sort":[{"updatetime":"desc"}]}`
  759. return fmt.Sprintf(qstr, IC.C.BuyerSearchLimit)
  760. }