166 lines
5.0 KiB
Go
166 lines
5.0 KiB
Go
package product
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"gitea.timerzz.com/kedaya_haitao/common/model/product"
|
||
coach_client "gitea.timerzz.com/kedaya_haitao/common/pkg/coach-client"
|
||
"gitea.timerzz.com/kedaya_haitao/pusher/kitex_gen/push"
|
||
"gitea.timerzz.com/kedaya_haitao/pusher/rpc/pusher"
|
||
"github.com/golang/glog"
|
||
"github.com/samber/lo"
|
||
"gorm.io/gorm"
|
||
"gorm.io/gorm/clause"
|
||
"log/slog"
|
||
"time"
|
||
)
|
||
|
||
type Controller struct {
|
||
ctx context.Context
|
||
client *coach_client.US
|
||
updateTime time.Time // 上次抓取时间
|
||
db *gorm.DB
|
||
calculates []productv1.CalculateProcess
|
||
Option
|
||
}
|
||
|
||
func NewController(client *coach_client.US, db *gorm.DB) *Controller {
|
||
ctl := &Controller{
|
||
client: client,
|
||
db: db,
|
||
}
|
||
ctl.AutoMigrate()
|
||
ctl.LoadOption()
|
||
ctl.LoadCalculateProcess()
|
||
return ctl
|
||
}
|
||
|
||
func (c *Controller) AutoMigrate() {
|
||
if err := c.db.AutoMigrate(&productv1.Product{}, &productv1.HistoryPrice{}, &Option{}, &productv1.CalculateProcess{}); err != nil {
|
||
panic(err)
|
||
}
|
||
}
|
||
func (c *Controller) Run(ctx context.Context) {
|
||
c.ctx = ctx
|
||
ticker := time.NewTicker(c.Interval)
|
||
if err := c.Crawl(); err != nil {
|
||
slog.Error(err.Error())
|
||
} else {
|
||
slog.Info("抓取信息成功")
|
||
c.updateTime = time.Now()
|
||
}
|
||
for {
|
||
select {
|
||
case <-ctx.Done():
|
||
return
|
||
case <-ticker.C:
|
||
if err := c.Crawl(); err != nil {
|
||
slog.Error(err.Error())
|
||
} else {
|
||
slog.Info("抓取信息成功")
|
||
c.updateTime = time.Now()
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
func (c *Controller) Crawl() error {
|
||
slog.Info("开始抓取信息")
|
||
for page, totalPage := 1, -1; page <= totalPage || totalPage == -1; page++ {
|
||
resp, err := c.client.ViewAllBags(c.ctx, page)
|
||
if err != nil {
|
||
return fmt.Errorf("访问coach第%d页失败: %w", page, err)
|
||
}
|
||
totalPage = resp.PageData.TotalPages
|
||
|
||
if err = c.saveRespData(resp.PageData.Products); err != nil {
|
||
return fmt.Errorf("保存第%d页数据失败: %w", page, err)
|
||
}
|
||
glog.Infof("第%d页数据保存成功", page)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (c *Controller) saveRespData(list []coach_client.Product) error {
|
||
var products = make([]productv1.Product, 0, len(list))
|
||
for _, resp := range list {
|
||
for _, color := range resp.Colors {
|
||
price, _ := lo.Find(resp.VariantsOnSale, func(item coach_client.Variant) bool {
|
||
return item.Id == color.VgId
|
||
})
|
||
// 获取已经存的运费和得物价格
|
||
var savedProduct productv1.Product
|
||
c.db.Model(&savedProduct).Where("pid = ?", color.VgId).Select("freight", "dw_price").Scan(&savedProduct)
|
||
if savedProduct.Freight == 0 {
|
||
savedProduct.Freight = c.Freight
|
||
}
|
||
p := productv1.Product{
|
||
UpdatedAt: time.Now(),
|
||
Name: resp.Name,
|
||
Pid: color.VgId,
|
||
Color: color.Text,
|
||
Link: fmt.Sprintf("%s/%s", "https://www.coachoutlet.com", color.Url),
|
||
Image: color.Media.Thumbnail.Src,
|
||
Orderable: color.Orderable,
|
||
DiscPercent: price.Price.MarkdownDiscPercent,
|
||
OriginalPrice: price.Price.Sales.Value,
|
||
Freight: savedProduct.Freight,
|
||
ExchangeRate: c.ExchangeRate,
|
||
DWPrice: savedProduct.DWPrice,
|
||
}
|
||
|
||
var calculate []productv1.CalculateProcess
|
||
c.db.Model(&productv1.CalculateProcess{}).Find(&calculate, "pid = ? AND website = ?", color.VgId, productv1.WebSite_US_Coach_Outlet)
|
||
p.CalCNY(append(calculate, c.calculates...))
|
||
products = append(products, p)
|
||
}
|
||
}
|
||
// 去重
|
||
products = lo.UniqBy(products, func(p productv1.Product) string {
|
||
return p.Pid
|
||
})
|
||
if len(products) == 0 {
|
||
return nil
|
||
}
|
||
lo.ForEach(products, func(p productv1.Product, _ int) {
|
||
p.CalRate()
|
||
if p.Rate >= 15 && p.Orderable {
|
||
c.Push("美国coach outlet有收益大于15%的商品", fmt.Sprintf("coach outlet 商品 %s 收益率达到:%.2f%% \n商品名:%s\n链接:%s", p.Pid, p.Rate, p.Name, p.Link))
|
||
return
|
||
}
|
||
var historyPrice []productv1.HistoryPrice
|
||
c.db.Model(&productv1.HistoryPrice{}).Find(&historyPrice, "pid = ?", p.Pid)
|
||
if len(historyPrice) > 0 {
|
||
historyPrice = lo.Filter(historyPrice, func(item productv1.HistoryPrice, index int) bool {
|
||
return item.OriginalPrice > 0
|
||
})
|
||
lowestPrice := lo.MinBy(historyPrice, func(a productv1.HistoryPrice, b productv1.HistoryPrice) bool {
|
||
return a.OriginalPrice < b.OriginalPrice
|
||
})
|
||
if p.OriginalPrice < lowestPrice.OriginalPrice {
|
||
c.Push("美国coach outlet有商品价格史低", fmt.Sprintf("coach outlet 商品 %s 价格为%.2f之前最低价为:%.2f \n商品名:%s\n链接:%s", p.Pid, p.OriginalPrice, lowestPrice.OriginalPrice, p.Name, p.Link))
|
||
}
|
||
}
|
||
|
||
})
|
||
return c.db.Clauses(clause.OnConflict{
|
||
Columns: []clause.Column{{Name: "pid"}},
|
||
DoUpdates: clause.AssignmentColumns([]string{"name", "color", "link", "orderable", "original_price", "cny_price", "cal_mark", "rate", "price_status", "disc_percent", "updated_at"}),
|
||
}).Create(products).Error
|
||
}
|
||
|
||
func (c *Controller) Push(title, content string) {
|
||
resp, err := pusher.Push(c.ctx, &push.PushReq{
|
||
Ids: []int64{2},
|
||
Title: title,
|
||
Content: content,
|
||
})
|
||
if err != nil {
|
||
glog.Errorf("消息推送失败:%v", err)
|
||
}
|
||
if resp.Code != 0 {
|
||
glog.Errorf("消息推送失败:%s", resp.Msg)
|
||
}
|
||
}
|