This commit is contained in:
laodaming 2023-06-13 17:47:48 +08:00
parent da347feac9
commit d941402ef1
13 changed files with 502 additions and 18 deletions

3
constants/cart.go Normal file
View File

@ -0,0 +1,3 @@
package constants
const CART_EXPIRE_TIME = 60 //购物车过期时间

View File

@ -96,3 +96,17 @@ func (c *FsCartModel) CountUserCart(ctx context.Context, userId int64) (total in
}
return
}
func (c *FsCartModel) GetAllByUserId(ctx context.Context, userId int64, sort string) (resp []FsCart, err error) {
db := c.db.WithContext(ctx).Model(&FsCart{}).Where("`user_id` = ? and `status` = ?", userId, 1)
switch sort {
case "ctime-desc":
db = db.Order("`ctime` DESC")
case "ctime-asc":
db = db.Order("`ctime` ASC")
}
err = db.Find(&resp).Error
if err != nil {
return nil, err
}
return
}

View File

@ -40,3 +40,13 @@ func (d *FsProductDesignModel) FindOneBySn(ctx context.Context, sn string) (resp
}
return resp, nil
}
func (d *FsProductDesignModel) GetAllByIds(ctx context.Context, ids []int64) (resp []FsProductDesign, err error) {
if len(ids) == 0 {
return
}
err = d.db.WithContext(ctx).Model(&FsProductDesign{}).Where("`id` in (?) and `status` = ?", ids, 1).Find(&resp).Error
if err != nil {
return nil, err
}
return
}

View File

@ -1,6 +1,9 @@
package gmodel
import "gorm.io/gorm"
import (
"context"
"gorm.io/gorm"
)
type FsProductModel3d struct {
Id int64 `gorm:"primary_key" json:"id"`
@ -29,3 +32,23 @@ type FsProductModel3dModel struct {
func NewFsProductModel3dModel(db *gorm.DB) *FsProductModel3dModel {
return &FsProductModel3dModel{db}
}
func (d *FsProductModel3dModel) GetAllByIds(ctx context.Context, ids []int64) (resp []FsProductModel3d, err error) {
if len(ids) == 0 {
return
}
err = d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` in (?) and `status` = ?", ids, 1).Find(&resp).Error
if err != nil {
return nil, err
}
return
}
func (d *FsProductModel3dModel) GetAllByIdsTag(ctx context.Context, ids []int64, tag int64) (resp []FsProductModel3d, err error) {
if len(ids) == 0 {
return
}
err = d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` in (?) and `status` = ? and `tag` = ?", ids, 1, tag).Find(&resp).Error
if err != nil {
return nil, err
}
return
}

View File

@ -34,7 +34,7 @@ type GetPriceListByProductIdsRsp struct {
Price string `json:"price"`
}
func (p *FsProductPriceModel) GetPriceListByProductIds(ctx context.Context, productIds []int64) (resp []GetPriceListByProductIdsRsp, err error) {
func (p *FsProductPriceModel) GetSimplePriceListByProductIds(ctx context.Context, productIds []int64) (resp []GetPriceListByProductIdsRsp, err error) {
if len(productIds) == 0 {
return nil, nil
}
@ -82,3 +82,14 @@ func (p *FsProductPriceModel) FindOneProductPriceByParams(ctx context.Context, r
}
return resp, nil
}
func (p *FsProductPriceModel) GetPriceListByProductIds(ctx context.Context, productIds []int64) (resp []FsProductPrice, err error) {
if len(productIds) == 0 {
return nil, nil
}
db := p.db.WithContext(ctx).Model(&FsProductPrice{}).
Where("`product_id` in (?) and `status` = ?", productIds, 1)
if err = db.Find(&resp).Error; err != nil {
return nil, err
}
return
}

View File

@ -77,7 +77,7 @@ func (l *GetProductListLogic) GetProductList(req *types.GetProductListReq, login
productIds = append(productIds, v.Id)
}
productPriceModel := gmodel.NewFsProductPriceModel(l.svcCtx.MysqlConn)
productPriceList, err := productPriceModel.GetPriceListByProductIds(l.ctx, productIds)
productPriceList, err := productPriceModel.GetSimplePriceListByProductIds(l.ctx, productIds)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product min price list")

View File

@ -9,6 +9,7 @@ import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/format"
"fusenapi/utils/step_price"
"strings"
"fusenapi/server/product/internal/svc"
@ -167,7 +168,7 @@ func (l *GetSizeByProductLogic) GetSecondChildrenList(product gmodel.FsProduct,
for int(*price.MinBuyNum) < (stepNum[len(stepNum)-1]+5) && index < 3 {
priceList = append(priceList, types.PriceObj{
Num: int(*price.MinBuyNum * *price.EachBoxNum),
Price: l.GetPrice(int(*price.MinBuyNum), stepNum, stepPrice),
Price: step_price.GetStepPrice(int(*price.MinBuyNum), stepNum, stepPrice),
})
*price.MinBuyNum++
index++
@ -181,17 +182,3 @@ func (l *GetSizeByProductLogic) GetSecondChildrenList(product gmodel.FsProduct,
}
return
}
func (l *GetSizeByProductLogic) GetPrice(minBuyNum int, stepNum []int, stepPrice []int) float64 {
if minBuyNum > stepNum[len(stepNum)-1] {
return float64(stepPrice[len(stepPrice)-1]) / float64(100)
}
for k, v := range stepNum {
if minBuyNum <= v {
if k <= (len(stepPrice) - 1) {
return float64(stepPrice[k]) / float64(100)
}
return float64(stepPrice[len(stepPrice)-1]) / float64(100)
}
}
return float64(stepPrice[len(stepPrice)-1]) / float64(100)
}

View File

@ -0,0 +1,67 @@
package handler
import (
"errors"
"net/http"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/rest/httpx"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/server/shopping-cart-confirmation/internal/logic"
"fusenapi/server/shopping-cart-confirmation/internal/svc"
"fusenapi/server/shopping-cart-confirmation/internal/types"
)
func CartListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 解析jwtToken
/*claims, err := svcCtx.ParseJwtToken(r)
// 如果解析出错则返回未授权的JSON响应并记录错误消息
if err != nil {
httpx.OkJsonCtx(r.Context(), w, &basic.Response{
Code: 401,
Message: "unauthorized",
})
logx.Info("unauthorized:", err.Error())
return
}
// 从Token里获取对应的信息
userinfo, err := auth.GetUserInfoFormMapClaims(claims)
// 如果获取用户信息出错则返回未授权的JSON响应并记录错误消息
if err != nil {
httpx.OkJsonCtx(r.Context(), w, &basic.Response{
Code: 401,
Message: "unauthorized",
})
logx.Info("unauthorized:", err.Error())
return
}
*/
var req types.CartListReq
// 如果端点有请求结构体则使用httpx.Parse方法从HTTP请求体中解析请求数据
if err := httpx.Parse(r, &req); err != nil {
httpx.OkJsonCtx(r.Context(), w, &basic.Response{
Code: 510,
Message: "parameter error",
})
logx.Info(err)
return
}
// 创建一个业务逻辑层实例
l := logic.NewCartListLogic(r.Context(), svcCtx)
resp := l.CartList(&req, &auth.UserInfo{86})
// 如果响应不为nil则使用httpx.OkJsonCtx方法返回JSON响应;
// 否则发送500内部服务器错误的JSON响应并记录错误消息logx.Error。
if resp != nil {
httpx.OkJsonCtx(r.Context(), w, resp)
} else {
err := errors.New("server logic is error, resp must not be nil")
httpx.ErrorCtx(r.Context(), w, err)
logx.Error(err)
}
}
}

View File

@ -27,6 +27,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/cart/num",
Handler: CartNumberHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/cart/list",
Handler: CartListHandler(serverCtx),
},
},
)
}

View File

@ -0,0 +1,273 @@
package logic
import (
"encoding/json"
"errors"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/format"
"fusenapi/utils/image"
"fusenapi/utils/step_price"
"strings"
"sync"
"time"
"context"
"fusenapi/server/shopping-cart-confirmation/internal/svc"
"fusenapi/server/shopping-cart-confirmation/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type CartListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewCartListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CartListLogic {
return &CartListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 获取用户购物车列表
func (l *CartListLogic) CartList(req *types.CartListReq, userinfo *auth.UserInfo) (resp *basic.Response) {
//获取当前图片应该返回的尺寸大小
if req.Size > 0 {
req.Size = image.GetCurrentSize(req.Size)
}
//获取用户购物车数据
cartRelativeData, err := l.getUserCartRelativeList(l.ctx, userinfo.UserId)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get cart list data")
}
if len(cartRelativeData.CartList) == 0 {
return resp.SetStatusWithMessage(basic.CodeOK, "success")
}
//产品名map
mapProduct := make(map[int64]int)
for k, v := range cartRelativeData.ProductList {
mapProduct[v.Id] = k
}
//产品尺寸size map
mapProductSize := make(map[int64]int)
for k, v := range cartRelativeData.ProductSizeList {
mapProductSize[v.Id] = k
}
//设计map数据
mapProductDesign := make(map[int64]int)
for k, v := range cartRelativeData.ProductDesignList {
mapProductDesign[v.Id] = k
}
//产品模型map数据
mapProductModel3d := make(map[int64]int)
for k, v := range cartRelativeData.ProductModel3dList {
mapProductModel3d[v.Id] = k
}
//遍历组装数据
rspList := make([]types.CartListRsp, 0, len(cartRelativeData.CartList))
for _, v := range cartRelativeData.CartList {
name := ""
productSn := ""
if productIndex, ok := mapProduct[*v.ProductId]; ok {
name = *cartRelativeData.ProductList[productIndex].Title
productSn = strings.ToLower(*cartRelativeData.ProductList[productIndex].Sn)
}
capacity := ""
var sizeList types.CartSizeItem
if sizeIndex, ok := mapProductSize[*v.SizeId]; ok {
capacity = *cartRelativeData.ProductSizeList[sizeIndex].Capacity
err = json.Unmarshal([]byte(*cartRelativeData.ProductSizeList[sizeIndex].Title), &sizeList)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to parse product size`s title")
}
}
designSn := ""
if designIndex, ok := mapProductDesign[*v.DesignId]; ok {
designSn = strings.ToLower(*cartRelativeData.ProductDesignList[designIndex].Sn)
}
option := types.CartOption{}
if model3dIndex, ok := mapProductModel3d[*v.OptionalId]; ok {
option.Id = cartRelativeData.ProductModel3dList[model3dIndex].Id
option.Title = *cartRelativeData.ProductModel3dList[model3dIndex].Title
option.Price = float64(*cartRelativeData.ProductModel3dList[model3dIndex].Price) / float64(100)
}
pcList, err := l.getPcList(cartRelativeData.ProductPriceList, *v.ProductId, *v.MaterialId, *v.SizeId)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to calculate step price")
}
rspList = append(rspList, types.CartListRsp{
Id: v.Id,
Cover: *v.Cover,
Name: name,
Capacity: capacity,
ETA: time.Now().AddDate(0, 0, 60).Format("2006-01-02 15:04:05"),
Pcs: *v.BuyNum,
ProductSn: productSn,
DesignSn: designSn,
Option: option,
IsCheck: *v.IsCheck,
TsTime: v.TsTime.Format("2006-01-02 15:04:05"),
PcsList: pcList,
Size: sizeList,
})
}
return resp.SetStatusWithMessage(basic.CodeOK, "success", rspList)
}
type GetUserCartRelativeListRsp struct {
CartList []gmodel.FsCart
ProductDesignList []gmodel.FsProductDesign
ProductSizeList []gmodel.FsProductSize
ProductList []gmodel.FsProduct
ProductModel3dList []gmodel.FsProductModel3d
ProductTemplateV2List []gmodel.FsProductTemplateV2
ProductPriceList []gmodel.FsProductPrice
}
// 获取阶梯对应的价格
func (l *CartListLogic) getPcList(productPriceList []gmodel.FsProductPrice, productId int64, materialId int64, sizeId int64) (list []types.PcsItem, err error) {
for _, price := range productPriceList {
if *price.ProductId != productId || *price.MaterialId != materialId || *price.SizeId != sizeId {
continue
}
stepNumStrSlice := strings.Split(*price.StepNum, ",")
stepNumSlice, err := format.StrSlicToIntSlice(stepNumStrSlice)
if err != nil {
return nil, err
}
stepPriceStrSlice := strings.Split(*price.StepPrice, ",")
stepPriceSlice, err := format.StrSlicToIntSlice(stepPriceStrSlice)
if err != nil {
return nil, err
}
lenStepPriceSlice := len(stepPriceSlice)
lenStepNumSlice := len(stepNumSlice)
if lenStepPriceSlice == 0 || lenStepNumSlice == 0 {
return nil, errors.New("step num or step price item count can`t be 0 ")
}
for int(*price.MinBuyNum) < stepNumSlice[lenStepNumSlice-1]+5 {
list = append(list, types.PcsItem{
Num: *price.MinBuyNum,
TotalNum: *price.MinBuyNum * *price.EachBoxNum,
Title: *price.Title,
Price: step_price.GetStepPrice(int(*price.MinBuyNum), stepNumSlice, stepPriceSlice),
})
*price.MinBuyNum++
}
}
return list, nil
}
// 获取用户购物车数据
func (l *CartListLogic) getUserCartRelativeList(ctx context.Context, userId int64) (resp GetUserCartRelativeListRsp, err error) {
//购物车列表
cartModel := gmodel.NewFsCartModel(l.svcCtx.MysqlConn)
cartList, err := cartModel.GetAllByUserId(ctx, userId, "ctime-desc")
if err != nil {
return GetUserCartRelativeListRsp{}, err
}
if len(cartList) == 0 {
return
}
resp.CartList = cartList
productIds := make([]int64, 0, len(cartList))
sizeIds := make([]int64, 0, len(cartList))
designIds := make([]int64, 0, len(cartList))
optionIds := make([]int64, 0, len(cartList))
templateIds := make([]int64, 0, len(cartList))
for _, v := range cartList {
productIds = append(productIds, *v.ProductId)
sizeIds = append(sizeIds, *v.SizeId)
designIds = append(designIds, *v.DesignId)
optionIds = append(optionIds, *v.OptionalId)
templateIds = append(templateIds, *v.TemplateId)
}
//******************************协程并发开始***********************************
wait := sync.WaitGroup{}
gorutine := 6 //注意要加协程这里要记得加
errChan := make(chan error, gorutine)
wait.Add(gorutine)
//获取产品数据1
go func() {
defer wait.Done()
productModel := gmodel.NewFsProductModel(l.svcCtx.MysqlConn)
productList, err := productModel.GetProductListByIds(ctx, productIds, "")
if err != nil {
errChan <- err
return
}
resp.ProductList = productList
}()
//获取尺寸数据2
go func() {
defer wait.Done()
productSizeModel := gmodel.NewFsProductSizeModel(l.svcCtx.MysqlConn)
productSizeList, err := productSizeModel.GetAllByIds(ctx, sizeIds, "")
if err != nil {
errChan <- err
}
resp.ProductSizeList = productSizeList
}()
//获取设计列表3
go func() {
defer wait.Done()
productDesignModel := gmodel.NewFsProductDesignModel(l.svcCtx.MysqlConn)
productDesignList, err := productDesignModel.GetAllByIds(ctx, designIds)
if err != nil {
errChan <- err
}
resp.ProductDesignList = productDesignList
}()
//获取配件列表4
go func() {
defer wait.Done()
productModel3dModel := gmodel.NewFsProductModel3dModel(l.svcCtx.MysqlConn)
productModel3dList, err := productModel3dModel.GetAllByIdsTag(ctx, optionIds, constants.TAG_PARTS)
if err != nil {
errChan <- err
}
resp.ProductModel3dList = productModel3dList
}()
//获取模板信息5
go func() {
defer wait.Done()
productTemplateModel := gmodel.NewFsProductTemplateV2Model(l.svcCtx.MysqlConn)
templateV2List, err := productTemplateModel.FindAllByProductIds(ctx, templateIds)
if err != nil {
errChan <- err
}
resp.ProductTemplateV2List = templateV2List
}()
//获取产品价格列表6
go func() {
defer wait.Done()
productPriceModel := gmodel.NewFsProductPriceModel(l.svcCtx.MysqlConn)
productPriceList, err := productPriceModel.GetPriceListByProductIds(ctx, productIds)
if err != nil {
errChan <- err
}
resp.ProductPriceList = productPriceList
}()
//******************************协程并发结束***********************************
go func() {
wait.Wait()
close(errChan)
}()
//获取错误信息
for err = range errChan {
if err != nil {
return GetUserCartRelativeListRsp{}, err
}
}
return resp, nil
}

View File

@ -19,6 +19,44 @@ type CartNumberRsp struct {
Num int64 `json:"num"`
}
type CartListReq struct {
Size uint32 `form:"size"`
}
type CartListRsp struct {
Id int64 `json:"id"`
Cover string `json:"cover"`
Name string `json:"name"`
Capacity string `json:"capacity"`
ETA string `json:"ETA"`
Pcs int64 `json:"pcs"`
ProductSn string `json:"product_sn"`
DesignSn string `json:"designSn"`
Option CartOption `json:"option"`
IsCheck int64 `json:"is_check"`
TsTime string `json:"ts_time"`
PcsList []PcsItem `json:"pcs_list"`
Size CartSizeItem `json:"size"`
}
type CartOption struct {
Id int64 `json:"id"`
Title string `json:"title"`
Price float64 `json:"price"`
}
type PcsItem struct {
Num int64 `json:"num"`
TotalNum int64 `json:"total_num"`
Title string `json:"title"`
Price float64 `json:"price"`
}
type CartSizeItem struct {
Cm string `json:"cm"`
Inch string `json:"inch"`
}
type Response struct {
Code int `json:"code"`
Message string `json:"msg"`

View File

@ -17,6 +17,9 @@ service shopping-cart-confirmation {
//获取用户购物车数量
@handler CartNumberHandler
get /cart/num ( ) returns (response);
//获取用户购物车列表
@handler CartListHandler
get /cart/list (CartListReq) returns (response);
}
//添加入购物车
@ -32,4 +35,38 @@ type CartDeleteReq {
//获取用户购物车数量
type CartNumberRsp {
Num int64 `json:"num"`
}
//获取用户购物车列表
type CartListReq {
Size uint32 `form:"size"`
}
type CartListRsp {
Id int64 `json:"id"`
Cover string `json:"cover"`
Name string `json:"name"`
Capacity string `json:"capacity"`
ETA string `json:"ETA"`
Pcs int64 `json:"pcs"`
ProductSn string `json:"product_sn"`
DesignSn string `json:"designSn"`
Option CartOption `json:"option"`
IsCheck int64 `json:"is_check"`
TsTime string `json:"ts_time"`
PcsList []PcsItem `json:"pcs_list"`
Size CartSizeItem `json:"size"`
}
type CartOption {
Id int64 `json:"id"`
Title string `json:"title"`
Price float64 `json:"price"`
}
type PcsItem {
Num int64 `json:"num"`
TotalNum int64 `json:"total_num"`
Title string `json:"title"`
Price float64 `json:"price"`
}
type CartSizeItem {
Cm string `json:"cm"`
Inch string `json:"inch"`
}

16
utils/step_price/price.go Normal file
View File

@ -0,0 +1,16 @@
package step_price
func GetStepPrice(minBuyNum int, stepNum []int, stepPrice []int) float64 {
if minBuyNum > stepNum[len(stepNum)-1] {
return float64(stepPrice[len(stepPrice)-1]) / float64(100)
}
for k, v := range stepNum {
if minBuyNum <= v {
if k <= (len(stepPrice) - 1) {
return float64(stepPrice[k]) / float64(100)
}
return float64(stepPrice[len(stepPrice)-1]) / float64(100)
}
}
return float64(stepPrice[len(stepPrice)-1]) / float64(100)
}