package service import ( "context" "fmt" "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv" "jybxseo/internal/consts" "jybxseo/utility" "strings" "time" ) type ( SeoBiddingQuery struct { status int keys string area string city string district string topType string subType string topClass string subClass string } InfoList struct { Title string Url string Area string City string Industry string Subtype string Price string Site string Detail string Keyword string FileExists bool PublishTime int64 } ListResp struct { Total int List []*InfoList } ) func NewBiddingQuery() *SeoBiddingQuery { return &SeoBiddingQuery{} } func (query *SeoBiddingQuery) QueryState(value int) *SeoBiddingQuery { if value > 0 { query.status = value } return query } // EquipArea 装备地区查询 func (query *SeoBiddingQuery) EquipArea(areaNode *AreaNode) *SeoBiddingQuery { if areaNode.Type == 2 { query.city = areaNode.Name } else { query.area = areaNode.Name } return query } func (query *SeoBiddingQuery) EquipKeyWord(keyword string) *SeoBiddingQuery { query.keys = keyword return query } func (query *SeoBiddingQuery) EquipIndustry(topClass, subClass string) *SeoBiddingQuery { if topClass != "" { query.topClass = topClass } if subClass != "" { query.subClass = subClass } return query } func (query *SeoBiddingQuery) dataFormat(data []map[string]interface{}) (bList []*InfoList) { if len(data) > 0 { titleReduction := map[string]int{} for _, v := range data { var publishTime int64 tm := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 23, 59, 59, 59, time.Now().Location()) if gconv.Int64(v["publish_time"])+3600*24 > tm.Unix() { publishTime = gconv.Int64(v["publish_time"]) } else { publishTime = gconv.Int64(v["publish_time"]) + 3600*24 } bl := &InfoList{ Title: gconv.String(fmt.Sprintf("【%s】%s", consts.TopTypeMap[gconv.String(v["toptype"])], v["title"])), Url: fmt.Sprintf("/jybx/%s_%s.html", gtime.NewFromTimeStamp(publishTime).Format("Ymd"), gconv.String(v["seo_id"])), Area: gconv.String(v["area"]), City: gconv.String(v["city"]), Subtype: gconv.String(v["subtype"]), Detail: gconv.String(v["desc"]), Keyword: gconv.String(v["keyword"]), } titleReduction[bl.Title]++ //重复标题加数字后缀 if val := titleReduction[bl.Title]; val > 1 { bl.Title = fmt.Sprintf("%s%d", bl.Title, val-1) } bl.PublishTime = publishTime //增加一天 更新天数 if gconv.String(v["area"]) == "剑鱼信息发布平台" { bl.Site = "用户发布" } if industry := gconv.String(v["industry"]); industry != "" { bl.Industry = industry } if isValidFile, _ := v["isValidFile"].(bool); isValidFile { bl.FileExists = true } if budget := gconv.Float64(v["budget"]); budget > 0 { bl.Price = utility.ConversionMoney(v["budget"]) } else if bidamount := gconv.Float64(v["bidamount"]); bidamount > 0 { bl.Price = utility.ConversionMoney(v["bidamount"]) } bList = append(bList, bl) } } return } // getBidListCacheKey 获取列表缓存 func (query *SeoBiddingQuery) getDataPageListCacheKey(pageNum, maxTotal int, flag string) string { 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) } // GetDataPageList 翻页列表页查询 // 一次性查询全部信息,生成每页cache 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) { var vars *gvar.Var res = &ListResp{} vars, err = g.Redis().Get(ctx, query.getDataPageListCacheKey(pageNum, maxTotal, flag)) if err != nil || vars.IsNil() { //并发限制 if ok := utility.JySeoQueryListLimit.Limit(); !ok { err = fmt.Errorf("请求超时") return } defer utility.JySeoQueryListLimit.Reset() data := getData(ctx, maxTotal, query) formatData := query.dataFormat(data) count := len(formatData) if count > maxTotal { count = maxTotal } if data != nil && len(data) > 0 { totalPage := count / consts.SettingPageSize if count%consts.SettingPageSize != 0 { totalPage++ } for i := 1; i <= gconv.Int(totalPage); i++ { start, end := (i-1)*consts.SettingPageSize, (i)*consts.SettingPageSize if end > count { end = count } pageTmp := &ListResp{ Total: totalPage, List: formatData[start:end], } if i == pageNum { res = pageTmp } if err := g.Redis().SetEX(ctx, query.getDataPageListCacheKey(i, maxTotal, flag), pageTmp, consts.SettingBidCacheTime); err != nil { g.Log().Errorf(ctx, "第%d页数据 存储redis err:%v", err) } } } } else { err = vars.Struct(res) } return } // getTabDataCacheKey 获取列表缓存 func (query *SeoBiddingQuery) getOnceDataCacheKey(total int, flag string) string { 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) } // GetOnceData 获取数据 func (query *SeoBiddingQuery) GetOnceData(ctx context.Context, total int, flag string, getData func(context.Context, int, *SeoBiddingQuery) []map[string]interface{}) (res []*InfoList, err error) { var vars *gvar.Var cacheKey := query.getOnceDataCacheKey(total, flag) vars, err = g.Redis().Get(ctx, cacheKey) if err != nil || vars.IsNil() { //并发限制 if ok := utility.JySeoQueryTabLimit.Limit(); !ok { err = fmt.Errorf("请求超时") return } defer utility.JySeoQueryTabLimit.Reset() data := getData(ctx, total, query) if len(data) > total { data = data[:total] } if data != nil && len(data) > 0 { res = query.dataFormat(data) } if res != nil && len(res) > 0 { if err := g.Redis().SetEX(ctx, cacheKey, res, consts.SettingBidCacheTime); err != nil { g.Log().Errorf(ctx, "GetOnceData 存储redis err:%v", err) } } } else { err = vars.Struct(&res) } return } func FillingBiddingBaseFields(ctx context.Context, res []map[string]interface{}) []map[string]interface{} { var batchSize = g.Cfg().MustGet(context.Background(), "listPageSetting.batchSize", 200).Int() var ( queryIdBatch = [][]string{} tmpArr = make([]string, 0, batchSize) total = len(res) index = 0 ) for _, m := range res { bidId := gconv.String(m["bid_id"]) if bidId == "" { continue } tmpArr = append(tmpArr, bidId) if len(tmpArr) == batchSize { queryIdBatch = append(queryIdBatch, tmpArr) tmpArr = make([]string, 0, batchSize) } index++ if index == total { queryIdBatch = append(queryIdBatch, tmpArr) } } var ( bidMap = map[string]map[string]interface{}{} ) for _, ids := range queryIdBatch { bidRes, _ := g.DB().Query(ctx, fmt.Sprintf(`SELECT * FROM new_bidList WHERE bid_id IN ('%s')`, strings.Join(ids, "','"))) if bidRes.IsEmpty() { continue } for _, m := range bidRes.List() { if bidIdStr := gconv.String(m["bid_id"]); bidIdStr != "" { bidMap[bidIdStr] = m } } } var finalArr []map[string]interface{} for i := 0; i < len(res); i++ { if tBid := gconv.String(res[i]["bid_id"]); tBid != "" && bidMap[tBid] != nil && len(bidMap[tBid]) > 0 { for k, v := range bidMap[tBid] { res[i][k] = v } finalArr = append(finalArr, res[i]) } } return finalArr }