v0.1
This commit is contained in:
@@ -4,30 +4,32 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Product 产品实体
|
||||
type Product struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" comment:"产品ID"`
|
||||
Name string `gorm:"type:varchar(100);not null" comment:"产品名称"`
|
||||
Code string `gorm:"type:varchar(50);uniqueIndex;not null" comment:"产品编号"`
|
||||
Description string `gorm:"type:text" comment:"产品简介"`
|
||||
Content string `gorm:"type:text" comment:"产品内容"`
|
||||
CategoryID string `gorm:"type:varchar(36);not null" comment:"产品分类ID"`
|
||||
Price float64 `gorm:"type:decimal(10,2);not null;default:0" comment:"产品价格"`
|
||||
IsEnabled bool `gorm:"default:true" comment:"是否启用"`
|
||||
IsVisible bool `gorm:"default:true" comment:"是否展示"`
|
||||
IsPackage bool `gorm:"default:false" comment:"是否组合包"`
|
||||
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" comment:"产品ID"`
|
||||
Name string `gorm:"type:varchar(100);not null" comment:"产品名称"`
|
||||
Code string `gorm:"type:varchar(50);uniqueIndex;not null" comment:"产品编号"`
|
||||
Description string `gorm:"type:text" comment:"产品简介"`
|
||||
Content string `gorm:"type:text" comment:"产品内容"`
|
||||
CategoryID string `gorm:"type:varchar(36);not null" comment:"产品分类ID"`
|
||||
Price decimal.Decimal `gorm:"type:decimal(10,2);not null;default:0" comment:"产品价格"`
|
||||
IsEnabled bool `gorm:"default:true" comment:"是否启用"`
|
||||
IsVisible bool `gorm:"default:true" comment:"是否展示"`
|
||||
IsPackage bool `gorm:"default:false" comment:"是否组合包"`
|
||||
// 组合包相关关联
|
||||
PackageItems []*ProductPackageItem `gorm:"foreignKey:PackageID" comment:"组合包项目列表"`
|
||||
// SEO信息
|
||||
SEOTitle string `gorm:"type:varchar(200)" comment:"SEO标题"`
|
||||
SEODescription string `gorm:"type:text" comment:"SEO描述"`
|
||||
SEOKeywords string `gorm:"type:text" comment:"SEO关键词"`
|
||||
|
||||
|
||||
// 关联关系
|
||||
Category *ProductCategory `gorm:"foreignKey:CategoryID" comment:"产品分类"`
|
||||
|
||||
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" comment:"创建时间"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" comment:"更新时间"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" comment:"软删除时间"`
|
||||
@@ -56,13 +58,6 @@ func (p *Product) CanBeSubscribed() bool {
|
||||
return p.IsValid() && p.IsVisible
|
||||
}
|
||||
|
||||
// GetDisplayPrice 获取显示价格
|
||||
func (p *Product) GetDisplayPrice() float64 {
|
||||
if p.Price < 0 {
|
||||
return 0
|
||||
}
|
||||
return p.Price
|
||||
}
|
||||
|
||||
// UpdateSEO 更新SEO信息
|
||||
func (p *Product) UpdateSEO(title, description, keywords string) {
|
||||
@@ -96,7 +91,6 @@ func (p *Product) SetAsPackage() {
|
||||
p.IsPackage = true
|
||||
}
|
||||
|
||||
// SetAsSingle 设置为单个产品
|
||||
func (p *Product) SetAsSingle() {
|
||||
p.IsPackage = false
|
||||
}
|
||||
func (p *Product) IsCombo() bool {
|
||||
return p.IsPackage
|
||||
}
|
||||
159
internal/domains/product/entities/product_api_config.go
Normal file
159
internal/domains/product/entities/product_api_config.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ProductApiConfig 产品API配置实体
|
||||
type ProductApiConfig struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" comment:"配置ID"`
|
||||
ProductID string `gorm:"type:varchar(36);not null;uniqueIndex" comment:"产品ID"`
|
||||
|
||||
// 请求参数配置
|
||||
RequestParams string `gorm:"type:json;not null" comment:"请求参数配置JSON"`
|
||||
|
||||
// 响应字段配置
|
||||
ResponseFields string `gorm:"type:json;not null" comment:"响应字段配置JSON"`
|
||||
|
||||
// 响应示例
|
||||
ResponseExample string `gorm:"type:json;not null" comment:"响应示例JSON"`
|
||||
|
||||
// 关联关系
|
||||
Product *Product `gorm:"foreignKey:ProductID" comment:"产品"`
|
||||
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" comment:"创建时间"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" comment:"更新时间"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" comment:"软删除时间"`
|
||||
}
|
||||
|
||||
// RequestParam 请求参数结构
|
||||
type RequestParam struct {
|
||||
Name string `json:"name" comment:"参数名称"`
|
||||
Field string `json:"field" comment:"参数字段名"`
|
||||
Type string `json:"type" comment:"参数类型"`
|
||||
Required bool `json:"required" comment:"是否必填"`
|
||||
Description string `json:"description" comment:"参数描述"`
|
||||
Example string `json:"example" comment:"参数示例"`
|
||||
Validation string `json:"validation" comment:"验证规则"`
|
||||
}
|
||||
|
||||
// ResponseField 响应字段结构
|
||||
type ResponseField struct {
|
||||
Name string `json:"name" comment:"字段名称"`
|
||||
Path string `json:"path" comment:"字段路径"`
|
||||
Type string `json:"type" comment:"字段类型"`
|
||||
Description string `json:"description" comment:"字段描述"`
|
||||
Required bool `json:"required" comment:"是否必填"`
|
||||
Example string `json:"example" comment:"字段示例"`
|
||||
}
|
||||
|
||||
// BeforeCreate GORM钩子:创建前自动生成UUID
|
||||
func (pac *ProductApiConfig) BeforeCreate(tx *gorm.DB) error {
|
||||
if pac.ID == "" {
|
||||
pac.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Validate 验证产品API配置
|
||||
func (pac *ProductApiConfig) Validate() error {
|
||||
if pac.ProductID == "" {
|
||||
return NewValidationError("产品ID不能为空")
|
||||
}
|
||||
if pac.RequestParams == "" {
|
||||
return NewValidationError("请求参数配置不能为空")
|
||||
}
|
||||
if pac.ResponseFields == "" {
|
||||
return NewValidationError("响应字段配置不能为空")
|
||||
}
|
||||
if pac.ResponseExample == "" {
|
||||
return NewValidationError("响应示例不能为空")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewValidationError 创建验证错误
|
||||
func NewValidationError(message string) error {
|
||||
return &ValidationError{Message: message}
|
||||
}
|
||||
|
||||
// ValidationError 验证错误
|
||||
type ValidationError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *ValidationError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
// GetRequestParams 获取请求参数列表
|
||||
func (pac *ProductApiConfig) GetRequestParams() ([]RequestParam, error) {
|
||||
var params []RequestParam
|
||||
if pac.RequestParams != "" {
|
||||
err := json.Unmarshal([]byte(pac.RequestParams), ¶ms)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
// SetRequestParams 设置请求参数列表
|
||||
func (pac *ProductApiConfig) SetRequestParams(params []RequestParam) error {
|
||||
data, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pac.RequestParams = string(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetResponseFields 获取响应字段列表
|
||||
func (pac *ProductApiConfig) GetResponseFields() ([]ResponseField, error) {
|
||||
var fields []ResponseField
|
||||
if pac.ResponseFields != "" {
|
||||
err := json.Unmarshal([]byte(pac.ResponseFields), &fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
// SetResponseFields 设置响应字段列表
|
||||
func (pac *ProductApiConfig) SetResponseFields(fields []ResponseField) error {
|
||||
data, err := json.Marshal(fields)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pac.ResponseFields = string(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetResponseExample 获取响应示例
|
||||
func (pac *ProductApiConfig) GetResponseExample() (map[string]interface{}, error) {
|
||||
var example map[string]interface{}
|
||||
if pac.ResponseExample != "" {
|
||||
err := json.Unmarshal([]byte(pac.ResponseExample), &example)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return example, nil
|
||||
}
|
||||
|
||||
// SetResponseExample 设置响应示例
|
||||
func (pac *ProductApiConfig) SetResponseExample(example map[string]interface{}) error {
|
||||
data, err := json.Marshal(example)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pac.ResponseExample = string(data)
|
||||
return nil
|
||||
}
|
||||
@@ -9,17 +9,17 @@ import (
|
||||
|
||||
// ProductCategory 产品分类实体
|
||||
type ProductCategory struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" comment:"分类ID"`
|
||||
Name string `gorm:"type:varchar(100);not null" comment:"分类名称"`
|
||||
Code string `gorm:"type:varchar(50);uniqueIndex;not null" comment:"分类编号"`
|
||||
Description string `gorm:"type:text" comment:"分类描述"`
|
||||
Sort int `gorm:"default:0" comment:"排序"`
|
||||
IsEnabled bool `gorm:"default:true" comment:"是否启用"`
|
||||
IsVisible bool `gorm:"default:true" comment:"是否展示"`
|
||||
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" comment:"分类ID"`
|
||||
Name string `gorm:"type:varchar(100);not null" comment:"分类名称"`
|
||||
Code string `gorm:"type:varchar(50);uniqueIndex;not null" comment:"分类编号"`
|
||||
Description string `gorm:"type:text" comment:"分类描述"`
|
||||
Sort int `gorm:"default:0" comment:"排序"`
|
||||
IsEnabled bool `gorm:"default:true" comment:"是否启用"`
|
||||
IsVisible bool `gorm:"default:true" comment:"是否展示"`
|
||||
|
||||
// 关联关系
|
||||
Products []Product `gorm:"foreignKey:CategoryID" comment:"产品列表"`
|
||||
|
||||
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" comment:"创建时间"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" comment:"更新时间"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" comment:"软删除时间"`
|
||||
@@ -61,4 +61,4 @@ func (pc *ProductCategory) Show() {
|
||||
// Hide 隐藏分类
|
||||
func (pc *ProductCategory) Hide() {
|
||||
pc.IsVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
32
internal/domains/product/entities/product_package_item.go
Normal file
32
internal/domains/product/entities/product_package_item.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ProductPackageItem 产品组合包项目
|
||||
type ProductPackageItem struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)"`
|
||||
PackageID string `gorm:"type:varchar(36);not null;index" comment:"组合包产品ID"`
|
||||
ProductID string `gorm:"type:varchar(36);not null;index" comment:"子产品ID"`
|
||||
SortOrder int `gorm:"default:0" comment:"排序"`
|
||||
|
||||
// 关联关系
|
||||
Package *Product `gorm:"foreignKey:PackageID" comment:"组合包产品"`
|
||||
Product *Product `gorm:"foreignKey:ProductID" comment:"子产品"`
|
||||
|
||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
}
|
||||
|
||||
// BeforeCreate GORM钩子:创建前自动生成UUID
|
||||
func (ppi *ProductPackageItem) BeforeCreate(tx *gorm.DB) error {
|
||||
if ppi.ID == "" {
|
||||
ppi.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
53
internal/domains/product/entities/product_parameter.go
Normal file
53
internal/domains/product/entities/product_parameter.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ProductParameter 产品参数配置实体
|
||||
type ProductParameter struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" comment:"参数配置ID"`
|
||||
ProductID string `gorm:"type:varchar(36);not null;index" comment:"产品ID"`
|
||||
Name string `gorm:"type:varchar(100);not null" comment:"参数名称"`
|
||||
Field string `gorm:"type:varchar(50);not null" comment:"参数字段名"`
|
||||
Type string `gorm:"type:varchar(20);not null;default:'string'" comment:"参数类型"`
|
||||
Required bool `gorm:"default:true" comment:"是否必填"`
|
||||
Description string `gorm:"type:text" comment:"参数描述"`
|
||||
Example string `gorm:"type:varchar(200)" comment:"参数示例"`
|
||||
Validation string `gorm:"type:text" comment:"验证规则"`
|
||||
SortOrder int `gorm:"default:0" comment:"排序"`
|
||||
|
||||
// 关联关系
|
||||
Product *Product `gorm:"foreignKey:ProductID" comment:"产品"`
|
||||
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" comment:"创建时间"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" comment:"更新时间"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" comment:"软删除时间"`
|
||||
}
|
||||
|
||||
// BeforeCreate GORM钩子:创建前自动生成UUID
|
||||
func (pp *ProductParameter) BeforeCreate(tx *gorm.DB) error {
|
||||
if pp.ID == "" {
|
||||
pp.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid 检查参数配置是否有效
|
||||
func (pp *ProductParameter) IsValid() bool {
|
||||
return pp.DeletedAt.Time.IsZero()
|
||||
}
|
||||
|
||||
// GetValidationRules 获取验证规则
|
||||
func (pp *ProductParameter) GetValidationRules() map[string]interface{} {
|
||||
if pp.Validation == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 这里可以解析JSON格式的验证规则
|
||||
// 暂时返回空map,后续可以扩展
|
||||
return make(map[string]interface{})
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -12,7 +13,7 @@ type Subscription struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" comment:"订阅ID"`
|
||||
UserID string `gorm:"type:varchar(36);not null;index" comment:"用户ID"`
|
||||
ProductID string `gorm:"type:varchar(36);not null;index" comment:"产品ID"`
|
||||
Price float64 `gorm:"type:decimal(10,2);not null" comment:"订阅价格"`
|
||||
Price decimal.Decimal `gorm:"type:decimal(10,2);not null" comment:"订阅价格"`
|
||||
APIUsed int64 `gorm:"default:0" comment:"已使用API调用次数"`
|
||||
|
||||
// 关联关系
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"tyapi-server/internal/domains/product/entities"
|
||||
)
|
||||
|
||||
// ProductApiConfigRepository 产品API配置仓库接口
|
||||
type ProductApiConfigRepository interface {
|
||||
// 基础CRUD操作
|
||||
Create(ctx context.Context, config entities.ProductApiConfig) error
|
||||
Update(ctx context.Context, config entities.ProductApiConfig) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
GetByID(ctx context.Context, id string) (*entities.ProductApiConfig, error)
|
||||
|
||||
// 根据产品ID查找配置
|
||||
FindByProductID(ctx context.Context, productID string) (*entities.ProductApiConfig, error)
|
||||
|
||||
// 根据产品代码查找配置
|
||||
FindByProductCode(ctx context.Context, productCode string) (*entities.ProductApiConfig, error)
|
||||
|
||||
// 批量获取配置
|
||||
FindByProductIDs(ctx context.Context, productIDs []string) ([]*entities.ProductApiConfig, error)
|
||||
|
||||
// 检查配置是否存在
|
||||
ExistsByProductID(ctx context.Context, productID string) (bool, error)
|
||||
}
|
||||
@@ -10,22 +10,30 @@ import (
|
||||
// ProductRepository 产品仓储接口
|
||||
type ProductRepository interface {
|
||||
interfaces.Repository[entities.Product]
|
||||
|
||||
|
||||
// 基础查询方法
|
||||
FindByCode(ctx context.Context, code string) (*entities.Product, error)
|
||||
FindByCategoryID(ctx context.Context, categoryID string) ([]*entities.Product, error)
|
||||
FindVisible(ctx context.Context) ([]*entities.Product, error)
|
||||
FindEnabled(ctx context.Context) ([]*entities.Product, error)
|
||||
|
||||
|
||||
// 复杂查询方法
|
||||
ListProducts(ctx context.Context, query *queries.ListProductsQuery) ([]*entities.Product, int64, error)
|
||||
|
||||
|
||||
// 业务查询方法
|
||||
FindSubscribableProducts(ctx context.Context, userID string) ([]*entities.Product, error)
|
||||
FindProductsByIDs(ctx context.Context, ids []string) ([]*entities.Product, error)
|
||||
|
||||
|
||||
// 统计方法
|
||||
CountByCategory(ctx context.Context, categoryID string) (int64, error)
|
||||
CountEnabled(ctx context.Context) (int64, error)
|
||||
CountVisible(ctx context.Context) (int64, error)
|
||||
}
|
||||
|
||||
// 组合包相关方法
|
||||
GetPackageItems(ctx context.Context, packageID string) ([]*entities.ProductPackageItem, error)
|
||||
CreatePackageItem(ctx context.Context, packageItem *entities.ProductPackageItem) error
|
||||
GetPackageItemByID(ctx context.Context, itemID string) (*entities.ProductPackageItem, error)
|
||||
UpdatePackageItem(ctx context.Context, packageItem *entities.ProductPackageItem) error
|
||||
DeletePackageItem(ctx context.Context, itemID string) error
|
||||
DeletePackageItemsByPackageID(ctx context.Context, packageID string) error
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ package queries
|
||||
|
||||
// ListSubscriptionsQuery 订阅列表查询
|
||||
type ListSubscriptionsQuery struct {
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
UserID string `json:"user_id"`
|
||||
Keyword string `json:"keyword"`
|
||||
SortBy string `json:"sort_by"`
|
||||
SortOrder string `json:"sort_order"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
UserID string `json:"user_id"`
|
||||
Keyword string `json:"keyword"`
|
||||
SortBy string `json:"sort_by"`
|
||||
SortOrder string `json:"sort_order"`
|
||||
}
|
||||
|
||||
// GetSubscriptionQuery 获取订阅详情查询
|
||||
@@ -23,4 +23,4 @@ type GetUserSubscriptionsQuery struct {
|
||||
// GetProductSubscriptionsQuery 获取产品订阅查询
|
||||
type GetProductSubscriptionsQuery struct {
|
||||
ProductID string `json:"product_id"`
|
||||
}
|
||||
}
|
||||
|
||||
161
internal/domains/product/services/product_api_config_service.go
Normal file
161
internal/domains/product/services/product_api_config_service.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"tyapi-server/internal/domains/product/entities"
|
||||
"tyapi-server/internal/domains/product/repositories"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// ProductApiConfigService 产品API配置领域服务接口
|
||||
type ProductApiConfigService interface {
|
||||
// 根据产品ID获取API配置
|
||||
GetApiConfigByProductID(ctx context.Context, productID string) (*entities.ProductApiConfig, error)
|
||||
|
||||
// 根据产品代码获取API配置
|
||||
GetApiConfigByProductCode(ctx context.Context, productCode string) (*entities.ProductApiConfig, error)
|
||||
|
||||
// 批量获取产品API配置
|
||||
GetApiConfigsByProductIDs(ctx context.Context, productIDs []string) ([]*entities.ProductApiConfig, error)
|
||||
|
||||
// 创建产品API配置
|
||||
CreateApiConfig(ctx context.Context, config *entities.ProductApiConfig) error
|
||||
|
||||
// 更新产品API配置
|
||||
UpdateApiConfig(ctx context.Context, config *entities.ProductApiConfig) error
|
||||
|
||||
// 删除产品API配置
|
||||
DeleteApiConfig(ctx context.Context, configID string) error
|
||||
|
||||
// 检查产品API配置是否存在
|
||||
ExistsByProductID(ctx context.Context, productID string) (bool, error)
|
||||
}
|
||||
|
||||
// ProductApiConfigServiceImpl 产品API配置领域服务实现
|
||||
type ProductApiConfigServiceImpl struct {
|
||||
apiConfigRepo repositories.ProductApiConfigRepository
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewProductApiConfigService 创建产品API配置领域服务
|
||||
func NewProductApiConfigService(
|
||||
apiConfigRepo repositories.ProductApiConfigRepository,
|
||||
logger *zap.Logger,
|
||||
) ProductApiConfigService {
|
||||
return &ProductApiConfigServiceImpl{
|
||||
apiConfigRepo: apiConfigRepo,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// GetApiConfigByProductID 根据产品ID获取API配置
|
||||
func (s *ProductApiConfigServiceImpl) GetApiConfigByProductID(ctx context.Context, productID string) (*entities.ProductApiConfig, error) {
|
||||
s.logger.Debug("获取产品API配置", zap.String("product_id", productID))
|
||||
|
||||
config, err := s.apiConfigRepo.FindByProductID(ctx, productID)
|
||||
if err != nil {
|
||||
s.logger.Error("获取产品API配置失败", zap.Error(err), zap.String("product_id", productID))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// GetApiConfigByProductCode 根据产品代码获取API配置
|
||||
func (s *ProductApiConfigServiceImpl) GetApiConfigByProductCode(ctx context.Context, productCode string) (*entities.ProductApiConfig, error) {
|
||||
s.logger.Debug("根据产品代码获取API配置", zap.String("product_code", productCode))
|
||||
|
||||
config, err := s.apiConfigRepo.FindByProductCode(ctx, productCode)
|
||||
if err != nil {
|
||||
s.logger.Error("根据产品代码获取API配置失败", zap.Error(err), zap.String("product_code", productCode))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// GetApiConfigsByProductIDs 批量获取产品API配置
|
||||
func (s *ProductApiConfigServiceImpl) GetApiConfigsByProductIDs(ctx context.Context, productIDs []string) ([]*entities.ProductApiConfig, error) {
|
||||
s.logger.Debug("批量获取产品API配置", zap.Strings("product_ids", productIDs))
|
||||
|
||||
configs, err := s.apiConfigRepo.FindByProductIDs(ctx, productIDs)
|
||||
if err != nil {
|
||||
s.logger.Error("批量获取产品API配置失败", zap.Error(err), zap.Strings("product_ids", productIDs))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
// CreateApiConfig 创建产品API配置
|
||||
func (s *ProductApiConfigServiceImpl) CreateApiConfig(ctx context.Context, config *entities.ProductApiConfig) error {
|
||||
s.logger.Debug("创建产品API配置", zap.String("product_id", config.ProductID))
|
||||
|
||||
// 检查是否已存在配置
|
||||
exists, err := s.apiConfigRepo.ExistsByProductID(ctx, config.ProductID)
|
||||
if err != nil {
|
||||
s.logger.Error("检查产品API配置是否存在失败", zap.Error(err), zap.String("product_id", config.ProductID))
|
||||
return err
|
||||
}
|
||||
|
||||
if exists {
|
||||
return entities.NewValidationError("产品API配置已存在")
|
||||
}
|
||||
|
||||
// 验证配置
|
||||
if err := config.Validate(); err != nil {
|
||||
s.logger.Error("产品API配置验证失败", zap.Error(err), zap.String("product_id", config.ProductID))
|
||||
return err
|
||||
}
|
||||
|
||||
// 保存配置
|
||||
err = s.apiConfigRepo.Create(ctx, *config)
|
||||
if err != nil {
|
||||
s.logger.Error("创建产品API配置失败", zap.Error(err), zap.String("product_id", config.ProductID))
|
||||
return err
|
||||
}
|
||||
|
||||
s.logger.Info("产品API配置创建成功", zap.String("product_id", config.ProductID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateApiConfig 更新产品API配置
|
||||
func (s *ProductApiConfigServiceImpl) UpdateApiConfig(ctx context.Context, config *entities.ProductApiConfig) error {
|
||||
s.logger.Debug("更新产品API配置", zap.String("config_id", config.ID))
|
||||
|
||||
// 验证配置
|
||||
if err := config.Validate(); err != nil {
|
||||
s.logger.Error("产品API配置验证失败", zap.Error(err), zap.String("config_id", config.ID))
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新配置
|
||||
err := s.apiConfigRepo.Update(ctx, *config)
|
||||
if err != nil {
|
||||
s.logger.Error("更新产品API配置失败", zap.Error(err), zap.String("config_id", config.ID))
|
||||
return err
|
||||
}
|
||||
|
||||
s.logger.Info("产品API配置更新成功", zap.String("config_id", config.ID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteApiConfig 删除产品API配置
|
||||
func (s *ProductApiConfigServiceImpl) DeleteApiConfig(ctx context.Context, configID string) error {
|
||||
s.logger.Debug("删除产品API配置", zap.String("config_id", configID))
|
||||
|
||||
err := s.apiConfigRepo.Delete(ctx, configID)
|
||||
if err != nil {
|
||||
s.logger.Error("删除产品API配置失败", zap.Error(err), zap.String("config_id", configID))
|
||||
return err
|
||||
}
|
||||
|
||||
s.logger.Info("产品API配置删除成功", zap.String("config_id", configID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExistsByProductID 检查产品API配置是否存在
|
||||
func (s *ProductApiConfigServiceImpl) ExistsByProductID(ctx context.Context, productID string) (bool, error) {
|
||||
return s.apiConfigRepo.ExistsByProductID(ctx, productID)
|
||||
}
|
||||
@@ -8,8 +8,11 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"tyapi-server/internal/application/product/dto/commands"
|
||||
"tyapi-server/internal/domains/product/entities"
|
||||
"tyapi-server/internal/domains/product/repositories"
|
||||
"tyapi-server/internal/domains/product/repositories/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
)
|
||||
|
||||
// ProductManagementService 产品管理领域服务
|
||||
@@ -69,6 +72,13 @@ func (s *ProductManagementService) GetProductByID(ctx context.Context, productID
|
||||
return &product, nil
|
||||
}
|
||||
|
||||
func (s *ProductManagementService) GetProductByCode(ctx context.Context, productCode string) (*entities.Product, error) {
|
||||
product, err := s.productRepo.FindByCode(ctx, productCode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("产品不存在: %w", err)
|
||||
}
|
||||
return product, nil
|
||||
}
|
||||
// GetProductWithCategory 获取产品及其分类信息
|
||||
func (s *ProductManagementService) GetProductWithCategory(ctx context.Context, productID string) (*entities.Product, error) {
|
||||
product, err := s.productRepo.GetByID(ctx, productID)
|
||||
@@ -84,9 +94,107 @@ func (s *ProductManagementService) GetProductWithCategory(ctx context.Context, p
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是组合包,加载子产品信息
|
||||
if product.IsPackage {
|
||||
packageItems, err := s.productRepo.GetPackageItems(ctx, productID)
|
||||
if err == nil {
|
||||
product.PackageItems = packageItems
|
||||
}
|
||||
}
|
||||
|
||||
return &product, nil
|
||||
}
|
||||
|
||||
// GetPackageItems 获取组合包项目列表
|
||||
func (s *ProductManagementService) GetPackageItems(ctx context.Context, packageID string) ([]*entities.ProductPackageItem, error) {
|
||||
packageItems, err := s.productRepo.GetPackageItems(ctx, packageID)
|
||||
if err != nil {
|
||||
s.logger.Error("获取组合包项目失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("获取组合包项目失败: %w", err)
|
||||
}
|
||||
return packageItems, nil
|
||||
}
|
||||
|
||||
// CreatePackageItem 创建组合包项目
|
||||
func (s *ProductManagementService) CreatePackageItem(ctx context.Context, packageItem *entities.ProductPackageItem) error {
|
||||
if err := s.productRepo.CreatePackageItem(ctx, packageItem); err != nil {
|
||||
s.logger.Error("创建组合包项目失败", zap.Error(err))
|
||||
return fmt.Errorf("创建组合包项目失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("组合包项目创建成功",
|
||||
zap.String("package_id", packageItem.PackageID),
|
||||
zap.String("product_id", packageItem.ProductID),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPackageItemByID 根据ID获取组合包项目
|
||||
func (s *ProductManagementService) GetPackageItemByID(ctx context.Context, itemID string) (*entities.ProductPackageItem, error) {
|
||||
packageItem, err := s.productRepo.GetPackageItemByID(ctx, itemID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("组合包项目不存在: %w", err)
|
||||
}
|
||||
return packageItem, nil
|
||||
}
|
||||
|
||||
// UpdatePackageItem 更新组合包项目
|
||||
func (s *ProductManagementService) UpdatePackageItem(ctx context.Context, packageItem *entities.ProductPackageItem) error {
|
||||
if err := s.productRepo.UpdatePackageItem(ctx, packageItem); err != nil {
|
||||
s.logger.Error("更新组合包项目失败", zap.Error(err))
|
||||
return fmt.Errorf("更新组合包项目失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("组合包项目更新成功",
|
||||
zap.String("item_id", packageItem.ID),
|
||||
zap.String("package_id", packageItem.PackageID),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeletePackageItem 删除组合包项目
|
||||
func (s *ProductManagementService) DeletePackageItem(ctx context.Context, itemID string) error {
|
||||
if err := s.productRepo.DeletePackageItem(ctx, itemID); err != nil {
|
||||
s.logger.Error("删除组合包项目失败", zap.Error(err))
|
||||
return fmt.Errorf("删除组合包项目失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("组合包项目删除成功", zap.String("item_id", itemID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdatePackageItemsBatch 批量更新组合包子产品
|
||||
func (s *ProductManagementService) UpdatePackageItemsBatch(ctx context.Context, packageID string, items []commands.PackageItemData) error {
|
||||
// 删除现有的所有子产品
|
||||
if err := s.productRepo.DeletePackageItemsByPackageID(ctx, packageID); err != nil {
|
||||
s.logger.Error("删除现有组合包子产品失败", zap.Error(err))
|
||||
return fmt.Errorf("删除现有组合包子产品失败: %w", err)
|
||||
}
|
||||
|
||||
// 创建新的子产品项目
|
||||
for _, item := range items {
|
||||
packageItem := &entities.ProductPackageItem{
|
||||
PackageID: packageID,
|
||||
ProductID: item.ProductID,
|
||||
SortOrder: item.SortOrder,
|
||||
}
|
||||
|
||||
if err := s.productRepo.CreatePackageItem(ctx, packageItem); err != nil {
|
||||
s.logger.Error("创建组合包子产品失败", zap.Error(err))
|
||||
return fmt.Errorf("创建组合包子产品失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
s.logger.Info("批量更新组合包子产品成功",
|
||||
zap.String("package_id", packageID),
|
||||
zap.Int("item_count", len(items)),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateProduct 更新产品
|
||||
func (s *ProductManagementService) UpdateProduct(ctx context.Context, product *entities.Product) error {
|
||||
// 验证产品信息
|
||||
@@ -152,7 +260,7 @@ func (s *ProductManagementService) ValidateProduct(product *entities.Product) er
|
||||
return errors.New("产品编号不能为空")
|
||||
}
|
||||
|
||||
if product.Price < 0 {
|
||||
if product.Price.IsNegative() {
|
||||
return errors.New("产品价格不能为负数")
|
||||
}
|
||||
|
||||
@@ -182,4 +290,48 @@ func (s *ProductManagementService) ValidateProductCode(code string, excludeID st
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ListProducts 获取产品列表(支持筛选和分页)
|
||||
func (s *ProductManagementService) ListProducts(ctx context.Context, filters map[string]interface{}, options interfaces.ListOptions) ([]*entities.Product, int64, error) {
|
||||
// 构建查询条件
|
||||
query := &queries.ListProductsQuery{
|
||||
Page: options.Page,
|
||||
PageSize: options.PageSize,
|
||||
SortBy: options.Sort,
|
||||
SortOrder: options.Order,
|
||||
}
|
||||
|
||||
// 应用筛选条件
|
||||
if keyword, ok := filters["keyword"].(string); ok && keyword != "" {
|
||||
query.Keyword = keyword
|
||||
}
|
||||
if categoryID, ok := filters["category_id"].(string); ok && categoryID != "" {
|
||||
query.CategoryID = categoryID
|
||||
}
|
||||
if isEnabled, ok := filters["is_enabled"].(bool); ok {
|
||||
query.IsEnabled = &isEnabled
|
||||
}
|
||||
if isVisible, ok := filters["is_visible"].(bool); ok {
|
||||
query.IsVisible = &isVisible
|
||||
}
|
||||
if isPackage, ok := filters["is_package"].(bool); ok {
|
||||
query.IsPackage = &isPackage
|
||||
}
|
||||
|
||||
// 调用仓储层获取产品列表
|
||||
products, total, err := s.productRepo.ListProducts(ctx, query)
|
||||
if err != nil {
|
||||
s.logger.Error("获取产品列表失败", zap.Error(err))
|
||||
return nil, 0, fmt.Errorf("获取产品列表失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("产品列表查询成功",
|
||||
zap.Int("count", len(products)),
|
||||
zap.Int64("total", total),
|
||||
zap.Int("page", options.Page),
|
||||
zap.Int("page_size", options.PageSize),
|
||||
)
|
||||
|
||||
return products, total, nil
|
||||
}
|
||||
@@ -5,10 +5,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"tyapi-server/internal/domains/product/entities"
|
||||
"tyapi-server/internal/domains/product/repositories"
|
||||
"tyapi-server/internal/domains/product/repositories/queries"
|
||||
)
|
||||
|
||||
// ProductSubscriptionService 产品订阅领域服务
|
||||
@@ -32,6 +35,31 @@ func NewProductSubscriptionService(
|
||||
}
|
||||
}
|
||||
|
||||
// UserSubscribedProductByCode 查找用户已订阅的产品
|
||||
func (s *ProductSubscriptionService) UserSubscribedProductByCode(ctx context.Context, userID string, productCode string) (*entities.Subscription, error) {
|
||||
product, err := s.productRepo.FindByCode(ctx, productCode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
subscription, err := s.subscriptionRepo.FindByUserAndProduct(ctx, userID, product.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return subscription, nil
|
||||
}
|
||||
|
||||
// GetUserSubscribedProduct 查找用户已订阅的产品
|
||||
func (s *ProductSubscriptionService) GetUserSubscribedProduct(ctx context.Context, userID string, productID string) (*entities.Subscription, error) {
|
||||
subscription, err := s.subscriptionRepo.FindByUserAndProduct(ctx, userID, productID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return subscription, nil
|
||||
}
|
||||
|
||||
// CanUserSubscribeProduct 检查用户是否可以订阅产品
|
||||
func (s *ProductSubscriptionService) CanUserSubscribeProduct(ctx context.Context, userID string, productID string) (bool, error) {
|
||||
// 检查产品是否存在且可订阅
|
||||
@@ -92,6 +120,11 @@ func (s *ProductSubscriptionService) CreateSubscription(ctx context.Context, use
|
||||
return &createdSubscription, nil
|
||||
}
|
||||
|
||||
// ListSubscriptions 获取订阅列表
|
||||
func (s *ProductSubscriptionService) ListSubscriptions(ctx context.Context, query *queries.ListSubscriptionsQuery) ([]*entities.Subscription, int64, error) {
|
||||
return s.subscriptionRepo.ListSubscriptions(ctx, query)
|
||||
}
|
||||
|
||||
// GetUserSubscriptions 获取用户订阅列表
|
||||
func (s *ProductSubscriptionService) GetUserSubscriptions(ctx context.Context, userID string) ([]*entities.Subscription, error) {
|
||||
return s.subscriptionRepo.FindByUserID(ctx, userID)
|
||||
@@ -141,4 +174,20 @@ func (s *ProductSubscriptionService) GetProductStats(ctx context.Context) (map[s
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ProductSubscriptionService) SaveSubscription(ctx context.Context, subscription *entities.Subscription) error {
|
||||
exists, err := s.subscriptionRepo.Exists(ctx, subscription.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("检查订阅是否存在失败: %w", err)
|
||||
}
|
||||
if exists {
|
||||
return s.subscriptionRepo.Update(ctx, *subscription)
|
||||
} else {
|
||||
_, err := s.subscriptionRepo.Create(ctx, *subscription)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建订阅失败: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user