queryStruct.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/gogf/gf/v2/container/gvar"
  6. "github.com/gogf/gf/v2/frame/g"
  7. "github.com/gogf/gf/v2/os/gtime"
  8. "github.com/gogf/gf/v2/util/gconv"
  9. "jybxseo/internal/consts"
  10. "jybxseo/utility"
  11. "strings"
  12. "time"
  13. )
  14. type (
  15. SeoBiddingQuery struct {
  16. status int
  17. keys string
  18. area string
  19. city string
  20. district string
  21. topType string
  22. subType string
  23. topClass string
  24. subClass string
  25. }
  26. InfoList struct {
  27. Title string
  28. Url string
  29. Area string
  30. City string
  31. Industry string
  32. Subtype string
  33. Price string
  34. Site string
  35. Detail string
  36. Keyword string
  37. FileExists bool
  38. PublishTime int64
  39. }
  40. ListResp struct {
  41. Total int
  42. List []*InfoList
  43. }
  44. )
  45. func NewBiddingQuery() *SeoBiddingQuery {
  46. return &SeoBiddingQuery{}
  47. }
  48. func (query *SeoBiddingQuery) QueryState(value int) *SeoBiddingQuery {
  49. if value > 0 {
  50. query.status = value
  51. }
  52. return query
  53. }
  54. // EquipArea 装备地区查询
  55. func (query *SeoBiddingQuery) EquipArea(areaNode *AreaNode) *SeoBiddingQuery {
  56. if areaNode.Type == 2 {
  57. query.city = areaNode.Name
  58. } else {
  59. query.area = areaNode.Name
  60. }
  61. return query
  62. }
  63. func (query *SeoBiddingQuery) EquipKeyWord(keyword string) *SeoBiddingQuery {
  64. query.keys = keyword
  65. return query
  66. }
  67. func (query *SeoBiddingQuery) EquipIndustry(topClass, subClass string) *SeoBiddingQuery {
  68. if topClass != "" {
  69. query.topClass = topClass
  70. }
  71. if subClass != "" {
  72. query.subClass = subClass
  73. }
  74. return query
  75. }
  76. func (query *SeoBiddingQuery) dataFormat(data []map[string]interface{}) (bList []*InfoList) {
  77. if len(data) > 0 {
  78. titleReduction := map[string]int{}
  79. for _, v := range data {
  80. var publishTime int64
  81. tm := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 23, 59, 59, 0, time.Now().Location())
  82. if gconv.Int64(v["publish_time"])+3600*24 > tm.Unix() {
  83. publishTime = gconv.Int64(v["publish_time"])
  84. } else {
  85. publishTime = gconv.Int64(v["publish_time"]) + 3600*24
  86. }
  87. bl := &InfoList{
  88. Title: gconv.String(fmt.Sprintf("【%s】%s", consts.TopTypeMap[gconv.String(v["toptype"])], v["title"])),
  89. Url: fmt.Sprintf("/jybx/%s_%s.html", gtime.NewFromTimeStamp(publishTime).Format("Ymd"), gconv.String(v["seo_id"])),
  90. Area: gconv.String(v["area"]),
  91. City: gconv.String(v["city"]),
  92. Subtype: gconv.String(v["subtype"]),
  93. Detail: gconv.String(v["desc"]),
  94. Keyword: gconv.String(v["keyword"]),
  95. }
  96. titleReduction[bl.Title]++
  97. //重复标题加数字后缀
  98. if val := titleReduction[bl.Title]; val > 1 {
  99. bl.Title = fmt.Sprintf("%s%d", bl.Title, val-1)
  100. }
  101. bl.PublishTime = publishTime //增加一天 更新天数
  102. if gconv.String(v["area"]) == "剑鱼信息发布平台" {
  103. bl.Site = "用户发布"
  104. }
  105. if industry := gconv.String(v["industry"]); industry != "" {
  106. bl.Industry = industry
  107. }
  108. if isValidFile, _ := v["isValidFile"].(bool); isValidFile {
  109. bl.FileExists = true
  110. }
  111. if budget := gconv.Float64(v["budget"]); budget > 0 {
  112. bl.Price = utility.ConversionMoney(v["budget"])
  113. } else if bidamount := gconv.Float64(v["bidamount"]); bidamount > 0 {
  114. bl.Price = utility.ConversionMoney(v["bidamount"])
  115. }
  116. bList = append(bList, bl)
  117. }
  118. }
  119. return
  120. }
  121. // getBidListCacheKey 获取列表缓存
  122. func (query *SeoBiddingQuery) getDataPageListCacheKey(pageNum, maxTotal int, flag string) string {
  123. return fmt.Sprintf("JybxSeoBidDataPageList_%s_%d_%d_%s_%s_%s_%s_%s_%s_%s_%s", flag, pageNum, maxTotal, query.keys, query.area, query.city, query.district, query.topType, query.subType, query.topClass, query.subClass)
  124. }
  125. // GetDataPageList 翻页列表页查询
  126. // 一次性查询全部信息,生成每页cache
  127. func (query *SeoBiddingQuery) GetDataPageList(ctx context.Context, pageNum, maxTotal int, flag string, getData func(context.Context, int, *SeoBiddingQuery) []map[string]interface{}) (res *ListResp, err error) {
  128. var vars *gvar.Var
  129. res = &ListResp{}
  130. vars, err = g.Redis().Get(ctx, query.getDataPageListCacheKey(pageNum, maxTotal, flag))
  131. if err != nil || vars.IsNil() {
  132. //并发限制
  133. if ok := utility.JySeoQueryListLimit.Limit(); !ok {
  134. err = fmt.Errorf("请求超时")
  135. return
  136. }
  137. defer utility.JySeoQueryListLimit.Reset()
  138. data := getData(ctx, maxTotal, query)
  139. formatData := query.dataFormat(data)
  140. count := len(formatData)
  141. if count > maxTotal {
  142. count = maxTotal
  143. }
  144. if data != nil && len(data) > 0 {
  145. totalPage := count / consts.SettingPageSize
  146. if count%consts.SettingPageSize != 0 {
  147. totalPage++
  148. }
  149. for i := 1; i <= gconv.Int(totalPage); i++ {
  150. start, end := (i-1)*consts.SettingPageSize, (i)*consts.SettingPageSize
  151. if end > count {
  152. end = count
  153. }
  154. pageTmp := &ListResp{
  155. Total: totalPage,
  156. List: formatData[start:end],
  157. }
  158. if i == pageNum {
  159. res = pageTmp
  160. }
  161. if err := g.Redis().SetEX(ctx, query.getDataPageListCacheKey(i, maxTotal, flag), pageTmp, consts.SettingBidCacheTime); err != nil {
  162. g.Log().Errorf(ctx, "第%d页数据 存储redis err:%v", err)
  163. }
  164. }
  165. }
  166. } else {
  167. err = vars.Struct(res)
  168. }
  169. return
  170. }
  171. // getTabDataCacheKey 获取列表缓存
  172. func (query *SeoBiddingQuery) getOnceDataCacheKey(total int, flag string) string {
  173. return fmt.Sprintf("JybxSeoBidDataOnceList_%s_%d_%s_%s_%s_%s_%s_%s_%s_%s", flag, total, query.keys, query.area, query.city, query.district, query.topType, query.subType, query.topClass, query.subClass)
  174. }
  175. // GetOnceData 获取数据
  176. func (query *SeoBiddingQuery) GetOnceData(ctx context.Context, total int, flag string, getData func(context.Context, int, *SeoBiddingQuery) []map[string]interface{}) (res []*InfoList, err error) {
  177. var vars *gvar.Var
  178. cacheKey := query.getOnceDataCacheKey(total, flag)
  179. vars, err = g.Redis().Get(ctx, cacheKey)
  180. if err != nil || vars.IsNil() {
  181. //并发限制
  182. if ok := utility.JySeoQueryTabLimit.Limit(); !ok {
  183. err = fmt.Errorf("请求超时")
  184. return
  185. }
  186. defer utility.JySeoQueryTabLimit.Reset()
  187. data := getData(ctx, total, query)
  188. if len(data) > total {
  189. data = data[:total]
  190. }
  191. if data != nil && len(data) > 0 {
  192. res = query.dataFormat(data)
  193. }
  194. if res != nil && len(res) > 0 {
  195. if err := g.Redis().SetEX(ctx, cacheKey, res, consts.SettingBidCacheTime); err != nil {
  196. g.Log().Errorf(ctx, "GetOnceData 存储redis err:%v", err)
  197. }
  198. }
  199. } else {
  200. err = vars.Struct(&res)
  201. }
  202. return
  203. }
  204. func FillingBiddingBaseFields(ctx context.Context, res []map[string]interface{}) []map[string]interface{} {
  205. var batchSize = g.Cfg().MustGet(context.Background(), "listPageSetting.batchSize", 200).Int()
  206. var (
  207. queryIdBatch = [][]string{}
  208. tmpArr = make([]string, 0, batchSize)
  209. total = len(res)
  210. index = 0
  211. )
  212. for _, m := range res {
  213. bidId := gconv.String(m["bid_id"])
  214. if bidId == "" {
  215. continue
  216. }
  217. tmpArr = append(tmpArr, bidId)
  218. if len(tmpArr) == batchSize {
  219. queryIdBatch = append(queryIdBatch, tmpArr)
  220. tmpArr = make([]string, 0, batchSize)
  221. }
  222. index++
  223. if index == total {
  224. queryIdBatch = append(queryIdBatch, tmpArr)
  225. }
  226. }
  227. var (
  228. bidMap = map[string]map[string]interface{}{}
  229. )
  230. for _, ids := range queryIdBatch {
  231. bidRes, _ := g.DB().Query(ctx, fmt.Sprintf(`SELECT * FROM new_bidList WHERE bid_id IN ('%s')`, strings.Join(ids, "','")))
  232. if bidRes.IsEmpty() {
  233. continue
  234. }
  235. for _, m := range bidRes.List() {
  236. if bidIdStr := gconv.String(m["bid_id"]); bidIdStr != "" {
  237. bidMap[bidIdStr] = m
  238. }
  239. }
  240. }
  241. var finalArr []map[string]interface{}
  242. for i := 0; i < len(res); i++ {
  243. if tBid := gconv.String(res[i]["bid_id"]); tBid != "" && bidMap[tBid] != nil && len(bidMap[tBid]) > 0 {
  244. for k, v := range bidMap[tBid] {
  245. res[i][k] = v
  246. }
  247. finalArr = append(finalArr, res[i])
  248. }
  249. }
  250. return finalArr
  251. }