package goods import ( "fmt" "recook/internal/back" "recook/internal/cache" "recook/internal/dbc" "recook/internal/model/goods" "recook/internal/model/promotion" "recook/internal/v2/lib/es" "recook/internal/v2/model/flashsale" "recook/internal/v2/model/keywords" goods2 "recook/internal/v2/model/recook/goods" "recook/internal/v2/model/recook/user" "recook/tools" "strconv" "strings" "time" mysql2 "git.oa00.com/go/mysql" "github.com/gin-gonic/gin" "github.com/golangkit/formatime" "github.com/shopspring/decimal" gorm2 "gorm.io/gorm" "gorm.io/gorm/clause" ) type queryOrderGoodsListParam struct { SecondCategoryID uint `json:"secondCategoryID"` BrandID uint `json:"brandID"` Page uint `json:"page"` Order string `json:"order"` /*asc 生序 desc 降序*/ Keyword string `json:"keyword" form:"keyword"` /* 搜索的关键字 */ CountryId uint `json:"country_id"` UserId uint `json:"user_id"` Kind uint `json:"kind"` } type QueryCategoryGoodsListResp struct { ID uint `json:"id"` GoodsName string `json:"goodsName"` BrandImg string `json:"brandImg"` BrandName string `json:"brandName"` BrandId uint `json:"brandId"` Description string `json:"description"` Inventory uint `json:"inventory"` // 总库存 SalesVolume uint `json:"salesVolume"` // 总销量 MainPhotoURL string `json:"mainPhotoUrl"` // 主图链接 PromotionName string `json:"promotionName"` OriginalPrice decimal.Decimal `json:"originalPrice"` DiscountPrice decimal.Decimal `json:"discountPrice"` Commission decimal.Decimal `json:"commission"` Tags []string `json:"tags"` // 为产品打上标签,比如 "新人特惠" "限时特卖" Percent uint `json:"percent"` // 活动的%-1代表不是活动 StartTime formatime.Second `json:"startTime"` // 开始时间 EndTime formatime.Second `json:"endTime"` // 结束时间 Coupon decimal.Decimal `gorm:"coupon" json:"coupon"` IsImport int `json:"isImport"` //是否进口商品 Storehouse int `json:"storehouse"` //进口商品仓库 IsFerme int `json:"isFerme"` //是否包税 HasCoin bool `json:"hasCoin"` //是否支持瑞币抵扣 HasBalance bool `json:"hasBalance"` //是否支持余额支付 Living live `json:"living"` //直播中 GysId uint `json:"gys_id"` //供应商id SpecIcon []string `json:"spec_icon"` //特卖活动图标数组 CountryIcon string `json:"country_icon"` //进口国家图标 SecKill SecKillDetail `json:"sec_kill"` } func getFillList(c *gin.Context, goodsList []goods.Information, volSort string) []goods.Information { // 显示记录太少 // 1.用浏览历史记录填充 // 2.用T1 - T4商品记录填充 uid, _ := strconv.Atoi(c.Request.Header.Get("X-Recook-ID")) deviceType := cache.GetDeviceType(c) recookUserLoginModel := user.RecookUserLoginModel{} tokenInfo := recookUserLoginModel.FindByIdAndDeviceType(uint(uid), deviceType) // 购买记录 s11 := mysql2.Db.Select("goods_id").Table("recook_order_goods_detail"). Where("user_id = ?", tokenInfo.UserId) // 已经存在的数据 var id []uint for _, v := range goodsList { id = append(id, v.ID) } add := 20 - len(goodsList) // 浏览记录 sh1 := mysql2.Db.Table("recook_app_user_history").Select("MAX(id)"). Where("user_id = ?", tokenInfo.UserId). Where("goods_id not in (?)", s11). Group("goods_id") if len(id) != 0 { sh1 = sh1.Where("goods_id not in (?)", id) } var args []uint mysql2.Db.Table("recook_app_user_history"). Select("goods_id").Where("id in (?)", sh1).Order("id DESC").Pluck("goods_id", &args) var history []goods.Information query := mysql2.Db.Table("recook_goods_info").Clauses(clause.OrderBy{ Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{args}, WithoutParentheses: true}}). Where("id in (?) AND publish_status = 1", args) if volSort != "" { query = query.Order("sales_volume " + volSort) } query.Limit(add).Find(&history) goodsList = append(goodsList, history...) id = []uint{} for _, v := range goodsList { id = append(id, v.ID) } if len(goodsList) < 20 { // 检索 t1 - t4 add = 20 - len(goodsList) s1 := mysql2.Db.Table("recook_activity_info").Select("MAX(id)"). Where("is_active = 1 AND type > 0").Group("type") s2 := mysql2.Db.Table("recook_activity_goods"). Select("goods_id"). Where("activity_id IN (?)", s1). Where("goods_id NOT IN (?)", s11) if len(id) != 0 { s2 = s2.Where("goods_id not in (?)", id) } var remain []goods.Information query = mysql2.Db.Table("recook_goods_info"). Where("id in (?) AND publish_status = 1", s2) if volSort != "" { query = query.Order("sales_volume " + volSort) } query.Limit(add).Find(&remain) goodsList = append(goodsList, remain...) } return goodsList } // QueryGoodsListByComprehension 综合排序 func QueryGoodsListByComprehension(c *gin.Context) { var p queryOrderGoodsListParam if err := tools.ParseParams(&p, c); err != nil { back.Fail(c, err.Error()) return } if p.SecondCategoryID == 0 && p.BrandID == 0 && len(p.Keyword) == 0 { back.Fail(c, "参数不全") return } //新增模块:存入用户的搜索记录 if p.UserId != 0 && p.Keyword != "" { //条件:用户id和关键词非空 var kw = keywords.RecookUserKeywordsModel{ UserId: p.UserId, Keywords: p.Keyword, CreatedTime: formatime.NewSecondNow(), } dbc.DB.Table(kw.TableName()).Create(&kw) } //新增结束 var goodsList []goods.Information //综合查询中有直播的优先搜索到 //q1 := mysql2.Db.Table("recook_live_live_item").Select("max(id) as id").Group("main_goods_id") //q2 := mysql2.Db.Table("recook_live_live_item").Where("id in (?)", q1) q3 := mysql2.Db.Table("recook_goods_info as a"). Order("id desc").Limit(20).Offset(int(p.Page * 20)).Where(goods.Information{ BrandID: p.BrandID, SecondCategoryID: p.SecondCategoryID, PublishStatus: 1, Country: p.CountryId, }) switch p.Kind { case 1: q3 = q3.Where("vendor_id in (1800, 2000)") case 2: q3 = q3.Where("vendor_id = 1800") case 3: q3 = q3.Where("vendor_id = 2000") } findByKeyWord(q3, p.Keyword, &goodsList) back.Suc(c, "", GetGoodsRespByInfoList(goodsList, p.UserId)) } func findByKeyWord(q *gorm2.DB, str string, data *[]goods.Information) { if len(str) > 0 { r := es.IKReq{ Text: str, Tokenizer: "ik_smart", } res := es.GetIK(r) if len(res.Tokens) <= 1 { q.Find(&data, `goods_name like "%`+str+`%"`) } else { //keys := make([]string, 0) for _, v := range res.Tokens { q = q.Where(`goods_name like "%` + v.Token + `%"`) //keys = append(keys, v.Token) } //score := fmt.Sprintf("MATCH(goods_name) AGAINST('%s' in boolean mode)", strings.Join(keys, "* ")+"*") //selectSql := fmt.Sprintf("a.*, (%s) as score", score) //q.Select(selectSql).Or("MATCH(goods_name) AGAINST(? in boolean mode)", strings.Join(keys, "* ")+"*"). // Order("score desc").Find(&data) q.Find(&data) } } else { q.Find(&data) } } type DescVolGoodsList []goods.Information func (d DescVolGoodsList) Len() int { return len(d) } func (d DescVolGoodsList) Less(i, j int) bool { return d[i].SalesVolume > d[j].SalesVolume } func (d DescVolGoodsList) Swap(i, j int) { d[i], d[j] = d[j], d[i] } type AscVolGoodsList []goods.Information func (d AscVolGoodsList) Len() int { return len(d) } func (d AscVolGoodsList) Less(i, j int) bool { return d[i].SalesVolume < d[j].SalesVolume } func (d AscVolGoodsList) Swap(i, j int) { d[i], d[j] = d[j], d[i] } //新的按照销量排序 func QueryGoodsListBySalesVolume(c *gin.Context) { var p queryOrderGoodsListParam if err := tools.ParseParams(&p, c); err != nil { back.Fail(c, err.Error()) return } if p.SecondCategoryID == 0 && p.BrandID == 0 && len(p.Keyword) == 0 { back.Fail(c, "参数不全") return } var goodsList []goods.Information order := fmt.Sprintf("sales_volume %s, id desc", p.Order) q3 := mysql2.Db.Table("recook_goods_info as a").Limit(20).Order(order).Offset(int(p.Page * 20)).Where(goods.Information{ BrandID: p.BrandID, SecondCategoryID: p.SecondCategoryID, PublishStatus: 1, Country: p.CountryId, }) switch p.Kind { case 1: q3 = q3.Where("vendor_id in (1800, 2000)") case 2: q3 = q3.Where("vendor_id = 1800") case 3: q3 = q3.Where("vendor_id = 2000") } findByKeyWord(q3, p.Keyword, &goodsList) //if p.Kind == 0 { // if len(goodsList) < 20 && p.Page == 0 && p.Keyword != "" { // goodsList = getFillList(c, goodsList, p.Order) // if p.Order != "" { // switch p.Order { // case "desc": // gs := DescVolGoodsList(goodsList) // sort.Sort(gs) // goodsList = gs // case "asc": // gs := AscVolGoodsList(goodsList) // sort.Sort(gs) // goodsList = gs // } // } // } //} back.Suc(c, "", GetGoodsRespByInfoList(goodsList, p.UserId)) } //老的按照销量排序 //func QueryGoodsListBySalesVolume(c *gin.Context) { // var p queryOrderGoodsListParam // if err := tools.ParseParams(&p, c); err != nil { // http.Fail(c, err.Error()) // return // } // // if p.SecondCategoryID == 0 && p.BrandID == 0 { // http.Fail(c, "参数不全") // return // } // // var goodsIdList []uint // // var goodsInfoIdList []goods.Information // dbc.DB.Select("id").Where(goods.Information{ // BrandID: p.BrandID, // SecondCategoryID: p.SecondCategoryID, // PublishStatus: 1, // }).Find(&goodsInfoIdList) // for _, v := range goodsInfoIdList { // goodsIdList = append(goodsIdList, v.ID) // } // // var skuList []goods.Sku // dbc.DB.Select("SUM(inventory) AS inventory, "+ // "SUM(sales_volume) AS sales_volume, "+ // "MIN(original_price) AS original_price, "+ // "MIN(discount_price) AS discount_price, "+ // "MIN(commission) AS commission, "+ // "goods_id"). // Limit(20).Offset(p.Page*20).Order("sales_volume "+p.Order).Group("goods_id"). // Find(&skuList, "goods_id IN (?)", goodsIdList) // // http.Suc(c, "", getGoodsRespBySkuList(skuList)) //} func QueryGoodsListByDiscountPrice(c *gin.Context) { var p queryOrderGoodsListParam if err := tools.ParseParams(&p, c); err != nil { back.Fail(c, err.Error()) return } if p.SecondCategoryID == 0 && p.BrandID == 0 && len(p.Keyword) == 0 { back.Fail(c, "参数不全") return } var goodsIdList []uint var goodsInfoIdList []goods.Information q3 := mysql2.Db.Table("recook_goods_info as a").Where(goods.Information{ BrandID: p.BrandID, SecondCategoryID: p.SecondCategoryID, PublishStatus: 1, Country: p.CountryId, }) switch p.Kind { case 1: q3 = q3.Where("vendor_id in (1800, 2000)") case 2: q3 = q3.Where("vendor_id = 1800") case 3: q3 = q3.Where("vendor_id = 2000") } findByKeyWord(q3, p.Keyword, &goodsInfoIdList) //if p.Kind == 0 { // if len(goodsInfoIdList) < 20 && p.Page == 0 && p.Keyword != "" { // goodsInfoIdList = getFillList(c, goodsInfoIdList, "") // } //} for _, v := range goodsInfoIdList { goodsIdList = append(goodsIdList, v.ID) } var skuList []goods.Sku order := fmt.Sprintf("discount_price %s", p.Order) dbc.DB.Select("SUM(inventory) AS inventory, "+ "SUM(sales_volume) AS sales_volume, "+ "MIN(original_price) AS original_price, "+ "MIN(discount_price) AS discount_price, "+ "MIN(commission) AS commission, "+ "goods_id"). Limit(20).Offset(p.Page*20).Order(order).Group("goods_id"). Find(&skuList, "goods_id IN (?)", goodsIdList) back.Suc(c, "", GetGoodsRespBySkuList(skuList)) } // GetGoodsRespByInfoList ============================================================== func GetGoodsRespByInfoList(goodsList []goods.Information, userID uint) []QueryCategoryGoodsListResp { list := make([]QueryCategoryGoodsListResp, 0) var u user.RecookUserInfoModel mysql2.Db.First(&u, "id = ?", userID) //国家图标放入map结束 for _, v := range goodsList { var mainPhoto goods.MainPhoto dbc.DB.Select("url").First(&mainPhoto, "goods_id = ? AND is_master = 1", v.ID) gb := goods.Brand{} dbc.DB.First(&gb, "id = ?", v.BrandID) var sku goods.Sku mysql2.Db.Select( "MIN(name), "+ "SUM(inventory) AS inventory, "+ "SUM(sales_volume) AS sales_volume, "+ "MIN(purchase_price) AS purchase_price,"+ "MIN(original_price) AS original_price, "+ "MIN(discount_price) AS discount_price, "+ "MIN(commission) AS commission,"+ "MIN(coupon) AS coupon"). Where("goods_id = ?", v.ID). Group("goods_id"). Find(&sku) //var inventory uint //var percent uint var startTime = formatime.Second{} var endTime = formatime.Second{} inventory := sku.Inventory salesVolume := v.SalesVolume discountPrice := sku.DiscountPrice commission := sku.Commission now := time.Now() var tags = make([]string, 0, 0) var promotionGoods promotion.Goods mysql2.Db.Select("id, promotion_name, start_time, end_time").First(&promotionGoods, "goods_id = ? AND start_time <= ? AND end_time >= ?", v.ID, now, now) if promotionGoods.ID > 0 { var promotionSku promotion.Sku mysql2.Db.Select("SUM(inventory) AS inventory, SUM(sales_volume) AS sales_volume, MIN(discount_price) as discount_price , MIN(commission) as commission"). Where("promotion_goods_id = ?", promotionGoods.ID). Group("promotion_goods_id").Find(&promotionSku) discountPrice = promotionSku.DiscountPrice //活动的价格 //commission = promotionSku.Commission //活动的佣金 inventory = promotionSku.Inventory //活动的库存 startTime = promotionGoods.StartTime endTime = promotionGoods.EndTime // 打上特卖标签 tags = append(tags, "限时特卖") } else { // 再判断商品明天会不会参加活动 mysql2.Db.Select("id, promotion_name").First(&promotionGoods, "goods_id = ? AND start_time > ? ", v.ID, now) if promotionGoods.ID > 0 { var promotionSku promotion.Sku dbc.DB.Select("MIN(discount_price) AS discount_price, MIN(commission) AS commission"). Where("promotion_goods_id = ?", promotionGoods.ID). Group("promotion_goods_id"). Find(&promotionSku) startTime = promotionGoods.StartTime endTime = promotionGoods.EndTime } } // 查看是否是 新人特惠 商品 if isMember, _ := cache.IsMemberOfNewerTehui(strconv.Itoa(int(v.ID))); isMember { tags = append(tags, "新人特惠") } rate := decimal.Zero switch u.Level { case 1: rate = decimal.NewFromFloat(0.5) case 2: rate = decimal.NewFromFloat(0.7) } fmt.Println(u.Level, sku.DiscountPrice, sku.PurchasePrice) commission = sku.DiscountPrice.Sub(sku.PurchasePrice).Mul(rate) recookGoodsInfoModel := &goods2.RecookGoodsInfoModel{} space := " " list = append(list, QueryCategoryGoodsListResp{ ID: v.ID, GoodsName: strings.Join([]string{v.GoodsName, strings.Replace(sku.Name, "+", space, -1)},space), BrandName: gb.Name + "品牌馆", BrandImg: gb.LogoURL, BrandId: gb.ID, Description: v.Description, Inventory: inventory, SalesVolume: salesVolume, MainPhotoURL: mainPhoto.URL, PromotionName: "", OriginalPrice: sku.OriginalPrice, DiscountPrice: discountPrice, Commission: commission, Tags: tags, Percent: 0, //百分比,-1不显示 StartTime: startTime, EndTime: endTime, Coupon: sku.Coupon, IsImport: v.IsImport, Storehouse: v.Storehouse, IsFerme: v.IsFerme, HasCoin: recookGoodsInfoModel.HasCoin(v.Storehouse), HasBalance: recookGoodsInfoModel.HasBalance(v.Storehouse), GysId: v.VendorID, CountryIcon: , }) } return list } type live struct { Status int `json:"status"` RoomId int `json:"room_id"` } func GetGoodsRespBySkuList(skuList []goods.Sku) []QueryCategoryGoodsListResp { list := make([]QueryCategoryGoodsListResp, 0, 0) for _, v := range skuList { var mainPhoto goods.MainPhoto dbc.DB.Select("url").First(&mainPhoto, "goods_id = ? AND is_master = 1", v.GoodsID) var goodsInfo goods.Information dbc.DB.First(&goodsInfo, v.GoodsID) gb := goods.Brand{} dbc.DB.First(&gb, "id = ?", goodsInfo.BrandID) var inventory uint //var percent uint var startTime = formatime.Second{} var endTime = formatime.Second{} salesVolume := goodsInfo.SalesVolume discountPrice := v.DiscountPrice commission := v.Commission inventory = v.Inventory //sku库存 now := time.Now() var promotionGoods promotion.Goods dbc.DB.Select("id, promotion_name, start_time, end_time"). First(&promotionGoods, "goods_id = ? AND start_time <= ? AND end_time >= ?", v.GoodsID, now, now) if promotionGoods.ID > 0 { var promotionSku promotion.Sku dbc.DB.Select("SUM(inventory) AS inventory, SUM(sales_volume) AS sales_volume,min(discount_price) as discount_price,min(discount_price) as discount_price"). First(&promotionSku, "promotion_goods_id = ?", promotionGoods.ID) discountPrice = promotionSku.DiscountPrice //活动的价格 commission = promotionSku.Commission //活动的佣金 inventory = promotionSku.Inventory salesVolume = promotionSku.SalesVolume //计算% //percent = uint(salesVolume / (inventory + salesVolume) * 100) startTime = promotionGoods.StartTime endTime = promotionGoods.EndTime } else { dbc.DB.Select("id, promotion_name"). First(&promotionGoods, "goods_id = ? AND start_time > ?", v.GoodsID, now) if promotionGoods.ID > 0 { var promotionSku promotion.Sku dbc.DB.Select("MIN(discount_price) AS discount_price, MIN(commission) AS commission").Find(&promotionSku, "promotion_goods_id = ?", promotionGoods.ID) startTime = promotionGoods.StartTime endTime = promotionGoods.EndTime } } //新增进口专区国家图标 //var iconList []goods2.RecookAbroadCountryModel //dbc.DB.Table((&goods2.RecookAbroadCountryModel{}).TableName()).Find(&iconList) //var countryMap = make(map[uint]string) //countryMap[0] = "" //for _, j := range iconList { // countryMap[j.ID] = j.Icon //} //fmt.Println(len(countryMap)) //国家图标放入map结束 recookGoodsInfoModel := &goods2.RecookGoodsInfoModel{} list = append(list, QueryCategoryGoodsListResp{ ID: v.GoodsID, GoodsName: goodsInfo.GoodsName, BrandImg: gb.LogoURL, BrandName: gb.Name + "品牌馆", BrandId: gb.ID, Description: goodsInfo.Description, Inventory: inventory, SalesVolume: salesVolume, MainPhotoURL: mainPhoto.URL, PromotionName: promotionGoods.PromotionName, OriginalPrice: v.OriginalPrice, DiscountPrice: discountPrice, Commission: commission, Percent: 0, //百分比,-1不显示 StartTime: startTime, EndTime: endTime, Coupon: v.Coupon, IsImport: goodsInfo.IsImport, Storehouse: goodsInfo.Storehouse, IsFerme: goodsInfo.IsFerme, HasCoin: recookGoodsInfoModel.HasCoin(goodsInfo.Storehouse), HasBalance: recookGoodsInfoModel.HasBalance(goodsInfo.Storehouse), GysId: goodsInfo.VendorID, CountryIcon: "", }) } return list } func GetListByLive(goodsList []goods.Information) []QueryCategoryGoodsListResp { //return GetGoodsRespByInfoList(goodsList) return nil } func secKillAbout(list []QueryCategoryGoodsListResp) (result []QueryCategoryGoodsListResp) { //新增秒杀的图标 //获取当前时间段的秒杀商品 now := time.Now() var seckill flashsale.RecookSecKillModel dbc.DB.Table(seckill.TableName()).Where("activity_start_time?", now).Where("status=2").First(&seckill) smp := GetSecKillGoods() fmt.Println(len(smp)) for i, v := range list { if _, ok := smp[v.ID]; ok { one := GetSecKillDetail(v.ID) list[i].SecKill = one } else { continue } } result = list return } func GetSecKillGoods() map[uint]uint { now := time.Now() var seckill flashsale.RecookSecKillModel dbc.DB.Table(seckill.TableName()).Where("activity_start_time?", now).Where("status=2").First(&seckill) //获取当前时间段的商品 now2 := time.Date(0, 1, 1, now.Hour(), now.Minute(), now.Second(), 0, time.Local) var sgal []int64 q := dbc.DB.Table((&flashsale.RecookSecKillSortModel{}).TableName()).Where("show_time_start?", now2).Where("sec_kill_activity_id=?", seckill.Id) q.Group("goods_id").Pluck("goods_id", &sgal) smp := make(map[uint]uint) for _, i2 := range sgal { smp[uint(i2)] = 1 } return smp } func GetSecKillDetail(gi uint) SecKillDetail { now := time.Now() var seckill flashsale.RecookSecKillModel dbc.DB.Table(seckill.TableName()).Where("activity_start_time?", now).Where("status=2").First(&seckill) var sk flashsale.RecookSecKillGoodsModel dbc.DB.Table(sk.TableName()).Where("sec_kill_activity_id=?", seckill.Id).Where("goods_id=?", gi).First(&sk) now2 := time.Date(0, 1, 1, now.Hour(), now.Minute(), now.Second(), 0, time.Local) secMinPrice := decimal.Zero secCommission := decimal.Zero MaxStock := decimal.Zero //sku_list var skuList []flashsale.RecookSecKillGoodsModel var sl []int q := dbc.DB.Table((&flashsale.RecookSecKillSortModel{}).TableName()).Where("show_time_start?", now2).Where("sec_kill_activity_id=?", sk.SecKillActivityId) q.Select("sku_id").Where("goods_id=?", sk.GoodsId).Pluck("sku_id", &sl) dbc.DB.Table(sk.TableName()).Where("sec_kill_activity_id=?", sk.SecKillActivityId).Where("goods_id=?", sk.GoodsId).Where("goods_sku_id in (?)", sl).Find(&skuList) secEndTime := time.Time{} for i1, model := range skuList { var sec flashsale.RecookSecKillSortModel q.Where("goods_id=?", sk.GoodsId).Where("sku_id=?", model.GoodsSkuId).First(&sec) if i1 == 0 { secMinPrice = model.SecKillDiscountPrice secCommission = model.SecKillCommission secEndTime = sec.ShowTimeEnd MaxStock = model.RealStock } else { if secMinPrice.GreaterThan(model.SecKillDiscountPrice) { secMinPrice = model.SecKillDiscountPrice } if secCommission.LessThan(model.SecKillCommission) { secCommission = model.SecKillCommission } if sec.ShowTimeEnd.After(secEndTime) { secEndTime = sec.ShowTimeEnd } if MaxStock.LessThan(model.RealStock) { MaxStock = model.RealStock } } } one := SecKillDetail{ SecKill: 1, SecKillEndTime: secEndTime.Format("15:04:05"), SecKillMinPrice: secMinPrice, SecKillCommission: secCommission, RealStock: MaxStock, } return one } func KeyWordEs(c *gin.Context) { var p queryOrderGoodsListParam if err := tools.ParseParams(&p, c); err != nil { back.Fail(c, err.Error()) return } r := es.IKReq{ Text: p.Keyword, Tokenizer: "ik_smart", } res := es.GetIK(r) back.Suc(c, "", res.Tokens) }