@@ -0,0 +1,365 @@
package logic
import (
"encoding/json"
"errors"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/color_list"
"fusenapi/utils/format"
"fusenapi/utils/s3url_to_s3id"
"fusenapi/utils/template_switch_info"
"gorm.io/gorm"
"strings"
"context"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetProductDetailLogic struct {
logx . Logger
ctx context . Context
svcCtx * svc . ServiceContext
}
func NewGetProductDetailLogic ( ctx context . Context , svcCtx * svc . ServiceContext ) * GetProductDetailLogic {
return & GetProductDetailLogic {
Logger : logx . WithContext ( ctx ) ,
ctx : ctx ,
svcCtx : svcCtx ,
}
}
// 处理进入前逻辑w,r
// func (l *GetProductDetailLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func ( l * GetProductDetailLogic ) GetProductDetail ( req * types . GetProductDetailReq , userinfo * auth . UserInfo ) ( resp * basic . Response ) {
if req . ProductId <= 0 {
return resp . SetStatusWithMessage ( basic . CodeRequestParamsErr , "err param:product id is invalid" )
}
req . TemplateTag = strings . Trim ( req . TemplateTag , " " )
if req . TemplateTag == "" {
return resp . SetStatusWithMessage ( basic . CodeRequestParamsErr , "err param:template tag is invalid" )
}
//获取产品信息
productInfo , err := l . svcCtx . AllModels . FsProduct . FindOne ( l . ctx , req . ProductId )
if err != nil {
if errors . Is ( err , gorm . ErrRecordNotFound ) {
return resp . SetStatusWithMessage ( basic . CodeDbRecordNotFoundErr , "the product is not exists" )
}
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeDbSqlErr , "failed to get product info" )
}
if * productInfo . Status != 1 {
return resp . SetStatusWithMessage ( basic . CodeDbSqlErr , "the product status is unNormal" )
}
if * productInfo . IsShelf != 1 {
return resp . SetStatusWithMessage ( basic . CodeDbSqlErr , "the product status is off shelf" )
}
if * productInfo . IsDel == 1 {
return resp . SetStatusWithMessage ( basic . CodeDbSqlErr , "the product status is deleted" )
}
//获取产品类型
productTag , err := l . svcCtx . AllModels . FsTags . FindOne ( l . ctx , * productInfo . Type )
if err != nil {
if errors . Is ( err , gorm . ErrRecordNotFound ) {
return resp . SetStatusWithMessage ( basic . CodeDbRecordNotFoundErr , "the product`s tag is not exists" )
}
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeDbSqlErr , "failed to get product tag info" )
}
//获取模板标签颜色选择信息
templateTagColorInfo , err := l . GetTemplateTagColor ( req , userinfo )
if err != nil {
return resp . SetStatusWithMessage ( basic . CodeServiceErr , err . Error ( ) )
}
//获取产品尺寸列表
sizeList , err := l . svcCtx . AllModels . FsProductSize . GetAllByProductIds ( l . ctx , [ ] int64 { req . ProductId } , "is_hot DESC,sort ASC" )
if err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeDbSqlErr , "failed to get size list" )
}
//获取模型+配件信息
modelList , err := l . svcCtx . AllModels . FsProductModel3d . GetAllByProductIdTags ( l . ctx , req . ProductId , [ ] int64 { constants . TAG_MODEL , constants . TAG_PARTS } )
if err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeDbSqlErr , "failed to get model list" )
}
mapSizeKeyModel := make ( map [ int64 ] int ) //模型( 不包含配件) sizeId为key
mapFitting := make ( map [ int64 ] int ) //配件
publicFittingOptionTemplateIds := make ( [ ] int64 , 0 , len ( modelList ) ) //配件配置了公共模板的模板id
notPublicFittingOptionTemplateFittingIds := make ( [ ] int64 , 0 , len ( modelList ) ) //配件没有配置公共模板的配件id
lightIds := make ( [ ] int64 , 0 , len ( modelList ) )
for k , v := range modelList {
switch * v . Tag {
case constants . TAG_MODEL : //模型的
mapSizeKeyModel [ * v . SizeId ] = k
if * v . Light > 0 {
lightIds = append ( lightIds , * v . Light )
}
case constants . TAG_PARTS : //配件的
mapFitting [ v . Id ] = k
if * v . OptionTemplate > 0 {
publicFittingOptionTemplateIds = append ( publicFittingOptionTemplateIds , * v . OptionTemplate )
} else {
notPublicFittingOptionTemplateFittingIds = append ( notPublicFittingOptionTemplateFittingIds , v . Id )
}
}
}
//获取没有绑定公共模板的配件贴图
notPublicFittingOptionTemplateList , err := l . svcCtx . AllModels . FsProductTemplateV2 . FindAllByFittingIds ( l . ctx , notPublicFittingOptionTemplateFittingIds , "id,model_id,material_img" )
if err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeDbSqlErr , "failed to get fitting material image list" )
}
mapNotPublicFittingOptionTemplateMaterialImage := make ( map [ int64 ] string ) //model_id为key
for _ , v := range notPublicFittingOptionTemplateList {
mapNotPublicFittingOptionTemplateMaterialImage [ * v . ModelId ] = * v . MaterialImg
}
//获取配件绑定的公共模板列表
publicFittingOptionTemplateList , err := l . svcCtx . AllModels . FsProductTemplateV2 . FindAllByIds ( l . ctx , publicFittingOptionTemplateIds , "id,model_id,material_img" )
if err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeDbSqlErr , "failed to get fitting optional template list" )
}
mapPublicFittingOptionTemplate := make ( map [ int64 ] string ) //模板id为key
for _ , v := range publicFittingOptionTemplateList {
mapPublicFittingOptionTemplate [ v . Id ] = * v . MaterialImg
}
//获取灯光列表
lightList , err := l . svcCtx . AllModels . FsProductModel3dLight . GetAllByIds ( l . ctx , lightIds )
if err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeDbSqlErr , "failed to get light list" )
}
mapLight := make ( map [ int64 ] int )
for k , v := range lightList {
mapLight [ v . Id ] = k
}
//获取产品模板列表
templateList , err := l . svcCtx . AllModels . FsProductTemplateV2 . FindAllByProductIdsTemplateTag ( l . ctx , [ ] int64 { req . ProductId } , req . TemplateTag , "" )
if err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeDbSqlErr , "failed to get template list" )
}
mapModelIdKeyTemplate := make ( map [ int64 ] int )
for k , v := range templateList {
mapModelIdKeyTemplate [ * v . ModelId ] = k
}
//记录产品最低价
mapProductMinPrice := make ( map [ int64 ] int64 )
if err = l . svcCtx . AllModels . FsProductModel3d . GetProductMinPrice ( modelList , mapProductMinPrice ) ; err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeServiceErr , "failed to get product min price" )
}
//整理返回
rspSizeList := make ( [ ] types . SizeInfo , 0 , len ( sizeList ) )
for _ , sizeInfo := range sizeList {
var sizeTitle interface { }
if err = json . Unmarshal ( [ ] byte ( * sizeInfo . Title ) , & sizeTitle ) ; err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeJsonErr , "failed to parse size title" )
}
//尺寸下最低价
minPrice := ""
if price , ok := mapProductMinPrice [ * sizeInfo . ProductId ] ; ok {
minPrice = format . CentitoDollar ( price , 3 )
}
var modelInfoRsp types . ModelInfo
var TemplateInfoRsp interface { }
var FittingListRsp = make ( [ ] types . FittingInfo , 0 , 10 )
if modelIndex , ok := mapSizeKeyModel [ sizeInfo . Id ] ; ok {
modelInfo := modelList [ modelIndex ]
//模板信息
if templateIndex , ok := mapModelIdKeyTemplate [ modelInfo . Id ] ; ok {
templateInfo := templateList [ templateIndex ]
//获取开关信息
TemplateInfoRsp = template_switch_info . GetTemplateSwitchInfo ( templateInfo . Id , templateInfo . TemplateInfo , * templateInfo . MaterialImg )
}
//赋值id
modelInfoRsp . Id = modelInfo . Id
//模型设计信息
var modelDesignInfo interface { }
if modelInfo . ModelInfo != nil && * modelInfo . ModelInfo != "" {
if err = json . Unmarshal ( [ ] byte ( * modelInfo . ModelInfo ) , & modelDesignInfo ) ; err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeJsonErr , "failed to parse model design info" )
}
//赋值
modelInfoRsp . ModelDesignInfo = modelDesignInfo
}
//灯光信息
if lightIndex , ok := mapLight [ * modelInfo . Light ] ; ok {
lightInfo := lightList [ lightIndex ]
var lightDesignInfo interface { }
if lightInfo . Info != nil && * lightInfo . Info != "" {
if err = json . Unmarshal ( [ ] byte ( * lightInfo . Info ) , & lightDesignInfo ) ; err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeJsonErr , "failed to parse light design info" )
}
//赋值
modelInfoRsp . LightInfo = types . LightInfo {
Id : lightInfo . Id ,
LightName : * lightInfo . Name ,
LightDesignInfo : lightDesignInfo ,
}
}
}
optionalFittingIdsStr := strings . Trim ( * modelInfo . PartList , " " )
optionalFittingIdsStr = strings . Trim ( optionalFittingIdsStr , "," )
//配件信息
if optionalFittingIdsStr != "" {
optionalFittingIds , err := format . StrSlicToInt64Slice ( strings . Split ( optionalFittingIdsStr , "," ) )
if err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeServiceErr , "failed to split optional fitting list" )
}
//可选配件
for _ , optionFittingId := range optionalFittingIds {
fittingIndex , ok := mapFitting [ optionFittingId ]
if ! ok {
continue
}
fittingInfo := modelList [ fittingIndex ]
var fittingDesignInfo interface { }
if fittingInfo . ModelInfo == nil || * fittingInfo . ModelInfo == "" {
continue
}
if err = json . Unmarshal ( [ ] byte ( * fittingInfo . ModelInfo ) , & fittingDesignInfo ) ; err != nil {
logx . Error ( err )
return resp . SetStatusWithMessage ( basic . CodeJsonErr , "failed to parse fitting design info" )
}
//是否默认显示配件
isDefault := int64 ( 0 )
if optionFittingId == * modelInfo . PartId {
isDefault = 1
}
//配件贴图
FittingMaterialImg := ""
//贴图,如果绑定了公共模板,则获取公共模板的贴图数据(待优化)
if * fittingInfo . OptionTemplate > 0 {
if image , ok := mapPublicFittingOptionTemplate [ * fittingInfo . OptionTemplate ] ; ok {
FittingMaterialImg = image
}
} else { //否则取该配件下的模板贴图
if image , ok := mapNotPublicFittingOptionTemplateMaterialImage [ fittingInfo . Id ] ; ok {
FittingMaterialImg = image
}
}
FittingListRsp = append ( FittingListRsp , types . FittingInfo {
Id : fittingInfo . Id ,
IsHot : * fittingInfo . IsHot ,
MaterialImage : FittingMaterialImg ,
DesignInfo : fittingDesignInfo ,
Price : format . CentitoDollar ( * fittingInfo . Price , 3 ) ,
Name : * fittingInfo . Name ,
IsDefault : isDefault ,
} )
}
}
}
rspSizeList = append ( rspSizeList , types . SizeInfo {
Id : sizeInfo . Id ,
Title : sizeTitle ,
Capacity : * sizeInfo . Capacity ,
PartsCanDeleted : * sizeInfo . PartsCanDeleted ,
IsHot : * sizeInfo . IsHot ,
MinPrice : minPrice ,
TemplateInfo : TemplateInfoRsp ,
ModelInfo : modelInfoRsp ,
FittingList : FittingListRsp ,
} )
}
return resp . SetStatusWithMessage ( basic . CodeOK , "success" , types . GetProductDetailRsp {
TemplateTagColorInfo : templateTagColorInfo ,
ProductInfo : types . ProductInfo {
Id : productInfo . Id ,
ProductType : * productInfo . Type ,
ProductTypeName : * productTag . Title ,
Title : * productInfo . Title ,
IsEnv : * productInfo . IsProtection ,
IsMicro : * productInfo . IsMicrowave ,
IsCustomization : * productInfo . IsCustomization ,
} ,
BaseColors : color_list . GetColor ( ) ,
SizeList : rspSizeList ,
} )
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *GetProductDetailLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }
func ( l * GetProductDetailLogic ) GetTemplateTagColor ( req * types . GetProductDetailReq , userinfo * auth . UserInfo ) ( resp types . TemplateTagColorInfo , err error ) {
if req . SelectColorIndex < 0 {
return types . TemplateTagColorInfo { } , errors . New ( "param selected_color_index is invalid" )
}
//根据logo查询素材资源
resourceId := s3url_to_s3id . GetS3ResourceIdFormUrl ( req . Logo )
if resourceId == "" {
return types . TemplateTagColorInfo { } , errors . New ( "param logo is invalid" )
}
var (
userMaterial * gmodel . FsUserMaterial
templateTagInfo * gmodel . FsProductTemplateTags
)
//获取模板标签信息
templateTagInfo , err = l . svcCtx . AllModels . FsProductTemplateTags . FindOneByTagName ( l . ctx , req . TemplateTag )
if err != nil {
if errors . Is ( err , gorm . ErrRecordNotFound ) {
return types . TemplateTagColorInfo { } , errors . New ( "the template tag is not exists" )
}
logx . Error ( err )
return types . TemplateTagColorInfo { } , errors . New ( "failed to get template tag info" )
}
userMaterial , err = l . svcCtx . AllModels . FsUserMaterial . FindOneByLogoResourceId ( l . ctx , resourceId )
if err != nil {
if errors . Is ( err , gorm . ErrRecordNotFound ) {
return types . TemplateTagColorInfo { } , errors . New ( "the logo is not found" )
}
logx . Error ( err )
return types . TemplateTagColorInfo { } , errors . New ( "failed to get user material" )
}
if userMaterial . Metadata == nil || len ( * userMaterial . Metadata ) == 0 {
return types . TemplateTagColorInfo { } , errors . New ( "the user material is empty" )
}
//解析用户素材元数据
var metaData map [ string ] interface { }
if err = json . Unmarshal ( * userMaterial . Metadata , & metaData ) ; err != nil {
logx . Error ( err )
return types . TemplateTagColorInfo { } , errors . New ( "failed to parse user metadata" )
}
var mapMaterialTemplateTag map [ string ] [ ] [ ] string
b , _ := json . Marshal ( metaData [ "template_tag" ] )
if err = json . Unmarshal ( b , & mapMaterialTemplateTag ) ; err != nil {
logx . Error ( err )
return types . TemplateTagColorInfo { } , errors . New ( "invalid format of metadata`s template_tag" )
}
colors , ok := mapMaterialTemplateTag [ req . TemplateTag ]
if ! ok {
return types . TemplateTagColorInfo { } , errors . New ( "the template tag is not found from this logo material`s metadata" )
}
if req . SelectColorIndex >= len ( colors ) {
return types . TemplateTagColorInfo { } , errors . New ( "select color index is out of range !!" )
}
var templateTagGroups interface { }
if templateTagInfo . Groups != nil && * templateTagInfo . Groups != "" {
if err = json . Unmarshal ( [ ] byte ( * templateTagInfo . Groups ) , & templateTagGroups ) ; err != nil {
logx . Error ( err )
return types . TemplateTagColorInfo { } , errors . New ( "failed to parse template tag`s groups info" )
}
}
return types . TemplateTagColorInfo {
Colors : colors ,
SelectedColorIndex : req . SelectColorIndex ,
TemplateTagGroups : templateTagGroups ,
} , nil
}