package logic import ( "encoding/json" "errors" "fmt" "fusenapi/constants" "fusenapi/utils/auth" "fusenapi/utils/basic" "fusenapi/utils/format" "fusenapi/utils/image" "gorm.io/gorm" "strconv" "strings" "context" "fusenapi/server/product/internal/svc" "fusenapi/server/product/internal/types" "github.com/zeromicro/go-zero/core/logx" ) type GetProductInfoLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewGetProductInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductInfoLogic { return &GetProductInfoLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *GetProductInfoLogic) GetProductInfo(req *types.GetProductInfoReq, userinfo *auth.UserInfo) (resp *basic.Response) { //获取产品信息 productInfo, err := l.svcCtx.AllModels.FsProduct.FindOneBySn(l.ctx, req.Pid) 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 req.Size > 0 { req.Size = image.GetCurrentSize(req.Size) } materialIdSlice, err := format.StrSlicToInt64Slice(strings.Split(*productInfo.MaterialIds, ",")) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to parse product material Id list") } type Material struct { Id int64 `json:"id"` Title string `json:"title"` } //材料列表 materials := make([]Material, 0, len(materialIdSlice)) for _, v := range materialIdSlice { if title, ok := constants.MAP_MATERIAL[v]; ok { materials = append(materials, Material{ Id: v, Title: title, }) } } //尺寸列表[这里要处理数据中的title] sizeList, err := l.svcCtx.AllModels.FsProductSize.GetAllByStatus(l.ctx, int64(constants.STATUS_ON), 1, "id,title,capacity,cover,sort,parts_can_deleted") if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product size list") } sizeIds := make([]int64, 0, len(sizeList)) for _, v := range sizeList { sizeIds = append(sizeIds, v.Id) } //获取产品标签 tagInfo, err := l.svcCtx.AllModels.FsTags.FindOne(l.ctx, *productInfo.Type) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "tag info is not exists") } logx.Error(err) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get tag info") } typeName := *tagInfo.Title //获取该尺寸下的模型数据 model3dList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllBySizeIdsTag(l.ctx, sizeIds, constants.TAG_MODEL) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product 3d model list") } model3dIds := make([]int64, 0, len(model3dList)) mapModel3dWithSizeIdIndex := make(map[int64]int) //sizeid为key for k, v := range model3dList { model3dIds = append(model3dIds, v.Id) mapModel3dWithSizeIdIndex[*v.SizeId] = k } //通过产品id和模型id获取模板信息 productTemplateList, err := l.svcCtx.AllModels.FsProductTemplateV2.FindAllByProductIdModelIds(l.ctx, model3dIds, productInfo.Id) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product template list") } //获取模板包含的model_id mapTemplateModelId := make(map[int64]struct{}) tagIds := make([]int64, 0, len(productTemplateList)) for _, v := range productTemplateList { mapTemplateModelId[v.Id] = struct{}{} if v.Tag != nil && *v.Tag != "" { tagId, err := strconv.ParseInt(*v.Tag, 10, 64) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "tag is not a number") } tagIds = append(tagIds, tagId) } } //过滤没有模板的尺寸数据 sizeListRsp := make([]types.SizeItem, 0, len(sizeList)) for _, v := range sizeList { model3dIndex, ok := mapModel3dWithSizeIdIndex[v.Id] if !ok { continue } if _, ok = mapTemplateModelId[model3dList[model3dIndex].Id]; !ok { continue } var title types.SizeTitle if err = json.Unmarshal([]byte(*v.Title), &title); err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to decode size info`s title") } var modelInfo map[string]interface{} if err = json.Unmarshal([]byte(*model3dList[model3dIndex].ModelInfo), &modelInfo); err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse model info") } cover := "" if modelInfo["cover"] != nil { coverArr := strings.Split(modelInfo["cover"].(string), ".") cover = modelInfo["cover"].(string) if req.Size >= 200 { cover = fmt.Sprintf("%s_%d.%s", coverArr[0], req.Size, coverArr[1]) } } sizeListRsp = append(sizeListRsp, types.SizeItem{ Id: v.Id, Title: title, Capacity: *v.Capacity, Cover: cover, Sort: *v.Sort, PartsCanDeleted: *v.PartsCanDeleted > 0, }) } //获取标签列表 tagList, err := l.svcCtx.AllModels.FsTags.GetAllByIdsWithoutStatus(l.ctx, tagIds) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get tag list") } //获取全部模型信息 allModel3dList, err := l.svcCtx.AllModels.FsProductModel3d.GetAll(l.ctx) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get all 3d model list") } mapAllmodel3d := make(map[int64]int) optionTemplateIds := make([]int64, 0, len(allModel3dList)) lightIds := make([]int64, 0, len(allModel3dList)) for k, v := range allModel3dList { mapAllmodel3d[v.Id] = k optionTemplateIds = append(optionTemplateIds, *v.OptionTemplate) lightIds = append(lightIds, *v.Light) } //获取公共模板信息 optionTemplateList, err := l.svcCtx.AllModels.FsProductTemplateV2.FindAllByIdsWithoutStatus(l.ctx, optionTemplateIds, "id,material_img") if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get option template list") } mapOptionTemplate := make(map[int64]int) for k, v := range optionTemplateList { mapOptionTemplate[v.Id] = k } //获取灯光信息 lightList, err := l.svcCtx.AllModels.FsProductModel3dLight.GetAllByIdsWithoutStatus(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 } //循环处理组装模板信息 template484List := make([]interface{}, 0, len(productTemplateList)) for _, v := range productTemplateList { allModel3dIndex, ok := mapAllmodel3d[*v.ModelId] if !ok { continue } //如果是配件信息就跳过,不返回 if *allModel3dList[allModel3dIndex].Tag == constants.TAG_PARTS { continue } //未编辑模板信息的数据跳过 if v.TemplateInfo == nil || *v.TemplateInfo == "" { continue } model3dInfo := allModel3dList[allModel3dIndex] //解码template info var templateInfo map[string]interface{} if err = json.Unmarshal([]byte(*v.TemplateInfo), &templateInfo); err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse template info") } if templateInfo["cover"] != nil && templateInfo["cover"].(string) != "" { cover := templateInfo["cover"].(string) if req.Size >= 200 { coverArr := strings.Split(templateInfo["cover"].(string), ".") cover = fmt.Sprintf("%s_%d.%s", coverArr[0], req.Size, coverArr[1]) } templateInfo["cover"] = cover delete(templateInfo, "isPublic") delete(templateInfo, "name") } //解码模型数据 var modelInfo map[string]interface{} if err = json.Unmarshal([]byte(*model3dInfo.ModelInfo), &modelInfo); err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse template info") } modelInfo["id"] = allModel3dList[allModel3dIndex].Id //解码灯光数据 var lightInfo interface{} lightIndex, ok := mapLight[*model3dInfo.Light] if ok && lightList[lightIndex].Info != nil && *lightList[lightIndex].Info != "" { if err = json.Unmarshal([]byte(*lightList[lightIndex].Info), &lightInfo); err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse light info") } } //配件备选项 modelPartIds, err := format.StrSlicToInt64Slice(strings.Split(*model3dInfo.PartList, ",")) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to parse 3d model`s part_list") } partList := make([]interface{}, 0, len(modelPartIds)) for _, partId := range modelPartIds { //判断配件信息是否正常 key, ok := mapAllmodel3d[partId] if !ok || *allModel3dList[key].Status != 1 { continue } var thisInfo map[string]interface{} temBytes, _ := json.Marshal(allModel3dList[key]) _ = json.Unmarshal(temBytes, &thisInfo) } } /* //循环处理组装模板信息 foreach ($templates as $temp) { foreach ($modelPart as $row) { //判断配件信息是否正常 if (isset($models[$row]) && !empty($models[$row]) && $models[$row]['status'] == 1) { $thisInfo = $models[$row]; $thisInfo['id'] = $models[$row]['id']; if (!empty($models[$row]['option_template']) && !is_null($models[$row]['option_template'])) { $thisInfo['material_img'] = $optionTemlateData[$models[$row]['option_template']]['material_img']; } else { $thisInfo['material_img'] = ProductTemplateV2::find()->where(['model_id' => $row])->select(['material_img'])->scalar(); } $thisInfo['model_info'] = json_decode($thisInfo['model_info'], true); $partArr[] = $thisInfo; } } //按照材质和尺寸来存放模板信息 $product['templates']["{$materialId}_{$models[$temp['model_id']]['size_id']}"][] = [ 'id' => $temp['id'], 'title' => $temp['title'], 'templateData' => $info, 'modelData' => $modelData, 'lightData' => $lightData, 'partList' => $partArr, 'tag_name' => isset($tags[$temp['tag']]) ? $tags[$temp['tag']]['title'] : '', ]; } //产品价格查询 $prices = ProductPrice::find() ->andFilterWhere(['product_id' => $product['id']]) ->statusOn(ProductPrice::STATUS_ON) ->asArray() ->all(); //循环阶梯价计算 foreach ($prices as $price) { $price['step_num'] = explode(',', $price['step_num']); $price['step_price'] = explode(',', $price['step_price']); while ($price['min_buy_num'] < end($price['step_num']) + 5) { $product['prices']["{$price['material_id']}_{$price['size_id']}"]['items'][] = [ 'num' => intval($price['min_buy_num']), 'total_num' => $price['min_buy_num'] * $price['each_box_num'], 'price' => ProductPriceService::getPrice($price['min_buy_num'], $price['step_num'], $price['step_price']) ]; $price['min_buy_num'] += 1; } $product['prices']["{$price['material_id']}_{$price['size_id']}"]['min_price'] = floatval(end($price['step_price']) / 100); $product['prices']["{$price['material_id']}_{$price['size_id']}"]['max_price'] = floatval(reset($price['step_price']) / 100); } //这里加一个字段返回数据格式为最新的设计(只有当又用户信息是才会又这个) $uid = intval(\Yii::$app->getUser()->id); $product['last_design'] = (new ProductService())->getLastDesign($uid); $product['render_design'] = $haveCloudRendering == 'true' ? (new ProductService())->getRenderDesign($clientNo) : null; //获取色系数据 $product['colors'] = ProductService::getColor(); //获取用户信息 $userInfo = User::find()->where(['id' => $uid])->asArray()->one(); $product['is_low_rendering'] = $userInfo && $userInfo['is_low_rendering'] ? true : false; $product['is_remove_bg'] = $userInfo && $userInfo['is_remove_bg'] ? true : false;*/ return resp.SetStatus(basic.CodeOK) }