You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

453 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package goods
import (
"fmt"
"recook/internal/back"
"recook/internal/dbc"
"recook/internal/model/goods"
"recook/internal/v2/lib/es"
ac2 "recook/internal/v2/model/jyy"
"recook/internal/v2/model/keywords"
goods2 "recook/internal/v2/model/recook/goods"
"recook/internal/v2/model/recook/user"
"recook/internal/v2/model/search_ali"
"recook/tools"
"strings"
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"`
ActivityID uint `json:"activity_id"` // 批发活动商品
IsSale bool `json:"is_sale"`
}
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"`
SalePrice decimal.Decimal `json:"sale_price"`
}
// 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 && p.ActivityID == 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
status := 1
if p.IsSale {
status = 0
}
q3 := mysql2.Db.Table("recook_goods_info as a").Where("is_virtual = 0").Where(goods.Information{
BrandID: p.BrandID,
SecondCategoryID: p.SecondCategoryID,
PublishStatus: uint(status),
})
if p.ActivityID != 0 {
// 批发活动id
sub := mysql2.Db.Table((&ac2.ActivityGoods{}).TableName()).Order("id desc").Select("goods_id").Where("activity_id = ?", p.ActivityID)
ids := make([]uint, 0)
sub.Pluck("goods_id", &ids)
q3 = q3.Clauses(clause.OrderBy{
Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{ids}, WithoutParentheses: true}})
q3 = q3.Where("id in (?) and sale_publish = 1 and is_sale = 1", ids)
}
filters := map[string]interface{}{}
if p.SecondCategoryID > 0 {
filters["brand_id"] = p.BrandID
}
if p.SecondCategoryID > 0 {
filters["second_category_id"] = p.SecondCategoryID
}
findByKeyWord(q3, p.Keyword, filters, &goodsList, p.Page, p.IsSale, false)
back.Suc(c, "", GetGoodsRespByInfoList(goodsList, p.UserId, p.IsSale))
}
func findByKeyWord(q *gorm2.DB, str string, filters map[string]interface{}, data *[]goods.Information, page uint, isSale bool, isCondition bool) {
if str != "" {
gl, _, _ := search_ali.SearchByAliES(str, filters, isSale, 20, int(page))
q = q.Where("a.id in (?)", gl)
if !isCondition {
q = q.Clauses(clause.OrderBy{
Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{gl}, WithoutParentheses: true}})
}
q.Find(&data)
} else {
q.Limit(20).Offset(int(page * 20)).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] }
// QueryGoodsListBySalesVolume 新的按照销量排序
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 && p.ActivityID == 0 {
back.Fail(c, "参数不全")
return
}
status := 1
if p.IsSale {
status = 0
}
var goodsList []goods.Information
order := fmt.Sprintf("vol %s, id desc", p.Order)
q3 := mysql2.Db.Select("a.*, b.vol").Table("recook_goods_info as a").Where("is_virtual = 0").Joins("JOIN (SELECT goods_id, sum(sales_volume + sales_volume_inc ) as vol FROM recook_goods_sku GROUP BY goods_id) as b on a.id = b.goods_id ").Order(order).Where(goods.Information{
BrandID: p.BrandID,
SecondCategoryID: p.SecondCategoryID,
PublishStatus: uint(status),
Country: p.CountryId,
})
if p.ActivityID != 0 {
// 批发活动id
sub := mysql2.Db.Table((&ac2.ActivityGoods{}).TableName()).Select("goods_id").Where("activity_id = ?", p.ActivityID)
q3 = q3.Where("id in (?) and sale_publish = 1 and is_sale = 1", sub)
}
filters := map[string]interface{}{}
if p.SecondCategoryID > 0 {
filters["brand_id"] = p.BrandID
}
if p.SecondCategoryID > 0 {
filters["second_category_id"] = p.SecondCategoryID
}
findByKeyWord(q3, p.Keyword, filters, &goodsList, p.Page, p.IsSale, true)
back.Suc(c, "", GetGoodsRespByInfoList(goodsList, p.UserId, p.IsSale))
}
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 && p.ActivityID == 0 {
back.Fail(c, "参数不全")
return
}
status := 1
orderStr := "discount_price"
if p.IsSale {
status = 0
orderStr = "sale_purchase_price"
}
var goodsList []goods.Information
order := fmt.Sprintf("vol %s, id desc", p.Order)
q3 := mysql2.Db.Select("a.*, b.vol").Table("recook_goods_info as a").Where("is_virtual = 0").Joins(fmt.Sprintf("JOIN (SELECT goods_id, MIN(%s) as vol FROM recook_goods_sku GROUP BY goods_id) as b on a.id = b.goods_id", orderStr)).Order(order).Where(goods.Information{
BrandID: p.BrandID,
SecondCategoryID: p.SecondCategoryID,
PublishStatus: uint(status),
Country: p.CountryId,
})
if p.ActivityID != 0 {
// 批发活动id
sub := mysql2.Db.Table((&ac2.ActivityGoods{}).TableName()).Select("goods_id").Where("activity_id = ?", p.ActivityID)
q3 = q3.Where("id in (?) and sale_publish = 1 and is_sale= 1", sub)
}
filters := map[string]interface{}{}
if p.SecondCategoryID > 0 {
filters["brand_id"] = p.BrandID
}
if p.SecondCategoryID > 0 {
filters["second_category_id"] = p.SecondCategoryID
}
findByKeyWord(q3, p.Keyword, filters, &goodsList, p.Page, p.IsSale, true)
back.Suc(c, "", GetGoodsRespByInfoList(goodsList, p.UserId, p.IsSale))
}
// GetGoodsRespByInfoList ==============================================================
func GetGoodsRespByInfoList(goodsList []goods.Information, userID uint, isSale bool) []QueryCategoryGoodsListResp {
ids := make([]uint, 0)
bids := make([]uint, 0)
for _, v := range goodsList {
ids = append(ids, v.ID)
bids = append(bids, v.BrandID)
}
list := make([]QueryCategoryGoodsListResp, 0)
var u user.RecookUserInfoModel
mysql2.Db.First(&u, "id = ?", userID)
var sku []goods.Sku
mysql2.Db.Select(
"MIN(name), "+
"goods_id, "+
"SUM(inventory) AS inventory, "+
"SUM(sales_volume) AS sales_volume, "+
"SUM(sales_volume_inc) AS sales_volume_inc, "+
"SUM(sale_volume2) AS sale_volume2, "+
"SUM(sale_volume_inc2) AS sale_volume_inc2, "+
"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, "+
"MIN(sale_purchase_price) AS sale_purchase_price, "+
"MIN(extra_price) AS extra_price, "+
"MIN(sale_extra_price) AS sale_extra_price").
Group("goods_id").
Where("goods_id in (?)", ids).
Find(&sku)
skuMap := make(map[uint]goods.Sku)
for _, v := range sku {
skuMap[v.GoodsID] = v
}
var mainPhotoList []goods.MainPhoto
mysql2.Db.Find(&mainPhotoList, "goods_id in (?) AND is_master = 1", ids)
mpMap := make(map[uint]goods.MainPhoto)
for _, v := range mainPhotoList {
mpMap[v.GoodsID] = v
}
var brandList []goods.Brand
mysql2.Db.Find(&brandList, "id in (?)", bids)
brandMap := make(map[uint]goods.Brand)
for _, v := range brandList {
brandMap[v.ID] = v
}
//国家图标放入map结束
for _, v := range goodsList {
if isSale && v.SalePublish != 1 {
continue
}
if !isSale && v.PublishStatus == 0 {
continue
}
ss := skuMap[v.ID]
mp := mpMap[v.ID]
brand := brandMap[v.BrandID]
var startTime = formatime.Second{}
var endTime = formatime.Second{}
inventory := ss.Inventory
salesVolume := ss.SalesVolume + ss.SalesVolumeInc
if isSale {
salesVolume = ss.SaleVolume2 + ss.SaleVolumeInc2
}
commission := ss.GetSelfProfit(u.Level)
tags := make([]string, 0)
recookGoodsInfoModel := &goods2.RecookGoodsInfoModel{}
space := " "
list = append(list, QueryCategoryGoodsListResp{
ID: v.ID,
GoodsName: strings.Join([]string{v.GoodsName, strings.Replace(ss.Name, "+", space, -1)}, space),
BrandName: brand.Name + "品牌馆",
BrandImg: brand.LogoURL,
BrandId: brand.ID,
Description: v.Description,
Inventory: inventory,
SalesVolume: salesVolume,
MainPhotoURL: mp.URL,
PromotionName: "",
OriginalPrice: ss.OriginalPrice,
DiscountPrice: ss.DiscountPrice,
Commission: commission,
Tags: tags,
Percent: 0, //百分比,-1不显示
StartTime: startTime,
EndTime: endTime,
Coupon: ss.Coupon,
IsImport: v.IsImport,
Storehouse: v.Storehouse,
IsFerme: v.IsFerme,
HasCoin: recookGoodsInfoModel.HasCoin(v.Storehouse),
HasBalance: recookGoodsInfoModel.HasBalance(v.Storehouse),
GysId: v.VendorID,
CountryIcon: "",
SalePrice: ss.GetSalePrice(u.Level),
})
}
return list
}
type live struct {
Status int `json:"status"`
RoomId int `json:"room_id"`
}
//func GetGoodsRespBySkuList(skuList []goods.Sku, uid uint, isSale bool) []QueryCategoryGoodsListResp {
// list := make([]QueryCategoryGoodsListResp, 0, 0)
// var u user.RecookUserInfoModel
// mysql2.Db.First(&u, "id = ?", uid)
//
// rate1 := decimal.Zero
// rate2 := decimal.Zero
// rate3 := decimal.Zero
// if u.Level == 1 {
// rate1 = decimal.NewFromFloat32(0.4)
// rate2 = decimal.NewFromFloat32(0.1)
// }
// if u.Level == 2 {
// rate1 = decimal.NewFromFloat32(0.4)
// rate2 = decimal.NewFromFloat32(0.1)
// rate3 = decimal.NewFromFloat32(0.2)
// }
//
// 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)
// if !isSale && goodsInfo.PublishStatus == 0 {
// continue
// }
// if isSale && goodsInfo.SalePublish == 0 {
// continue
// }
// 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 := v.SalesVolume + v.SalesVolumeInc
// discountPrice := v.DiscountPrice
// commission := v.Commission
// inventory = v.Inventory //sku库存
//
// base := v.GetBase()
// commission1 := base.Mul(rate1).Round(2)
// commission2 := base.Mul(rate2).Round(2)
// commission3 := base.Mul(rate3).Round(2)
// fmt.Println(commission1, commission2, commission3, base, v.PurchasePrice, v.DiscountPrice)
// commission = commission1.Add(commission2).Add(commission3)
//
// if u.Level == 10 {
// commission = v.DiscountPrice.Sub(v.PurchasePrice.Mul(decimal.NewFromFloat(1.03))).Mul(decimal.NewFromFloat(define.Coefficient)).Round(2)
// }
//
// 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: "",
// 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: "",
// SalePrice: v.GetSalePrice(u.Level),
// })
// }
// return list
//}
func GetListByLive(goodsList []goods.Information, userID uint, isSale bool) []QueryCategoryGoodsListResp {
return GetGoodsRespByInfoList(goodsList, userID, isSale)
}
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)
}