91 lines
3.9 KiB
Go
91 lines
3.9 KiB
Go
|
|
// 功能描述:按购物车或收藏关联分类推荐真实在售商品;版本:1.0.0。
|
|||
|
|
package user
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"git.apinb.com/bsm-sdk/core/errcode"
|
|||
|
|
"git.apinb.com/bsm-sdk/core/infra"
|
|||
|
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
|
|||
|
|
common "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
|||
|
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
|||
|
|
"github.com/gin-gonic/gin"
|
|||
|
|
"gorm.io/gorm"
|
|||
|
|
"gorm.io/gorm/clause"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// Recommendations 排除本人已入购物车商品,收藏场景另排除已收藏;相同分类优先,其余按最近更新排序。
|
|||
|
|
func Recommendations(ctx *gin.Context) {
|
|||
|
|
account, ok := common.UserAccount(ctx)
|
|||
|
|
if !ok {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
var request struct {
|
|||
|
|
Source string `form:"source,default=cart" binding:"oneof=cart favorites"`
|
|||
|
|
Page int `form:"page,default=1" binding:"gte=1,lte=10000"`
|
|||
|
|
Size int `form:"page_size,default=2" binding:"gte=1,lte=20"`
|
|||
|
|
}
|
|||
|
|
if ctx.ShouldBindQuery(&request) != nil {
|
|||
|
|
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
query := impl.DBService.Where("status = ? AND stock_quantity > 0", common.StatusEnable).
|
|||
|
|
Where("NOT EXISTS (SELECT 1 FROM ec_cart c WHERE c.ec_product_id = ec_product.id AND c.user_account_id = ? AND c.status = ? AND c.deleted_at IS NULL)", account.ID, common.StatusEnable)
|
|||
|
|
table := "ec_cart"
|
|||
|
|
if request.Source == "favorites" {
|
|||
|
|
table = "ec_favorite"
|
|||
|
|
query = query.Where("NOT EXISTS (SELECT 1 FROM ec_favorite f WHERE f.ec_product_id = ec_product.id AND f.user_account_id = ? AND f.status = ? AND f.deleted_at IS NULL)", account.ID, common.StatusEnable)
|
|||
|
|
}
|
|||
|
|
// 表名来自固定枚举,用户输入不拼接进SQL;归属只使用JWT对应的内部账户键。
|
|||
|
|
rank := "CASE WHEN EXISTS (SELECT 1 FROM " + table + " r JOIN ec_product p ON p.id = r.ec_product_id WHERE r.user_account_id = ? AND r.status = ? AND r.deleted_at IS NULL AND p.ec_category_id = ec_product.ec_category_id) THEN 0 ELSE 1 END"
|
|||
|
|
var products []models.EcProduct
|
|||
|
|
if err := query.Clauses(clause.OrderBy{Expression: gorm.Expr(rank+", ec_product.updated_at desc, ec_product.identity", account.ID, common.StatusEnable)}).Offset((request.Page - 1) * request.Size).Limit(request.Size + 1).Find(&products).Error; err != nil {
|
|||
|
|
infra.Response.Error(ctx, err)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
values, err := recommendationValues(impl.DBService, products)
|
|||
|
|
if err != nil {
|
|||
|
|
infra.Response.Error(ctx, err)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
respondClientPage(ctx, clientPage{Number: request.Page, Size: request.Size}, values)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// recommendationValues 批量读取主图和分类,公开结果只包含展示和下单所需字段。
|
|||
|
|
func recommendationValues(db *gorm.DB, products []models.EcProduct) ([]gin.H, error) {
|
|||
|
|
result := make([]gin.H, 0, len(products))
|
|||
|
|
if len(products) == 0 {
|
|||
|
|
return result, nil
|
|||
|
|
}
|
|||
|
|
ids := make([]uint64, 0, len(products))
|
|||
|
|
categoryIDs := []uint64{}
|
|||
|
|
seen := map[uint64]bool{}
|
|||
|
|
for _, p := range products {
|
|||
|
|
ids = append(ids, p.ID)
|
|||
|
|
if !seen[p.EcCategoryID] {
|
|||
|
|
seen[p.EcCategoryID] = true
|
|||
|
|
categoryIDs = append(categoryIDs, p.EcCategoryID)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
var images []models.EcProductImage
|
|||
|
|
if err := db.Where("ec_product_id IN ? AND status = ?", ids, common.StatusEnable).Order("is_cover desc, sort_no, identity").Find(&images).Error; err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
imageMap := map[uint64]string{}
|
|||
|
|
for _, i := range images {
|
|||
|
|
if _, ok := imageMap[i.EcProductID]; !ok {
|
|||
|
|
imageMap[i.EcProductID] = i.ImageURI
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
var categories []models.EcCategory
|
|||
|
|
if err := db.Where("id IN ? AND status = ?", categoryIDs, common.StatusEnable).Find(&categories).Error; err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
categoryMap := map[uint64]string{}
|
|||
|
|
for _, c := range categories {
|
|||
|
|
categoryMap[c.ID] = c.Name
|
|||
|
|
}
|
|||
|
|
for _, p := range products {
|
|||
|
|
result = append(result, gin.H{"identity": p.Identity, "name": p.Name, "price_amount": p.PriceAmount, "stock_quantity": p.StockQuantity, "image_url": imageMap[p.ID], "category_name": categoryMap[p.EcCategoryID]})
|
|||
|
|
}
|
|||
|
|
return result, nil
|
|||
|
|
}
|