From 8e1293f4b735ebf679d9802c8a69f95f8f674315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A7=E9=A9=8A?= Date: Mon, 24 Mar 2025 00:08:32 +0800 Subject: [PATCH] feat: update create product --- go.mod | 1 + go.sum | 2 + pkg/usecase/product.go | 125 +++++++++++++++++++++++++++++++++-------- pkg/utils/times.go | 28 +++++++++ 4 files changed, 133 insertions(+), 23 deletions(-) create mode 100644 pkg/utils/times.go diff --git a/go.mod b/go.mod index 76f1669..89e1de8 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module code.30cm.net/digimon/app-cloudep-product-service go 1.24.0 require ( + code.30cm.net/digimon/library-go/errs v1.2.14 code.30cm.net/digimon/library-go/mongo v0.0.9 github.com/alicebob/miniredis/v2 v2.34.0 github.com/shopspring/decimal v1.4.0 diff --git a/go.sum b/go.sum index d8f6c5c..cef40c6 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +code.30cm.net/digimon/library-go/errs v1.2.14 h1:Un9wcIIjjJW8D2i0ISf8ibzp9oNT4OqLsaSKW0T4RJU= +code.30cm.net/digimon/library-go/errs v1.2.14/go.mod h1:Hs4v7SbXNggDVBGXSYsFMjkii1qLF+rugrIpWePN4/o= code.30cm.net/digimon/library-go/mongo v0.0.9 h1:fPciIE5B85tXpLg8aeVQqKVbLnfpVAk9xbMu7pE2tVw= code.30cm.net/digimon/library-go/mongo v0.0.9/go.mod h1:KBVKz/Ci5IheI77BgZxPUeKkaGvDy8fV8EDHSCOLIO4= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= diff --git a/pkg/usecase/product.go b/pkg/usecase/product.go index 0aeec73..08590c2 100644 --- a/pkg/usecase/product.go +++ b/pkg/usecase/product.go @@ -4,8 +4,15 @@ import ( "code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/entity" "code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/repository" "code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/usecase" + "code.30cm.net/digimon/app-cloudep-product-service/pkg/utils" "context" - "google.golang.org/protobuf/proto" + "github.com/zeromicro/go-zero/core/logx" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/mongo/readconcern" + + "code.30cm.net/digimon/library-go/errs" + "code.30cm.net/digimon/library-go/errs/code" ) type ProductUseCaseParam struct { @@ -26,36 +33,108 @@ func MustProductUseCase(param ProductUseCaseParam) usecase.ProductUseCase { } func (use *ProductUseCase) Create(ctx context.Context, product *usecase.Product) error { - //use.ProductRepo.Transaction() - insert := &entity.Product{ - UID: *product.UID, - Title: *product.Title, - ShortTitle: product.ShortTitle, - + // 資料前處理:準備 entity.Product 實體 + insert := &entity.Product{} + + if product.UID != nil { + insert.UID = *product.UID + } + if product.Title != nil { + insert.Title = *product.Title + } + if product.IsPublished != nil { + insert.IsPublished = *product.IsPublished + } + if product.Category != nil { + insert.Category = *product.Category + } + if product.ShortTitle != nil { + insert.ShortTitle = product.ShortTitle + } + if product.Details != nil { + insert.Details = product.Details + } + if product.ShortDescription != nil { + insert.ShortDescription = *product.ShortDescription + } + if product.Slug != nil { + insert.Slug = product.Slug + } + if product.Amount != 0 { + insert.Amount = product.Amount + } + if product.StartTime != nil { + st := utils.Rfc3339ToUnix(utils.ToValue(product.StartTime)) + insert.StartTime = &st + } + if product.EndTime != nil { + et := utils.Rfc3339ToUnix(utils.ToValue(product.EndTime)) + insert.EndTime = &et + } + if len(product.Media) > 0 { + medias := make([]entity.Media, 0, len(product.Media)) + for _, m := range product.Media { + medias = append(medias, entity.Media{ + Sort: m.Sort, + URL: m.URL, + Type: m.Type, + }) + } + insert.Media = medias + } + if len(product.CustomFields) > 0 { + cf := make([]entity.CustomFields, 0, len(product.CustomFields)) + for _, field := range product.CustomFields { + cf = append(cf, entity.CustomFields{ + Key: field.Key, + Value: field.Value, + }) + } + insert.CustomFields = cf } + // Transaction 設定:只做必要寫入 + opts := options.Transaction().SetReadConcern(readconcern.Local()) + err := use.ProductRepo.Transaction(ctx, func(sessCtx mongo.SessionContext) (any, error) { + // 插入 Product + if err := use.ProductRepo.Insert(sessCtx, insert); err != nil { + e := errs.DBError(code.CloudEPProduct, 0) + return nil, err + } - UID string `bson:"uid"` // 專案擁有者 UID - Title string `bson:"title"` // 專案名稱 - ShortTitle *string `bson:"short_title,omitempty"` // 計畫簡短標題 -> 不一定要有 - Details *string `bson:"details"` // 詳細內容 - ShortDescription string `bson:"short_description,omitempty"` // 簡短描述 - Media []Media `bson:"media,omitempty"` // 專案動態內容(圖片或者影片) - Slug *string `bson:"slug,omitempty"` // URL 後綴(查詢用) - IsPublished bool `bson:"is_published" ` // 是否已上架 - Amount uint64 `bson:"amount,omitempty"` // 目標金額 - StartTime *int64 `bson:"start_time,omitempty"` // 專案開始時間 - EndTime *int64 `bson:"end_time,omitempty"` // 專案結束時間 - Category string `bson:"category"` // 類別 - CustomFields []CustomFields `bson:"custom_fields,omitempty"` // 自定義屬性 + // 插入 Product 統計資料 + if err := use.ProductStatisticsRepo.Create(sessCtx, &entity.ProductStatistics{ + ProductID: insert.ID.Hex(), + Orders: 0, + OrdersUpdateTime: 0, + AverageRating: 0, + AverageRatingUpdateTime: 0, + FansCount: 0, + FansCountUpdateTime: 0, + }); err != nil { + return nil, err + } + // 過濾 Tag + // 綁定 Tags + for _, tag := range product.Tags { + if err := use.TagBinding.BindTag(sessCtx, &entity.TagsBindingTable{ + ReferenceID: insert.ID.Hex(), + TagID: tag, + }); err != nil { + logx.Errorf("failed to bind tag %s to product %s: %v", tag, insert.ID.Hex(), err) + return nil, err + } + } + + return nil, nil + }, opts) - err := use.ProductRepo.Insert(ctx, insert) if err != nil { return err } - //TODO implement me - panic("implement me") + + return nil } func (use *ProductUseCase) Update(ctx context.Context, id string, product *usecase.Product) error { diff --git a/pkg/utils/times.go b/pkg/utils/times.go new file mode 100644 index 0000000..36a5a81 --- /dev/null +++ b/pkg/utils/times.go @@ -0,0 +1,28 @@ +package utils + +import "time" + +func UnixToRfc3339(t int64) string { + res := time.Unix(0, t).UTC() + + return res.Format(time.RFC3339) +} + +func Rfc3339ToUnix(rfc3339 string) int64 { + // 解析 RFC3339 格式的時間 + t, err := time.Parse(time.RFC3339, rfc3339) + if err != nil { + return 0 + } + + // 轉換為 Unix Nano (納秒) + return t.UTC().UnixNano() +} + +func ToValue[T any](ptr *T) T { + if ptr == nil { + var zero T + return zero + } + return *ptr +}