diff --git a/model/gmodel/fs_product_template_v2_logic.go b/model/gmodel/fs_product_template_v2_logic.go index d5364778..40e8a6bc 100755 --- a/model/gmodel/fs_product_template_v2_logic.go +++ b/model/gmodel/fs_product_template_v2_logic.go @@ -153,3 +153,17 @@ func (t *FsProductTemplateV2Model) GetListByProductAndTemplateTag(ctx context.Co err = db.Find(&resp).Error return resp, err } +func (t *FsProductTemplateV2Model) FindAllByProductIdsTemplateTag(ctx context.Context, productIds []int64, templateTag string, sort string, fields ...string) (resp []FsProductTemplateV2, err error) { + if len(productIds) == 0 { + return + } + db := t.db.WithContext(ctx).Model(&FsProductTemplateV2{}).Where("`product_id` in (?) and `template_tag` = ? and `is_del` = ? and `status` = ?", productIds, templateTag, 0, 1) + if sort != "" { + db = db.Order(sort) + } + if len(fields) != 0 { + db = db.Select(fields[0]) + } + err = db.Find(&resp).Error + return resp, err +} diff --git a/server/product/internal/logic/gettagproductlistlogic.go b/server/product/internal/logic/gettagproductlistlogic.go index 8d51e6fa..c8642633 100644 --- a/server/product/internal/logic/gettagproductlistlogic.go +++ b/server/product/internal/logic/gettagproductlistlogic.go @@ -63,6 +63,7 @@ func (l *GetTagProductListLogic) GetTagProductList(req *types.GetTagProductListR logx.Error(err) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get tag info") } + //前台用的分类是1 if *tagData.Category != 1 { return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "invalid tag") } @@ -170,13 +171,20 @@ func (l *GetTagProductListLogic) GetTagProductList(req *types.GetTagProductListR } } //获取模板(只是获取产品product_id,id) - productTemplatesV2, err = l.svcCtx.AllModels.FsProductTemplateV2.FindAllByProductIds(l.ctx, productIds, "sort ASC", "product_id,id") + if req.TemplateTag != "" { //指定模板tag + productTemplatesV2, err = l.svcCtx.AllModels.FsProductTemplateV2.FindAllByProductIdsTemplateTag(l.ctx, productIds, req.TemplateTag, "sort ASC", "product_id,id") + } else { //没指定模板tag + productTemplatesV2, err = l.svcCtx.AllModels.FsProductTemplateV2.FindAllByProductIds(l.ctx, productIds, "sort ASC", "product_id,id") + } if err != nil { logx.Error(err) - return resp.SetStatusWithMessage(basic.CodeServiceErr, "get product template_v2 err") + return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product templates") } //只存第一个 for _, v := range productTemplatesV2 { + if _, ok := mapProductTemplate[*v.ProductId]; ok { + continue + } mapProductTemplate[*v.ProductId] = v.Id } //获取产品尺寸数量 diff --git a/server/product/internal/types/types.go b/server/product/internal/types/types.go index 7d511c6e..bc9c1135 100644 --- a/server/product/internal/types/types.go +++ b/server/product/internal/types/types.go @@ -249,6 +249,7 @@ type GetRecommandProductListRsp struct { type GetTagProductListReq struct { Cid int64 `form:"cid,optional"` //分类id Size uint32 `form:"size,optional"` //尺寸 + TemplateTag string `form:"template_tag,optional"` //模板标签 WithProduct bool `form:"with_product,optional"` //是否携带分类下的产品 } diff --git a/server/resource/etc/resource.yaml b/server/resource/etc/resource.yaml index 099a6460..f2f27737 100644 --- a/server/resource/etc/resource.yaml +++ b/server/resource/etc/resource.yaml @@ -15,8 +15,8 @@ AWS: Secret: sjCEv0JxATnPCxno2KNLm0X8oDc7srUR+4vkYhvm Token: BLMService: - # Url: "http://18.119.109.254:8999" - Url: "http://192.168.1.7:8999" + Url: "http://18.119.109.254:8999" + # Url: "http://192.168.1.7:8999" LogoCombine: #Url: "http://192.168.1.7:8999/LogoCombine" Url: "http://18.119.109.254:8999/LogoCombine" \ No newline at end of file diff --git a/server/upload/etc/upload.yaml b/server/upload/etc/upload.yaml index a2a2cb4b..8f8afac9 100644 --- a/server/upload/etc/upload.yaml +++ b/server/upload/etc/upload.yaml @@ -2,6 +2,7 @@ Name: upload Host: 0.0.0.0 Port: 9912 Timeout: 150000 #服务超时时间 +MaxBytes: 104857600 #传输字节大小 SourceMysql: "fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest" Env: "test" Auth: diff --git a/server/upload/internal/logic/uploadlogologic.go b/server/upload/internal/logic/uploadlogologic.go index bd495c61..0318e245 100644 --- a/server/upload/internal/logic/uploadlogologic.go +++ b/server/upload/internal/logic/uploadlogologic.go @@ -95,6 +95,12 @@ func (l *UploadLogoLogic) UploadLogo(req *types.UploadLogoReq, userinfo *auth.Us return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,file is not image") } + // 限制上传文件大小 50k + maxSize := 100 * 1024 + if fileHeader.Size > int64(maxSize) { + return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,The file size exceeds the maximum limit of 100k") + } + // 读取数据流 ioData, err := io.ReadAll(fileObject) if err != nil { diff --git a/server/websocket/internal/logic/rendernotifylogic.go b/server/websocket/internal/logic/rendernotifylogic.go index e14983d4..44d0cd51 100644 --- a/server/websocket/internal/logic/rendernotifylogic.go +++ b/server/websocket/internal/logic/rendernotifylogic.go @@ -1,14 +1,10 @@ package logic import ( - "fusenapi/constants" + "context" "fusenapi/utils/auth" "fusenapi/utils/basic" "fusenapi/utils/file" - "fusenapi/utils/websocket_data" - "time" - - "context" "fusenapi/server/websocket/internal/svc" "fusenapi/server/websocket/internal/types" @@ -77,35 +73,14 @@ func (l *RenderNotifyLogic) RenderNotify(req *types.RenderNotifyReq, userinfo *a logx.Error("渲染回调断言websocket连接失败") return true } - //关闭标识 - if ws.isClose { - return true - } - //查询有无该渲染任务 - renderId, ok := ws.renderProperty.renderImageTask[req.TaskId] - if !ok { - return true - } - b := ws.respondDataFormat(constants.WEBSOCKET_RENDER_IMAGE, websocket_data.RenderImageRspMsg{ - RenderId: renderId, - Image: uploadRes.ResourceUrl, + //发送处理并删除任务 + ws.deleteRenderTask(renderImageControlChanItem{ + Option: 0, //0删除 1添加 + TaskId: req.TaskId, + RenderNotifyImageUrl: uploadRes.ResourceUrl, }) - deleteTask := renderImageControlChanItem{ - Option: 0, //0删除 1添加 - TaskId: req.TaskId, - RenderId: renderId, - } - select { - case <-ws.closeChan: //关闭了 - return true - case ws.renderProperty.renderImageTaskCtlChan <- deleteTask: //删除对应的需要渲染的图片map - //发送数据到out chan - ws.sendToOutChan(b) - return true - case <-time.After(time.Second * 3): //超时丢弃 - return true - } + return true }) - logx.Info("渲染回调成功######################") + logx.Info("渲染回调成功,渲染结果图片为:", uploadRes.ResourceUrl) return resp.SetStatusWithMessage(basic.CodeOK, "success") } diff --git a/server/websocket/internal/logic/ws_render_image_logic.go b/server/websocket/internal/logic/ws_render_image_logic.go index 5f225038..f04a470e 100644 --- a/server/websocket/internal/logic/ws_render_image_logic.go +++ b/server/websocket/internal/logic/ws_render_image_logic.go @@ -24,9 +24,10 @@ type renderProperty struct { // 渲染任务新增移除的控制通道的数据 type renderImageControlChanItem struct { - Option int // 0删除 1添加 - TaskId string //map的key - RenderId string // map的val + Option int // 0删除 1添加 + TaskId string //map的key + RenderId string // map的val(增加任务时候传) + RenderNotifyImageUrl string //渲染回调数据(删除任务时候传) } // 发送到渲染缓冲池 @@ -34,14 +35,14 @@ func (w *wsConnectItem) sendToRenderChan(data []byte) { select { case <-w.closeChan: //已经关闭 return - case w.renderProperty.renderChan <- data: + case w.renderProperty.renderChan <- data: //发入到缓冲池 return - case <-time.After(time.Second * 3): + case <-time.After(time.Second * 3): //三秒没进入缓冲池就丢弃 return } } -// 渲染发送到组装数据组装数据 +// 渲染发送到组装数据组装数据(缓冲池) func (w *wsConnectItem) renderImage() { defer func() { if err := recover(); err != nil { @@ -137,11 +138,11 @@ func (w *wsConnectItem) consumeRenderCache(data []byte) { } //########################################### //把需要渲染的图片任务加进去 - w.renderProperty.renderImageTaskCtlChan <- renderImageControlChanItem{ + w.createRenderTask(renderImageControlChanItem{ Option: 1, //0删除 1添加 TaskId: taskId, RenderId: renderImageData.RenderId, - } + }) //组装数据 if err = w.assembleRenderData(taskId, renderImageData); err != nil { logx.Error("组装数据失败:", err) @@ -189,7 +190,7 @@ func (w *wsConnectItem) assembleRenderData(taskId string, info websocket_data.Re logx.Error("合成刀版图失败,合成的刀版图是空指针:", err) return err } - logx.Info("合成刀版图成功,合成刀版图数据:", combineReq, ",模板id:", productTemplate.Id, ",原logo:", info.RenderData.Logo, "刀版图:", *res.ResourceUrl) + logx.Info("合成刀版图成功,合成刀版图数据:", combineReq, ",logo图片:", info.RenderData.Logo, " 刀版图:", *res.ResourceUrl) //获取渲染设置信息 element, err := w.logic.svcCtx.AllModels.FsProductTemplateElement.FindOneByModelId(w.logic.ctx, *productTemplate.ModelId) if err != nil { @@ -282,17 +283,45 @@ func (w *wsConnectItem) assembleRenderData(taskId string, info websocket_data.Re "create_at": t, "render_data": sendData, } - p, _ := json.Marshal(postData) - _, err = curl.ApiCall(url, "POST", header, bytes.NewReader(p), time.Second*10) + postDataBytes, _ := json.Marshal(postData) + _, err = curl.ApiCall(url, "POST", header, bytes.NewReader(postDataBytes), time.Second*10) if err != nil { logx.Error("failed to send data to unity") return err } - logx.Info("发送到unity成功################") + logx.Info("发送到unity成功,刀版图:", combineImage, " 请求unity的数据:", string(postDataBytes)) return nil } -// 操作连接中渲染任务的增加/删除 +// 增加渲染任务 +func (w *wsConnectItem) createRenderTask(data renderImageControlChanItem) { + //强制设为增加 + data.Option = 1 + select { + case <-w.closeChan: //关闭 + return + case w.renderProperty.renderImageTaskCtlChan <- data: + return + case <-time.After(time.Second * 3): + return + } +} + +// 渲染回调处理并删除渲染任务 +func (w *wsConnectItem) deleteRenderTask(data renderImageControlChanItem) { + //强制设为删除 + data.Option = 0 + select { + case <-w.closeChan: //关闭 + return + case w.renderProperty.renderImageTaskCtlChan <- data: + return + case <-time.After(time.Second * 3): + return + } +} + +// 操作连接中渲染任务的增加/删除(任务map不能读写并发,所以放在chan里面串行执行) func (w *wsConnectItem) operationRenderTask() { for { select { @@ -300,7 +329,14 @@ func (w *wsConnectItem) operationRenderTask() { return case data := <-w.renderProperty.renderImageTaskCtlChan: switch data.Option { - case 0: //删除任务 + case 0: //渲染结果回调,删除任务 + //存在任务,则发送渲染结果给前端 + if renderId, ok := w.renderProperty.renderImageTask[data.TaskId]; ok { + w.sendToOutChan(w.respondDataFormat(constants.WEBSOCKET_RENDER_IMAGE, websocket_data.RenderImageRspMsg{ + RenderId: renderId, + Image: data.RenderNotifyImageUrl, + })) + } delete(w.renderProperty.renderImageTask, data.TaskId) case 1: //新增任务 w.renderProperty.renderImageTask[data.TaskId] = data.RenderId diff --git a/server_api/product.api b/server_api/product.api index 8a6fdbf8..b479c9ef 100644 --- a/server_api/product.api +++ b/server_api/product.api @@ -301,6 +301,7 @@ type GetRecommandProductListRsp { type GetTagProductListReq { Cid int64 `form:"cid,optional"` //分类id Size uint32 `form:"size,optional"` //尺寸 + TemplateTag string `form:"template_tag,optional"` //模板标签 WithProduct bool `form:"with_product,optional"` //是否携带分类下的产品 } type GetTagProductListRsp { diff --git a/service/repositories/image_handle.go b/service/repositories/image_handle.go index d16e8704..1f86dacb 100644 --- a/service/repositories/image_handle.go +++ b/service/repositories/image_handle.go @@ -92,7 +92,10 @@ func (l *defaultImageHandle) LogoCombine(ctx context.Context, in *LogoCombineReq hashKeyData.GuestId = 0 hashKeyData.UserId = 0 hashKeyData.LogoUrl = *userMaterialInfo.ResourceUrl - var resourceId string = hash.JsonHashKey(hashKeyData) + var hashKeyDataMap map[string]interface{} + hashKeyDataB, _ := json.Marshal(hashKeyData) + json.Unmarshal(hashKeyDataB, &hashKeyDataMap) + var resourceId string = hash.JsonHashKey(hashKeyDataMap) fmt.Println("hashKeyData:", hashKeyData) @@ -254,11 +257,48 @@ type ( IsmaxProportion bool ImgColor []string } + LogoStandardMetaData struct { + Param LogoStandardReq `json:"param"` + Result LogoStandardRes `json:"result"` + } ) /* 图片裁剪 */ func (l *defaultImageHandle) LogoStandard(ctx context.Context, in *LogoStandardReq) (*LogoStandardRes, error) { - var resourceId string = hash.JsonHashKey(in) + var ismaxProportion bool + var imgColor []string + var logoStandardMetaData LogoStandardMetaData + + var hashKeyDataMap map[string]interface{} + hashKeyDataB, _ := json.Marshal(in) + json.Unmarshal(hashKeyDataB, &hashKeyDataMap) + var resourceId string = hash.JsonHashKey(hashKeyDataMap) + + resourceModel := gmodel.NewFsResourceModel(l.MysqlConn) + resourceInfo, err := resourceModel.FindOneById(ctx, resourceId) + if err == nil && resourceInfo.ResourceId != "" { + if resourceInfo.Metadata != nil { + json.Unmarshal([]byte(*resourceInfo.Metadata), &logoStandardMetaData) + } + // 取出参数 + ismaxProportion = logoStandardMetaData.Result.IsmaxProportion + imgColor = logoStandardMetaData.Result.ImgColor + + return &LogoStandardRes{ + ResourceId: resourceInfo.ResourceId, + ResourceUrl: *resourceInfo.ResourceUrl, + IsmaxProportion: ismaxProportion, + ImgColor: imgColor, + }, nil + } else { + if err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + logx.Error(err) + return nil, err + } + } + } + var postMap = make(map[string]interface{}, 5) postMap["is_remove_bg"] = in.IsRemoveBg postMap["logo_file"] = in.LogoFile @@ -312,16 +352,30 @@ func (l *defaultImageHandle) LogoStandard(ctx context.Context, in *LogoStandardR logx.Error(err) return nil, err } + //$removeBg ='{"nobg_url": "/test/dIE10gGfXM_scale.png", "thumbnail_url": "/test/dIE10gGfXM_thumbnail.png", "ismax_proportion": true, "img_color": ["#000000", "#EEF5FB", "#6AAFE6", "#9ECDF1", "#298EDC", "#0C7BD1"]}' var fileBase = resultData["nobg_url"].(string) - var ismaxProportion = resultData["ismax_proportion"].(bool) + ismaxProportion = resultData["ismax_proportion"].(bool) - var imgColor []string for _, v := range resultData["img_color"].([]interface{}) { imgColor = append(imgColor, v.(string)) } + var logoStandardRes LogoStandardRes + logoStandardRes.IsmaxProportion = ismaxProportion + logoStandardRes.ImgColor = imgColor + + logoStandardMetaData.Param = *in + logoStandardMetaData.Result = logoStandardRes + metadataB, err := json.Marshal(logoStandardMetaData) + if err != nil { + logx.Error(err) + return nil, err + } + + var metadata = string(metadataB) + // 上传文件 var upload = file.Upload{ Ctx: ctx, @@ -334,6 +388,7 @@ func (l *defaultImageHandle) LogoStandard(ctx context.Context, in *LogoStandardR FileData: fileBase, UploadBucket: 1, ApiType: 2, + Metadata: metadata, }) if err != nil { logx.Error(err) diff --git a/utils/hash/hash.go b/utils/hash/hash.go index 968decf1..228c8328 100644 --- a/utils/hash/hash.go +++ b/utils/hash/hash.go @@ -5,13 +5,12 @@ import ( "crypto/sha256" "encoding/json" "fmt" - "reflect" "sort" ) func JsonHashKey(v interface{}) string { - if reflect.TypeOf(v).Kind() == reflect.String { + if _, ok := v.(string); ok { var obj interface{} err := json.Unmarshal([]byte(v.(string)), &obj) if err == nil {