755 lines
23 KiB
Go
755 lines
23 KiB
Go
|
|
package handler
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"dianshang/internal/model"
|
|||
|
|
"dianshang/internal/service"
|
|||
|
|
"dianshang/pkg/response"
|
|||
|
|
"dianshang/pkg/utils"
|
|||
|
|
"fmt"
|
|||
|
|
"strconv"
|
|||
|
|
|
|||
|
|
"github.com/gin-gonic/gin"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// FrontendHandler 前端接口处理器
|
|||
|
|
type FrontendHandler struct {
|
|||
|
|
productService *service.ProductService
|
|||
|
|
userService *service.UserService
|
|||
|
|
orderService *service.OrderService
|
|||
|
|
cartService *service.CartService
|
|||
|
|
bannerService *service.BannerService
|
|||
|
|
couponService *service.CouponService
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewFrontendHandler 创建前端接口处理器
|
|||
|
|
func NewFrontendHandler(
|
|||
|
|
productService *service.ProductService,
|
|||
|
|
userService *service.UserService,
|
|||
|
|
orderService *service.OrderService,
|
|||
|
|
cartService *service.CartService,
|
|||
|
|
bannerService *service.BannerService,
|
|||
|
|
couponService *service.CouponService,
|
|||
|
|
) *FrontendHandler {
|
|||
|
|
return &FrontendHandler{
|
|||
|
|
productService: productService,
|
|||
|
|
userService: userService,
|
|||
|
|
orderService: orderService,
|
|||
|
|
cartService: cartService,
|
|||
|
|
bannerService: bannerService,
|
|||
|
|
couponService: couponService,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetHomeData 获取首页数据
|
|||
|
|
func (h *FrontendHandler) GetHomeData(c *gin.Context) {
|
|||
|
|
// 获取轮播图
|
|||
|
|
banners, err := h.bannerService.GetActiveBanners()
|
|||
|
|
if err != nil {
|
|||
|
|
response.ErrorWithMessage(c, response.ERROR, "获取轮播图失败: "+err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取分类
|
|||
|
|
categories, err := h.productService.GetCategories()
|
|||
|
|
if err != nil {
|
|||
|
|
response.ErrorWithMessage(c, response.ERROR, "获取分类失败: "+err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取推荐商品
|
|||
|
|
recommendProducts, _, err := h.productService.GetProductList(1, 10, 0, "", 0, 0, "default", "desc")
|
|||
|
|
if err != nil {
|
|||
|
|
response.ErrorWithMessage(c, response.ERROR, "获取推荐商品失败: "+err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取热门商品
|
|||
|
|
hotProducts, _, err := h.productService.GetProductList(1, 10, 0, "", 0, 0, "sales", "desc")
|
|||
|
|
if err != nil {
|
|||
|
|
response.ErrorWithMessage(c, response.ERROR, "获取热门商品失败: "+err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 转换为前端格式
|
|||
|
|
frontendBanners := h.convertBannersToFrontend(banners)
|
|||
|
|
frontendCategories := h.convertCategoriesToFrontend(categories)
|
|||
|
|
frontendRecommendProducts := h.convertProductsToFrontend(recommendProducts)
|
|||
|
|
frontendHotProducts := h.convertProductsToFrontend(hotProducts)
|
|||
|
|
|
|||
|
|
homeData := gin.H{
|
|||
|
|
"banners": frontendBanners,
|
|||
|
|
"categories": frontendCategories,
|
|||
|
|
"recommendProducts": frontendRecommendProducts,
|
|||
|
|
"hotProducts": frontendHotProducts,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response.Success(c, homeData)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetProductsRecommend 获取推荐商品
|
|||
|
|
func (h *FrontendHandler) GetProductsRecommend(c *gin.Context) {
|
|||
|
|
page := utils.StringToInt(c.DefaultQuery("page", "1"))
|
|||
|
|
pageSize := utils.StringToInt(c.DefaultQuery("page_size", "10"))
|
|||
|
|
|
|||
|
|
products, pagination, err := h.productService.GetProductList(page, pageSize, 0, "", 0, 0, "default", "desc")
|
|||
|
|
if err != nil {
|
|||
|
|
response.ErrorWithMessage(c, response.ERROR, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
frontendProducts := h.convertProductsToFrontend(products)
|
|||
|
|
response.Page(c, frontendProducts, pagination.Total, pagination.Page, pagination.PageSize)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetProductsHot 获取热门商品
|
|||
|
|
func (h *FrontendHandler) GetProductsHot(c *gin.Context) {
|
|||
|
|
page := utils.StringToInt(c.DefaultQuery("page", "1"))
|
|||
|
|
pageSize := utils.StringToInt(c.DefaultQuery("page_size", "10"))
|
|||
|
|
|
|||
|
|
products, pagination, err := h.productService.GetProductList(page, pageSize, 0, "", 0, 0, "sales", "desc")
|
|||
|
|
if err != nil {
|
|||
|
|
response.ErrorWithMessage(c, response.ERROR, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
frontendProducts := h.convertProductsToFrontend(products)
|
|||
|
|
response.Page(c, frontendProducts, pagination.Total, pagination.Page, pagination.PageSize)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetProductDetail 获取商品详情
|
|||
|
|
func (h *FrontendHandler) GetProductDetail(c *gin.Context) {
|
|||
|
|
spuID := c.Param("spuId")
|
|||
|
|
if spuID == "" {
|
|||
|
|
response.BadRequest(c, "商品ID不能为空")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 这里简化处理,实际应该根据spuID查询
|
|||
|
|
id := utils.StringToUint(spuID)
|
|||
|
|
if id == 0 {
|
|||
|
|
response.BadRequest(c, "无效的商品ID")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
product, err := h.productService.GetProductDetail(id)
|
|||
|
|
if err != nil {
|
|||
|
|
response.ErrorWithMessage(c, response.ERROR, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
frontendProduct := h.convertProductToFrontend(product)
|
|||
|
|
response.Success(c, frontendProduct)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserCenter 获取用户中心数据
|
|||
|
|
func (h *FrontendHandler) GetUserCenter(c *gin.Context) {
|
|||
|
|
userID := c.GetUint("user_id")
|
|||
|
|
if userID == 0 {
|
|||
|
|
response.Unauthorized(c)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
user, err := h.userService.GetUserByID(userID)
|
|||
|
|
if err != nil {
|
|||
|
|
response.ErrorWithMessage(c, response.ERROR, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取用户优惠券数量
|
|||
|
|
couponCount := 0
|
|||
|
|
if userCoupons, err := h.couponService.GetUserCoupons(userID, 1); err == nil { // 状态1表示未使用
|
|||
|
|
couponCount = len(userCoupons)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// 获取用户订单统计
|
|||
|
|
orderStats := map[int]int{
|
|||
|
|
1: 0, // 待付款 (对应前端status=1)
|
|||
|
|
3: 0, // 待发货 (对应前端status=3)
|
|||
|
|
5: 0, // 待收货 (对应前端status=5)
|
|||
|
|
6: 0, // 待评价 (对应前端status=6)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取用户订单列表来统计各状态订单数量
|
|||
|
|
if orders, _, err := h.orderService.GetUserOrders(userID, 0, 1, 1000); err == nil {
|
|||
|
|
for _, order := range orders {
|
|||
|
|
switch order.Status {
|
|||
|
|
case 1: // 数据库中的待付款状态
|
|||
|
|
orderStats[1]++ // 映射到前端status=1
|
|||
|
|
case 2: // 数据库中的待发货状态
|
|||
|
|
orderStats[3]++ // 映射到前端status=3
|
|||
|
|
case 3: // 数据库中的待收货状态
|
|||
|
|
orderStats[5]++ // 映射到前端status=5
|
|||
|
|
case 4: // 数据库中的待评价状态
|
|||
|
|
orderStats[6]++ // 映射到前端status=6
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构造用户中心数据
|
|||
|
|
userCenter := model.FrontendUserCenter{
|
|||
|
|
UserInfo: model.FrontendUserInfo{
|
|||
|
|
AvatarURL: user.Avatar,
|
|||
|
|
NickName: user.Nickname,
|
|||
|
|
PhoneNumber: user.Phone,
|
|||
|
|
Gender: int(user.Gender),
|
|||
|
|
},
|
|||
|
|
CountsData: []model.FrontendCountData{
|
|||
|
|
{Num: couponCount, Name: "优惠券", Type: "coupon"},
|
|||
|
|
{Num: 0, Name: "收藏", Type: "favorite"},
|
|||
|
|
},
|
|||
|
|
OrderTagInfos: []model.FrontendOrderTagInfo{
|
|||
|
|
{OrderNum: orderStats[1], TabType: 1}, // 待付款
|
|||
|
|
{OrderNum: orderStats[3], TabType: 3}, // 待发货
|
|||
|
|
{OrderNum: orderStats[5], TabType: 5}, // 待收货
|
|||
|
|
{OrderNum: orderStats[6], TabType: 6}, // 待评价
|
|||
|
|
},
|
|||
|
|
CustomerServiceInfo: model.FrontendCustomerServiceInfo{
|
|||
|
|
ServicePhone: "400-123-4567",
|
|||
|
|
ServiceTimeDuration: "9:00-18:00",
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response.Success(c, userCenter)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetCartData 获取购物车数据
|
|||
|
|
func (h *FrontendHandler) GetCartData(c *gin.Context) {
|
|||
|
|
userID := c.GetUint("user_id")
|
|||
|
|
if userID == 0 {
|
|||
|
|
response.Unauthorized(c)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
cartItems, err := h.cartService.GetCart(userID)
|
|||
|
|
if err != nil {
|
|||
|
|
response.ErrorWithMessage(c, response.ERROR, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
frontendCartData := h.convertCartToFrontend(cartItems)
|
|||
|
|
response.Success(c, frontendCartData)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetOrderList 获取订单列表
|
|||
|
|
func (h *FrontendHandler) GetOrderList(c *gin.Context) {
|
|||
|
|
userID := c.GetUint("user_id")
|
|||
|
|
if userID == 0 {
|
|||
|
|
response.Unauthorized(c)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
page := utils.StringToInt(c.DefaultQuery("page", "1"))
|
|||
|
|
pageSize := utils.StringToInt(c.DefaultQuery("page_size", "10"))
|
|||
|
|
statusStr := c.Query("status")
|
|||
|
|
status := 0
|
|||
|
|
if statusStr != "" {
|
|||
|
|
frontendStatus := utils.StringToInt(statusStr)
|
|||
|
|
// 将前端状态映射到数据库状态
|
|||
|
|
// 前端和数据库状态保持一致:
|
|||
|
|
// 1=未付款, 2=已付款/待发货, 3=待发货, 4=已发货, 5=待收货, 6=已完成, 7=已取消, 8=退货中, 9=已退款
|
|||
|
|
status = frontendStatus
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
orders, pagination, err := h.orderService.GetUserOrders(userID, status, page, pageSize)
|
|||
|
|
if err != nil {
|
|||
|
|
response.ErrorWithMessage(c, response.ERROR, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
frontendOrders := h.convertOrdersToFrontend(orders)
|
|||
|
|
orderList := model.FrontendOrderList{
|
|||
|
|
PageNum: pagination.Page,
|
|||
|
|
PageSize: pagination.PageSize,
|
|||
|
|
TotalCount: int(pagination.Total),
|
|||
|
|
Orders: frontendOrders,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response.Success(c, orderList)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetAddressList 获取地址列表
|
|||
|
|
func (h *FrontendHandler) GetAddressList(c *gin.Context) {
|
|||
|
|
userID := c.GetUint("user_id")
|
|||
|
|
if userID == 0 {
|
|||
|
|
response.Unauthorized(c)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
addresses, err := h.userService.GetUserAddresses(userID)
|
|||
|
|
if err != nil {
|
|||
|
|
response.ErrorWithMessage(c, response.ERROR, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
frontendAddresses := h.convertAddressesToFrontend(addresses)
|
|||
|
|
response.Success(c, frontendAddresses)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 转换函数
|
|||
|
|
|
|||
|
|
func (h *FrontendHandler) convertBannersToFrontend(banners []model.Banner) []gin.H {
|
|||
|
|
result := make([]gin.H, len(banners))
|
|||
|
|
for i, banner := range banners {
|
|||
|
|
result[i] = gin.H{
|
|||
|
|
"img": banner.Image,
|
|||
|
|
"text": banner.Title,
|
|||
|
|
"url": banner.LinkValue,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return result
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (h *FrontendHandler) convertCategoriesToFrontend(categories []model.Category) []model.FrontendCategory {
|
|||
|
|
result := make([]model.FrontendCategory, len(categories))
|
|||
|
|
for i, category := range categories {
|
|||
|
|
frontendCategory := model.FrontendCategory{
|
|||
|
|
GroupID: strconv.Itoa(int(category.ID)),
|
|||
|
|
Name: category.Name,
|
|||
|
|
Thumbnail: category.Icon,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理子分类
|
|||
|
|
if len(category.Children) > 0 {
|
|||
|
|
frontendCategory.Children = h.convertCategoriesToFrontend(category.Children)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result[i] = frontendCategory
|
|||
|
|
}
|
|||
|
|
return result
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (h *FrontendHandler) convertProductsToFrontend(products []model.Product) []model.FrontendProduct {
|
|||
|
|
result := make([]model.FrontendProduct, len(products))
|
|||
|
|
for i, product := range products {
|
|||
|
|
result[i] = h.convertProductToFrontend(&product)
|
|||
|
|
}
|
|||
|
|
return result
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (h *FrontendHandler) convertProductToFrontend(product *model.Product) model.FrontendProduct {
|
|||
|
|
// 获取商品图片
|
|||
|
|
images := make([]string, 0)
|
|||
|
|
if len(product.Images) > 0 {
|
|||
|
|
for _, img := range product.Images {
|
|||
|
|
images = append(images, img)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 若无图片则回退使用主图,确保前端轮播可显示
|
|||
|
|
if len(images) == 0 && product.MainImage != "" {
|
|||
|
|
images = append(images, product.MainImage)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成详情描述,优先使用详情图片数组,其次文本描述
|
|||
|
|
desc := make([]string, 0)
|
|||
|
|
if len(product.DetailImages) > 0 {
|
|||
|
|
for _, d := range product.DetailImages {
|
|||
|
|
desc = append(desc, d)
|
|||
|
|
}
|
|||
|
|
} else if product.Description != "" {
|
|||
|
|
desc = append(desc, product.Description)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取商品规格和SKU
|
|||
|
|
specList := make([]model.FrontendProductSpec, 0)
|
|||
|
|
skuList := make([]model.FrontendProductSKU, 0)
|
|||
|
|
|
|||
|
|
// 用于收集所有规格信息
|
|||
|
|
specMap := make(map[string]map[string]bool) // specName -> specValue -> exists
|
|||
|
|
|
|||
|
|
if len(product.SKUs) > 0 {
|
|||
|
|
// 首先遍历所有SKU,收集规格信息
|
|||
|
|
for _, sku := range product.SKUs {
|
|||
|
|
for specName, specValue := range sku.SpecValues {
|
|||
|
|
if specMap[specName] == nil {
|
|||
|
|
specMap[specName] = make(map[string]bool)
|
|||
|
|
}
|
|||
|
|
if specValueStr, ok := specValue.(string); ok {
|
|||
|
|
specMap[specName][specValueStr] = true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成specList和规格值ID映射
|
|||
|
|
specIndex := 1
|
|||
|
|
specNameToID := make(map[string]string)
|
|||
|
|
specValueToID := make(map[string]map[string]string) // specName -> specValue -> specValueID
|
|||
|
|
for specName, specValues := range specMap {
|
|||
|
|
specID := strconv.Itoa(specIndex)
|
|||
|
|
specNameToID[specName] = specID
|
|||
|
|
specValueToID[specName] = make(map[string]string)
|
|||
|
|
|
|||
|
|
specValueList := make([]model.FrontendProductSpecValue, 0)
|
|||
|
|
valueIndex := 1
|
|||
|
|
for specValue := range specValues {
|
|||
|
|
specValueID := fmt.Sprintf("%s_%d", specID, valueIndex)
|
|||
|
|
specValueToID[specName][specValue] = specValueID
|
|||
|
|
|
|||
|
|
specValueList = append(specValueList, model.FrontendProductSpecValue{
|
|||
|
|
SpecValueID: specValueID,
|
|||
|
|
SpecID: specID,
|
|||
|
|
SaasID: "default",
|
|||
|
|
SpecValue: specValue,
|
|||
|
|
Image: "",
|
|||
|
|
})
|
|||
|
|
valueIndex++
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
specList = append(specList, model.FrontendProductSpec{
|
|||
|
|
SpecID: specID,
|
|||
|
|
Title: specName,
|
|||
|
|
SpecValueList: specValueList,
|
|||
|
|
})
|
|||
|
|
specIndex++
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成skuList
|
|||
|
|
for _, sku := range product.SKUs {
|
|||
|
|
specInfo := make([]model.FrontendSKUSpecInfo, 0)
|
|||
|
|
for specName, specValue := range sku.SpecValues {
|
|||
|
|
if specValueStr, ok := specValue.(string); ok {
|
|||
|
|
specValueID := ""
|
|||
|
|
if specValueMap, exists := specValueToID[specName]; exists {
|
|||
|
|
if valueID, exists := specValueMap[specValueStr]; exists {
|
|||
|
|
specValueID = valueID
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
specInfo = append(specInfo, model.FrontendSKUSpecInfo{
|
|||
|
|
SpecID: specNameToID[specName],
|
|||
|
|
SpecTitle: specName,
|
|||
|
|
SpecValueID: specValueID,
|
|||
|
|
SpecValue: specValueStr,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
frontendSKU := model.FrontendProductSKU{
|
|||
|
|
SkuID: strconv.Itoa(int(sku.ID)),
|
|||
|
|
SkuImage: sku.Image,
|
|||
|
|
SpecInfo: specInfo,
|
|||
|
|
PriceInfo: []model.FrontendSKUPriceInfo{
|
|||
|
|
{
|
|||
|
|
PriceType: 1,
|
|||
|
|
Price: fmt.Sprintf("%.0f", sku.Price),
|
|||
|
|
PriceTypeName: "销售价",
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
StockInfo: model.FrontendSKUStockInfo{
|
|||
|
|
StockQuantity: sku.Stock,
|
|||
|
|
SafeStockQuantity: 10,
|
|||
|
|
SoldQuantity: 0,
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
skuList = append(skuList, frontendSKU)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取商品标签
|
|||
|
|
spuTagList := make([]model.FrontendProductTag, 0)
|
|||
|
|
if len(product.Tags) > 0 {
|
|||
|
|
for _, tag := range product.Tags {
|
|||
|
|
spuTagList = append(spuTagList, model.FrontendProductTag{
|
|||
|
|
ID: strconv.Itoa(int(tag.ID)),
|
|||
|
|
Title: tag.Name,
|
|||
|
|
Image: "",
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return model.FrontendProduct{
|
|||
|
|
SaasID: "default",
|
|||
|
|
StoreID: strconv.Itoa(int(product.StoreID)),
|
|||
|
|
SpuID: strconv.Itoa(int(product.ID)),
|
|||
|
|
Title: product.Name,
|
|||
|
|
PrimaryImage: product.MainImage,
|
|||
|
|
Images: images,
|
|||
|
|
Available: 1,
|
|||
|
|
MinSalePrice: fmt.Sprintf("%.0f", product.Price),
|
|||
|
|
MinLinePrice: fmt.Sprintf("%.0f", product.Price),
|
|||
|
|
MaxSalePrice: fmt.Sprintf("%.0f", product.Price),
|
|||
|
|
MaxLinePrice: fmt.Sprintf("%.0f", product.Price),
|
|||
|
|
SpuStockQuantity: product.Stock,
|
|||
|
|
SoldNum: product.Sales,
|
|||
|
|
IsPutOnSale: 1,
|
|||
|
|
CategoryIds: []string{strconv.Itoa(int(product.CategoryID))},
|
|||
|
|
SpecList: specList,
|
|||
|
|
SkuList: skuList,
|
|||
|
|
SpuTagList: spuTagList,
|
|||
|
|
Desc: desc,
|
|||
|
|
Video: func() *string { if product.VideoURL != "" { v := product.VideoURL; return &v }; return nil }(),
|
|||
|
|
Etitle: product.Name,
|
|||
|
|
PromotionList: nil,
|
|||
|
|
MinProfitPrice: nil,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (h *FrontendHandler) convertCartToFrontend(cartItems []model.Cart) model.FrontendCartData {
|
|||
|
|
if len(cartItems) == 0 {
|
|||
|
|
return model.FrontendCartData{
|
|||
|
|
IsNotEmpty: false,
|
|||
|
|
StoreGoods: []model.FrontendStoreGoods{},
|
|||
|
|
IsAllSelected: false,
|
|||
|
|
SelectedGoodsCount: 0,
|
|||
|
|
TotalAmount: "0.00",
|
|||
|
|
TotalDiscountAmount: "0.00",
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 按店铺分组
|
|||
|
|
storeMap := make(map[uint][]model.Cart)
|
|||
|
|
for _, item := range cartItems {
|
|||
|
|
storeID := item.Product.StoreID
|
|||
|
|
storeMap[storeID] = append(storeMap[storeID], item)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
storeGoods := make([]model.FrontendStoreGoods, 0)
|
|||
|
|
totalAmount := 0.0
|
|||
|
|
selectedCount := 0
|
|||
|
|
|
|||
|
|
for storeID, items := range storeMap {
|
|||
|
|
goodsList := make([]model.FrontendCartGoods, 0)
|
|||
|
|
storeTotal := 0.0
|
|||
|
|
|
|||
|
|
for _, item := range items {
|
|||
|
|
price := (item.Product.Price / 100) * float64(item.Quantity)
|
|||
|
|
storeTotal += price
|
|||
|
|
if item.Selected {
|
|||
|
|
selectedCount += item.Quantity
|
|||
|
|
totalAmount += price
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建SKU规格信息
|
|||
|
|
specInfo := make([]model.FrontendSpecification, 0)
|
|||
|
|
if item.SKUID != nil {
|
|||
|
|
// 获取对应的SKU信息
|
|||
|
|
for _, sku := range item.Product.SKUs {
|
|||
|
|
if sku.ID == *item.SKUID {
|
|||
|
|
for specName, specValue := range sku.SpecValues {
|
|||
|
|
if specValueStr, ok := specValue.(string); ok {
|
|||
|
|
specInfo = append(specInfo, model.FrontendSpecification{
|
|||
|
|
SpecTitle: specName,
|
|||
|
|
SpecValue: specValueStr,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
goodsList = append(goodsList, model.FrontendCartGoods{
|
|||
|
|
UID: strconv.Itoa(int(item.ID)),
|
|||
|
|
SaasID: "default",
|
|||
|
|
StoreID: strconv.Itoa(int(storeID)),
|
|||
|
|
SpuID: strconv.Itoa(int(item.ProductID)),
|
|||
|
|
SkuID: func() string {
|
|||
|
|
if item.SKUID != nil {
|
|||
|
|
return strconv.Itoa(int(*item.SKUID))
|
|||
|
|
}
|
|||
|
|
return "0"
|
|||
|
|
}(),
|
|||
|
|
IsSelected: utils.BoolToInt(item.Selected),
|
|||
|
|
Thumb: item.Product.MainImage,
|
|||
|
|
Title: item.Product.Name,
|
|||
|
|
PrimaryImage: item.Product.MainImage,
|
|||
|
|
SpecInfo: specInfo,
|
|||
|
|
Quantity: item.Quantity,
|
|||
|
|
StockStatus: item.Product.Stock > 0,
|
|||
|
|
StockQuantity: item.Product.Stock,
|
|||
|
|
Price: fmt.Sprintf("%.0f", item.Product.Price),
|
|||
|
|
OriginPrice: fmt.Sprintf("%.0f", item.Product.Price),
|
|||
|
|
JoinCartTime: item.CreatedAt.Format("2006-01-02 15:04:05"),
|
|||
|
|
Available: 1,
|
|||
|
|
PutOnSale: 1,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 动态获取店铺名称
|
|||
|
|
storeName := "默认店铺" // 默认店铺名
|
|||
|
|
if storeID > 0 {
|
|||
|
|
store, err := h.productService.GetStoreByID(storeID)
|
|||
|
|
if err == nil && store != nil {
|
|||
|
|
storeName = store.Name
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
storeGoods = append(storeGoods, model.FrontendStoreGoods{
|
|||
|
|
StoreID: strconv.Itoa(int(storeID)),
|
|||
|
|
StoreName: storeName,
|
|||
|
|
StoreStatus: 1,
|
|||
|
|
TotalDiscountSalePrice: fmt.Sprintf("%.0f", storeTotal),
|
|||
|
|
GoodsList: goodsList,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return model.FrontendCartData{
|
|||
|
|
IsNotEmpty: len(cartItems) > 0,
|
|||
|
|
StoreGoods: storeGoods,
|
|||
|
|
IsAllSelected: selectedCount == len(cartItems),
|
|||
|
|
SelectedGoodsCount: selectedCount,
|
|||
|
|
TotalAmount: fmt.Sprintf("%.0f", totalAmount),
|
|||
|
|
TotalDiscountAmount: "0",
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (h *FrontendHandler) convertOrdersToFrontend(orders []model.Order) []model.FrontendOrder {
|
|||
|
|
result := make([]model.FrontendOrder, len(orders))
|
|||
|
|
for i, order := range orders {
|
|||
|
|
orderItems := make([]model.FrontendOrderItem, len(order.OrderItems))
|
|||
|
|
for j, item := range order.OrderItems {
|
|||
|
|
// 处理规格信息
|
|||
|
|
specifications := []model.FrontendSpecification{}
|
|||
|
|
|
|||
|
|
// 优先从SKU获取规格信息
|
|||
|
|
if item.SKUID != nil && item.SKU.ID > 0 && len(item.SKU.SpecValues) > 0 {
|
|||
|
|
for specName, specValue := range item.SKU.SpecValues {
|
|||
|
|
if specValueStr, ok := specValue.(string); ok {
|
|||
|
|
specifications = append(specifications, model.FrontendSpecification{
|
|||
|
|
SpecTitle: specName,
|
|||
|
|
SpecValue: specValueStr,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else if len(item.SpecInfo) > 0 {
|
|||
|
|
// 如果SKU没有规格信息,从订单项的SpecInfo获取
|
|||
|
|
for specName, specValue := range item.SpecInfo {
|
|||
|
|
if specValueStr, ok := specValue.(string); ok {
|
|||
|
|
specifications = append(specifications, model.FrontendSpecification{
|
|||
|
|
SpecTitle: specName,
|
|||
|
|
SpecValue: specValueStr,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else if item.SpecName != "" && item.SpecValue != "" {
|
|||
|
|
// 从单独的规格字段获取
|
|||
|
|
specifications = append(specifications, model.FrontendSpecification{
|
|||
|
|
SpecTitle: item.SpecName,
|
|||
|
|
SpecValue: item.SpecValue,
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
// 如果订单项没有规格信息,尝试从产品的第一个SKU获取默认规格
|
|||
|
|
if item.Product.ID > 0 && len(item.Product.SKUs) > 0 {
|
|||
|
|
firstSKU := item.Product.SKUs[0]
|
|||
|
|
for specName, specValue := range firstSKU.SpecValues {
|
|||
|
|
if specValueStr, ok := specValue.(string); ok {
|
|||
|
|
specifications = append(specifications, model.FrontendSpecification{
|
|||
|
|
SpecTitle: specName,
|
|||
|
|
SpecValue: specValueStr, // 使用实际的规格值
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// 如果还是没有规格信息,提供一个默认的规格
|
|||
|
|
if len(specifications) == 0 {
|
|||
|
|
specifications = append(specifications, model.FrontendSpecification{
|
|||
|
|
SpecTitle: "规格",
|
|||
|
|
SpecValue: "标准",
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
orderItems[j] = model.FrontendOrderItem{
|
|||
|
|
ID: strconv.Itoa(int(item.ID)),
|
|||
|
|
SpuID: strconv.Itoa(int(item.ProductID)),
|
|||
|
|
SkuID: func() string {
|
|||
|
|
if item.SKUID != nil {
|
|||
|
|
return strconv.Itoa(int(*item.SKUID))
|
|||
|
|
}
|
|||
|
|
return "0"
|
|||
|
|
}(),
|
|||
|
|
GoodsMainType: 1,
|
|||
|
|
GoodsViceType: 1,
|
|||
|
|
GoodsName: item.ProductName,
|
|||
|
|
Specifications: specifications,
|
|||
|
|
GoodsPictureURL: item.ProductImage,
|
|||
|
|
OriginPrice: fmt.Sprintf("%.0f", item.Price),
|
|||
|
|
ActualPrice: fmt.Sprintf("%.0f", item.Price),
|
|||
|
|
BuyQuantity: item.Quantity,
|
|||
|
|
ItemTotalAmount: fmt.Sprintf("%.0f", item.Price*float64(item.Quantity)),
|
|||
|
|
ItemDiscountAmount: "0.00",
|
|||
|
|
ItemPaymentAmount: fmt.Sprintf("%.0f", item.Price*float64(item.Quantity)),
|
|||
|
|
GoodsPaymentPrice: fmt.Sprintf("%.0f", item.Price),
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 动态获取店铺名称
|
|||
|
|
storeName := "默认店铺" // 默认店铺名
|
|||
|
|
if order.StoreID > 0 {
|
|||
|
|
store, err := h.productService.GetStoreByID(order.StoreID)
|
|||
|
|
if err == nil && store != nil {
|
|||
|
|
storeName = store.Name
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result[i] = model.FrontendOrder{
|
|||
|
|
SaasID: "default",
|
|||
|
|
StoreID: strconv.Itoa(int(order.StoreID)),
|
|||
|
|
StoreName: storeName,
|
|||
|
|
UID: strconv.Itoa(int(order.UserID)),
|
|||
|
|
ParentOrderNo: order.OrderNo,
|
|||
|
|
OrderID: strconv.Itoa(int(order.ID)),
|
|||
|
|
OrderNo: order.OrderNo,
|
|||
|
|
OrderType: 1,
|
|||
|
|
OrderSubType: 1,
|
|||
|
|
OrderStatus: int(order.Status),
|
|||
|
|
TotalAmount: fmt.Sprintf("%.0f", order.TotalAmount),
|
|||
|
|
GoodsAmount: fmt.Sprintf("%.0f", order.TotalAmount),
|
|||
|
|
GoodsAmountApp: fmt.Sprintf("%.0f", order.TotalAmount),
|
|||
|
|
PaymentAmount: fmt.Sprintf("%.0f", order.PayAmount),
|
|||
|
|
FreightFee: fmt.Sprintf("%.0f", order.ShippingFee),
|
|||
|
|
PackageFee: "0",
|
|||
|
|
DiscountAmount: fmt.Sprintf("%.0f", order.DiscountAmount),
|
|||
|
|
ChannelType: 1,
|
|||
|
|
ChannelSource: "miniprogram",
|
|||
|
|
ChannelIdentity: "wechat",
|
|||
|
|
Remark: order.Remark,
|
|||
|
|
CreateTime: order.CreatedAt.Format("2006-01-02 15:04:05"),
|
|||
|
|
OrderItemVOs: orderItems,
|
|||
|
|
LogisticsVO: model.FrontendLogistics{
|
|||
|
|
LogisticsType: 1,
|
|||
|
|
LogisticsNo: order.LogisticsNo,
|
|||
|
|
LogisticsCompanyCode: "SF",
|
|||
|
|
LogisticsCompanyName: "顺丰速运",
|
|||
|
|
ReceiverName: order.ReceiverName,
|
|||
|
|
ReceiverPhone: order.ReceiverPhone,
|
|||
|
|
ReceiverAddress: order.ReceiverAddress,
|
|||
|
|
},
|
|||
|
|
PaymentVO: model.FrontendPayment{
|
|||
|
|
PayStatus: int(order.PayStatus),
|
|||
|
|
Amount: fmt.Sprintf("%.2f", order.PayAmount),
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return result
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (h *FrontendHandler) convertAddressesToFrontend(addresses []model.UserAddress) []model.FrontendAddress {
|
|||
|
|
result := make([]model.FrontendAddress, len(addresses))
|
|||
|
|
for i, addr := range addresses {
|
|||
|
|
result[i] = model.FrontendAddress{
|
|||
|
|
SaasID: "default",
|
|||
|
|
UID: strconv.Itoa(int(addr.UserID)),
|
|||
|
|
ID: strconv.Itoa(int(addr.ID)),
|
|||
|
|
AddressID: strconv.Itoa(int(addr.ID)),
|
|||
|
|
Phone: addr.Phone,
|
|||
|
|
Name: addr.Name,
|
|||
|
|
CountryName: "中国",
|
|||
|
|
CountryCode: "CN",
|
|||
|
|
ProvinceName: addr.ProvinceName,
|
|||
|
|
ProvinceCode: "000000", // UserAddress模型中没有ProvinceCode字段,使用默认值
|
|||
|
|
CityName: addr.CityName,
|
|||
|
|
CityCode: "000000", // UserAddress模型中没有CityCode字段,使用默认值
|
|||
|
|
DistrictName: addr.DistrictName,
|
|||
|
|
DistrictCode: "000000", // UserAddress模型中没有DistrictCode字段,使用默认值
|
|||
|
|
DetailAddress: addr.DetailAddress,
|
|||
|
|
IsDefault: utils.BoolToInt(addr.IsDefault),
|
|||
|
|
AddressTag: addr.AddressTag,
|
|||
|
|
Latitude: fmt.Sprintf("%.6f", addr.Latitude),
|
|||
|
|
Longitude: fmt.Sprintf("%.6f", addr.Longitude),
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return result
|
|||
|
|
}
|