buyerListBYEs.go 26 KB

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