初始化项目
This commit is contained in:
104
service/ad_source_service.go
Normal file
104
service/ad_source_service.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
var (
|
||||
AdSource = adSourceService{}
|
||||
)
|
||||
|
||||
type adSourceService struct{}
|
||||
|
||||
// GetAvailableSources 获取可用的广告源列表
|
||||
func (s *adSourceService) GetAvailableSources(ctx context.Context) (list []*entity.AdSource, err error) {
|
||||
return dao.AdSource.GetAvailableSources(ctx)
|
||||
}
|
||||
|
||||
// GetSourcesByProvider 根据提供商获取广告源
|
||||
func (s *adSourceService) GetSourcesByProvider(ctx context.Context, provider string) (list []*entity.AdSource, err error) {
|
||||
return dao.AdSource.GetSourcesByProvider(ctx, provider)
|
||||
}
|
||||
|
||||
// CreateAdSource 创建广告源
|
||||
func (s *adSourceService) CreateAdSource(ctx context.Context, req *dto.CreateAdSourceReq) (id int64, err error) {
|
||||
// 检查广告源名称是否已存在
|
||||
existingSource, err := dao.AdSource.GetByName(ctx, req.Name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingSource != nil {
|
||||
return 0, gerror.New("广告源名称已存在")
|
||||
}
|
||||
|
||||
adSource := &entity.AdSource{
|
||||
Name: req.Name,
|
||||
Code: req.Code,
|
||||
Provider: req.Provider,
|
||||
Type: req.Type,
|
||||
APIEndpoint: req.APIEndpoint,
|
||||
Status: "active", // 默认状态
|
||||
Priority: 1, // 默认优先级
|
||||
}
|
||||
|
||||
return dao.AdSource.Create(ctx, adSource)
|
||||
}
|
||||
|
||||
// UpdateAdSource 更新广告源
|
||||
func (s *adSourceService) UpdateAdSource(ctx context.Context, id int64, req *dto.UpdateAdSourceReq) (affected int64, err error) {
|
||||
|
||||
// 检查广告源是否存在
|
||||
existingSource, err := dao.AdSource.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingSource == nil {
|
||||
return 0, gerror.New("广告源不存在")
|
||||
}
|
||||
|
||||
// 如果更新名称,检查是否与其他广告源冲突
|
||||
if req.Name != "" && req.Name != existingSource.Name {
|
||||
conflictSource, err := dao.AdSource.GetByName(ctx, req.Name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if conflictSource != nil {
|
||||
return 0, gerror.New("广告源名称已存在")
|
||||
}
|
||||
}
|
||||
|
||||
// 构建更新数据
|
||||
updateData := &entity.AdSource{}
|
||||
if req.Name != "" {
|
||||
updateData.Name = req.Name
|
||||
}
|
||||
if req.APIEndpoint != "" {
|
||||
updateData.APIEndpoint = req.APIEndpoint
|
||||
}
|
||||
|
||||
return dao.AdSource.UpdateFields(ctx, id, updateData)
|
||||
}
|
||||
|
||||
// DeleteAdSource 删除广告源
|
||||
func (s *adSourceService) DeleteAdSource(ctx context.Context, id int64) (affected int64, err error) {
|
||||
// 检查广告源是否存在
|
||||
existingSource, err := dao.AdSource.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingSource == nil {
|
||||
return 0, gerror.New("广告源不存在")
|
||||
}
|
||||
|
||||
return dao.AdSource.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// GetAdSourceByID 根据ID获取广告源
|
||||
func (s *adSourceService) GetAdSourceByID(ctx context.Context, id int64) (adSource *entity.AdSource, err error) {
|
||||
return dao.AdSource.GetByID(ctx, id)
|
||||
}
|
||||
360
service/cid_service.go
Normal file
360
service/cid_service.go
Normal file
@@ -0,0 +1,360 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidService/model/types"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/utils"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var (
|
||||
CID = cidService{}
|
||||
)
|
||||
|
||||
type cidService struct{}
|
||||
|
||||
// AdMatchingStrategy 广告匹配策略
|
||||
type AdMatchingStrategy struct {
|
||||
TenantLevel string // 租户级别
|
||||
MinConversion float64 // 最低转化率
|
||||
MaxConversion float64 // 最高转化率
|
||||
SourceWeight map[string]int // 广告源权重
|
||||
MaxAdsPerRequest int // 每次请求最大广告数
|
||||
}
|
||||
|
||||
// getMatchingStrategy 获取匹配策略
|
||||
func (s *cidService) getMatchingStrategy(ctx context.Context, tenantLevel string) (*AdMatchingStrategy, error) {
|
||||
// 从数据库获取策略
|
||||
strategyEntity, err := Strategy.GetStrategyByTenantLevel(ctx, tenantLevel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if strategyEntity == nil {
|
||||
// 返回默认策略
|
||||
return &AdMatchingStrategy{
|
||||
TenantLevel: tenantLevel,
|
||||
MinConversion: 0.01,
|
||||
MaxConversion: 0.05,
|
||||
SourceWeight: map[string]int{"self": 100},
|
||||
MaxAdsPerRequest: 3,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 反序列化权重配置
|
||||
var sourceWeights map[string]int
|
||||
if strategyEntity.SourceWeights != "" {
|
||||
err = json.Unmarshal([]byte(strategyEntity.SourceWeights), &sourceWeights)
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "策略权重反序列化失败: %v", err)
|
||||
sourceWeights = map[string]int{"self": 100}
|
||||
}
|
||||
}
|
||||
|
||||
return &AdMatchingStrategy{
|
||||
TenantLevel: strategyEntity.TenantLevel,
|
||||
MinConversion: strategyEntity.MinConversion,
|
||||
MaxConversion: strategyEntity.MaxConversion,
|
||||
SourceWeight: sourceWeights,
|
||||
MaxAdsPerRequest: strategyEntity.MaxAdsPerReq,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GenerateCID 生成CID广告
|
||||
func (s *cidService) GenerateCID(ctx context.Context, req *dto.GenerateCIDReq) (res *dto.GenerateCIDRes, err error) {
|
||||
// 获取当前用户信息
|
||||
userInfo, err := utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "获取用户信息失败")
|
||||
}
|
||||
|
||||
// 获取租户信息
|
||||
tenant, err := s.getTenantByUser(ctx, gconv.Int64(userInfo.UserName))
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "获取租户信息失败")
|
||||
}
|
||||
|
||||
// 获取匹配策略
|
||||
strategy, err := s.getMatchingStrategy(ctx, tenant.Level)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "获取匹配策略失败")
|
||||
}
|
||||
|
||||
// 根据策略获取广告
|
||||
ads, err := s.matchAds(ctx, req, strategy)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "广告匹配失败")
|
||||
}
|
||||
|
||||
// 记录CID请求
|
||||
go s.recordCIDRequest(context.Background(), req, tenant, ads)
|
||||
|
||||
// 生成唯一CID
|
||||
cid := s.generateUniqueCID()
|
||||
|
||||
return &dto.GenerateCIDRes{
|
||||
CID: cid,
|
||||
Ads: ads,
|
||||
TotalAds: len(ads),
|
||||
TenantId: tenant.Id,
|
||||
TenantName: tenant.Name,
|
||||
GeneratedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getTenantByUser 根据用户获取租户信息
|
||||
func (s *cidService) getTenantByUser(ctx context.Context, userId int64) (*types.Tenant, error) {
|
||||
// 通过common模块获取用户信息,包含租户ID
|
||||
userInfo, err := utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "获取用户信息失败")
|
||||
}
|
||||
|
||||
// 租户ID从用户信息中获取
|
||||
tenantId := gconv.Int64(userInfo.TenantId)
|
||||
if tenantId == 0 {
|
||||
tenantId = 1 // 默认租户ID
|
||||
}
|
||||
|
||||
// 租户级别和名称可以根据租户ID通过其他方式获取或配置
|
||||
// 这里使用映射配置,实际项目中可能需要调用其他服务
|
||||
tenantName := "默认租户"
|
||||
tenantLevel := "basic"
|
||||
tenantStatus := "active"
|
||||
|
||||
// 根据租户ID设置不同的级别(示例逻辑)
|
||||
switch tenantId {
|
||||
case 1:
|
||||
tenantName = "基础租户"
|
||||
tenantLevel = "basic"
|
||||
case 2:
|
||||
tenantName = "标准租户"
|
||||
tenantLevel = "standard"
|
||||
case 3:
|
||||
tenantName = "高级租户"
|
||||
tenantLevel = "premium"
|
||||
}
|
||||
|
||||
return &types.Tenant{
|
||||
Id: tenantId,
|
||||
Name: tenantName,
|
||||
Level: tenantLevel,
|
||||
Status: tenantStatus,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// matchAds 根据策略匹配广告
|
||||
func (s *cidService) matchAds(ctx context.Context, req *dto.GenerateCIDReq, strategy *AdMatchingStrategy) ([]*dto.AdInfo, error) {
|
||||
var matchedAds []*dto.AdInfo
|
||||
|
||||
// 根据策略权重从不同源获取广告
|
||||
for source, weight := range strategy.SourceWeight {
|
||||
if weight <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
sourceAds, err := s.getAdsFromSource(ctx, source, req, strategy, weight)
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "从广告源 %s 获取广告失败: %v", source, err)
|
||||
continue
|
||||
}
|
||||
|
||||
matchedAds = append(matchedAds, sourceAds...)
|
||||
}
|
||||
|
||||
// 过滤符合转化率要求的广告
|
||||
var filteredAds []*dto.AdInfo
|
||||
for _, ad := range matchedAds {
|
||||
if ad.ConversionRate >= strategy.MinConversion && ad.ConversionRate <= strategy.MaxConversion {
|
||||
filteredAds = append(filteredAds, ad)
|
||||
}
|
||||
}
|
||||
|
||||
// 限制广告数量
|
||||
if len(filteredAds) > strategy.MaxAdsPerRequest {
|
||||
rand.Shuffle(len(filteredAds), func(i, j int) {
|
||||
filteredAds[i], filteredAds[j] = filteredAds[j], filteredAds[i]
|
||||
})
|
||||
filteredAds = filteredAds[:strategy.MaxAdsPerRequest]
|
||||
}
|
||||
|
||||
return filteredAds, nil
|
||||
}
|
||||
|
||||
// getAdsFromSource 从指定广告源获取广告
|
||||
func (s *cidService) getAdsFromSource(ctx context.Context, source string, req *dto.GenerateCIDReq, strategy *AdMatchingStrategy, weight int) ([]*dto.AdInfo, error) {
|
||||
switch source {
|
||||
case "self":
|
||||
return s.getSelfServiceAds(ctx, req, weight)
|
||||
case "google":
|
||||
return s.getGoogleAds(ctx, req, weight)
|
||||
case "facebook":
|
||||
return s.getFacebookAds(ctx, req, weight)
|
||||
default:
|
||||
return nil, gerror.Newf("不支持的广告源: %s", source)
|
||||
}
|
||||
}
|
||||
|
||||
// getSelfServiceAds 获取自营广告
|
||||
func (s *cidService) getSelfServiceAds(ctx context.Context, req *dto.GenerateCIDReq, count int) ([]*dto.AdInfo, error) {
|
||||
// 这里应该从数据库查询自营广告
|
||||
// 暂时返回模拟数据
|
||||
ads := make([]*dto.AdInfo, 0)
|
||||
for i := 0; i < count; i++ {
|
||||
ads = append(ads, &dto.AdInfo{
|
||||
Id: int64(rand.Intn(89999) + 10000),
|
||||
Title: fmt.Sprintf("自营广告 %d", i+1),
|
||||
Description: "这是一个高质量的自营广告",
|
||||
ImageUrl: "https://example.com/ad.jpg",
|
||||
TargetUrl: "https://example.com/landing",
|
||||
ConversionRate: rand.Float64(),
|
||||
Source: "self",
|
||||
Bid: rand.Intn(901) + 100,
|
||||
})
|
||||
}
|
||||
return ads, nil
|
||||
}
|
||||
|
||||
// getGoogleAds 获取Google广告
|
||||
func (s *cidService) getGoogleAds(ctx context.Context, req *dto.GenerateCIDReq, count int) ([]*dto.AdInfo, error) {
|
||||
// 这里应该调用Google Ads API
|
||||
// 暂时返回模拟数据
|
||||
ads := make([]*dto.AdInfo, 0)
|
||||
for i := 0; i < count; i++ {
|
||||
ads = append(ads, &dto.AdInfo{
|
||||
Id: int64(rand.Intn(9999) + 20000),
|
||||
Title: fmt.Sprintf("Google广告 %d", i+1),
|
||||
Description: "来自Google的高质量广告",
|
||||
ImageUrl: "https://google.com/ad.jpg",
|
||||
TargetUrl: "https://google.com/landing",
|
||||
ConversionRate: rand.Float64()*0.3 + 0.1,
|
||||
Source: "google",
|
||||
Bid: rand.Intn(1301) + 200,
|
||||
})
|
||||
}
|
||||
return ads, nil
|
||||
}
|
||||
|
||||
// getFacebookAds 获取Facebook广告
|
||||
func (s *cidService) getFacebookAds(ctx context.Context, req *dto.GenerateCIDReq, count int) ([]*dto.AdInfo, error) {
|
||||
// 这里应该调用Facebook Ads API
|
||||
// 暂时返回模拟数据
|
||||
ads := make([]*dto.AdInfo, 0)
|
||||
for i := 0; i < count; i++ {
|
||||
ads = append(ads, &dto.AdInfo{
|
||||
Id: int64(rand.Intn(9999) + 30000),
|
||||
Title: fmt.Sprintf("Facebook广告 %d", i+1),
|
||||
Description: "来自Facebook的高质量广告",
|
||||
ImageUrl: "https://facebook.com/ad.jpg",
|
||||
TargetUrl: "https://facebook.com/landing",
|
||||
ConversionRate: rand.Float64()*0.25 + 0.08,
|
||||
Source: "facebook",
|
||||
Bid: rand.Intn(1051) + 150,
|
||||
})
|
||||
}
|
||||
return ads, nil
|
||||
}
|
||||
|
||||
// generateUniqueCID 生成唯一CID
|
||||
func (s *cidService) generateUniqueCID() string {
|
||||
timestamp := time.Now().Unix()
|
||||
random := rand.Intn(8999) + 1000
|
||||
return fmt.Sprintf("CID_%d_%d", timestamp, random)
|
||||
}
|
||||
|
||||
// recordCIDRequest 记录CID请求
|
||||
func (s *cidService) recordCIDRequest(ctx context.Context, req *dto.GenerateCIDReq, tenant *types.Tenant, ads []*dto.AdInfo) {
|
||||
// 转换dto.AdInfo到entity.Ad
|
||||
var entityAds []entity.Ad
|
||||
for _, ad := range ads {
|
||||
entityAds = append(entityAds, entity.Ad{
|
||||
ID: fmt.Sprintf("%d", ad.Id),
|
||||
AdSource: ad.Source,
|
||||
Title: ad.Title,
|
||||
Description: ad.Description,
|
||||
CreativeURL: ad.ImageUrl,
|
||||
LandingURL: ad.TargetUrl,
|
||||
BidAmount: int64(ad.Bid),
|
||||
})
|
||||
}
|
||||
|
||||
request := &entity.CidRequest{
|
||||
RequestID: fmt.Sprintf("REQ_%d_%d", time.Now().Unix(), rand.Intn(10000)),
|
||||
UserID: fmt.Sprintf("%d", req.UserId),
|
||||
TenantID: fmt.Sprintf("%d", tenant.Id),
|
||||
Response: &entity.CidResponse{
|
||||
Ads: entityAds,
|
||||
},
|
||||
ProcessingTime: int64(rand.Intn(401) + 100), // 模拟处理时间
|
||||
}
|
||||
|
||||
dao.CIDRequest.Create(ctx, request)
|
||||
}
|
||||
|
||||
// GetCIDStatistics 获取CID统计信息
|
||||
func (s *cidService) GetCIDStatistics(ctx context.Context, req *dto.GetCIDStatisticsReq) (res *dto.GetCIDStatisticsRes, err error) {
|
||||
// 这里应该实现真实的统计逻辑
|
||||
// 暂时返回模拟数据
|
||||
return &dto.GetCIDStatisticsRes{
|
||||
TotalRequests: int64(rand.Intn(9000) + 1000),
|
||||
SuccessfulReq: int64(rand.Intn(8100) + 900),
|
||||
AverageProcessTime: rand.Float64()*200 + 50,
|
||||
TopSources: []string{"self", "google", "facebook"},
|
||||
ConversionStats: map[string]float64{
|
||||
"self": rand.Float64() * 0.1,
|
||||
"google": rand.Float64() * 0.2,
|
||||
"facebook": rand.Float64() * 0.15,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetCIDHistory 获取CID请求历史
|
||||
func (s *cidService) GetCIDHistory(ctx context.Context, userId int64, page, size int) (res *dto.GetCIDHistoryRes, err error) {
|
||||
history, total, err := dao.CIDRequest.GetHistory(ctx, userId, page, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var historyList []*dto.CIDRequestHistory
|
||||
for _, record := range history {
|
||||
// 解析TenantID
|
||||
tenantId := int64(0)
|
||||
if record.TenantID != "" {
|
||||
tenantId, _ = strconv.ParseInt(record.TenantID, 10, 64)
|
||||
}
|
||||
|
||||
// 解析UserID
|
||||
uid := int64(0)
|
||||
if record.UserID != "" {
|
||||
uid, _ = strconv.ParseInt(record.UserID, 10, 64)
|
||||
}
|
||||
|
||||
historyList = append(historyList, &dto.CIDRequestHistory{
|
||||
Id: 0, // 使用默认值,因为entity使用的是ObjectID
|
||||
TenantId: tenantId,
|
||||
UserId: uid,
|
||||
RequestType: "CID", // 默认值
|
||||
Status: "completed", // 从response状态获取
|
||||
ProcessTime: int(record.ProcessingTime),
|
||||
CreatedAt: record.CreatedAt.String(),
|
||||
})
|
||||
}
|
||||
|
||||
return &dto.GetCIDHistoryRes{
|
||||
List: historyList,
|
||||
Total: total,
|
||||
Page: page,
|
||||
Size: size,
|
||||
}, nil
|
||||
}
|
||||
238
service/strategy_service.go
Normal file
238
service/strategy_service.go
Normal file
@@ -0,0 +1,238 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/utils"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
var (
|
||||
Strategy = strategyService{}
|
||||
)
|
||||
|
||||
type strategyService struct{}
|
||||
|
||||
// CreateStrategy 创建策略
|
||||
func (s *strategyService) CreateStrategy(ctx context.Context, req *dto.CreateStrategyReq) (id int64, err error) {
|
||||
// 检查策略名称是否已存在
|
||||
existingStrategy, err := dao.Strategy.GetByName(ctx, req.Name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingStrategy != nil {
|
||||
return 0, gerror.New("策略名称已存在")
|
||||
}
|
||||
|
||||
// 验证转化率范围
|
||||
if req.MaxConversion <= req.MinConversion {
|
||||
return 0, gerror.New("最高转化率必须大于最低转化率")
|
||||
}
|
||||
|
||||
// 序列化权重配置
|
||||
weightsJson, err := json.Marshal(req.SourceWeights)
|
||||
if err != nil {
|
||||
return 0, gerror.Wrap(err, "权重配置序列化失败")
|
||||
}
|
||||
|
||||
// 获取当前用户信息
|
||||
userInfo, err := utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return 0, gerror.Wrap(err, "获取用户信息失败")
|
||||
}
|
||||
|
||||
// 将UserName转换为int64,如果失败则使用0
|
||||
var userId int64
|
||||
if uid, ok := userInfo.UserName.(string); ok {
|
||||
if parsedId, err := strconv.ParseInt(uid, 10, 64); err == nil {
|
||||
userId = parsedId
|
||||
}
|
||||
}
|
||||
|
||||
strategy := &entity.Strategy{
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
TenantLevel: req.TenantLevel,
|
||||
MinConversion: req.MinConversion,
|
||||
MaxConversion: req.MaxConversion,
|
||||
SourceWeights: string(weightsJson),
|
||||
MaxAdsPerReq: req.MaxAdsPerReq,
|
||||
Priority: req.Priority,
|
||||
Status: req.Status,
|
||||
CreatedBy: userId,
|
||||
UpdatedBy: userId,
|
||||
}
|
||||
|
||||
return dao.Strategy.Create(ctx, strategy)
|
||||
}
|
||||
|
||||
// UpdateStrategy 更新策略
|
||||
func (s *strategyService) UpdateStrategy(ctx context.Context, req *dto.UpdateStrategyReq) (affected int64, err error) {
|
||||
// 检查策略是否存在
|
||||
existingStrategy, err := dao.Strategy.GetByID(ctx, req.Id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingStrategy == nil {
|
||||
return 0, gerror.New("策略不存在")
|
||||
}
|
||||
|
||||
// 如果更新名称,检查是否与其他策略冲突
|
||||
if req.Name != "" && req.Name != existingStrategy.Name {
|
||||
conflictStrategy, err := dao.Strategy.GetByName(ctx, req.Name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if conflictStrategy != nil {
|
||||
return 0, gerror.New("策略名称已存在")
|
||||
}
|
||||
}
|
||||
|
||||
// 验证转化率范围
|
||||
if req.MaxConversion <= req.MinConversion {
|
||||
return 0, gerror.New("最高转化率必须大于最低转化率")
|
||||
}
|
||||
|
||||
// 序列化权重配置
|
||||
weightsJson, err := json.Marshal(req.SourceWeights)
|
||||
if err != nil {
|
||||
return 0, gerror.Wrap(err, "权重配置序列化失败")
|
||||
}
|
||||
|
||||
// 获取当前用户信息
|
||||
userInfo, err := utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return 0, gerror.Wrap(err, "获取用户信息失败")
|
||||
}
|
||||
|
||||
// 将UserName转换为int64,如果失败则使用0
|
||||
var userId int64
|
||||
if uid, ok := userInfo.UserName.(string); ok {
|
||||
if parsedId, err := strconv.ParseInt(uid, 10, 64); err == nil {
|
||||
userId = parsedId
|
||||
}
|
||||
}
|
||||
|
||||
strategy := &entity.Strategy{
|
||||
Id: req.Id,
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
TenantLevel: req.TenantLevel,
|
||||
MinConversion: req.MinConversion,
|
||||
MaxConversion: req.MaxConversion,
|
||||
SourceWeights: string(weightsJson),
|
||||
MaxAdsPerReq: req.MaxAdsPerReq,
|
||||
Priority: req.Priority,
|
||||
Status: req.Status,
|
||||
UpdatedBy: userId,
|
||||
}
|
||||
|
||||
return dao.Strategy.Update(ctx, strategy)
|
||||
}
|
||||
|
||||
// DeleteStrategy 删除策略
|
||||
func (s *strategyService) DeleteStrategy(ctx context.Context, id int64) (affected int64, err error) {
|
||||
// 检查策略是否存在
|
||||
existingStrategy, err := dao.Strategy.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingStrategy == nil {
|
||||
return 0, gerror.New("策略不存在")
|
||||
}
|
||||
|
||||
return dao.Strategy.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// GetStrategyByID 根据ID获取策略
|
||||
func (s *strategyService) GetStrategyByID(ctx context.Context, id int64) (strategy *dto.StrategyRes, err error) {
|
||||
entity, err := dao.Strategy.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if entity == nil {
|
||||
return nil, gerror.New("策略不存在")
|
||||
}
|
||||
|
||||
// 反序列化权重配置
|
||||
var weights map[string]int
|
||||
if entity.SourceWeights != "" {
|
||||
err = json.Unmarshal([]byte(entity.SourceWeights), &weights)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "权重配置反序列化失败")
|
||||
}
|
||||
}
|
||||
|
||||
return &dto.StrategyRes{
|
||||
Id: entity.Id,
|
||||
Name: entity.Name,
|
||||
Description: entity.Description,
|
||||
TenantLevel: entity.TenantLevel,
|
||||
MinConversion: entity.MinConversion,
|
||||
MaxConversion: entity.MaxConversion,
|
||||
SourceWeights: weights,
|
||||
MaxAdsPerReq: entity.MaxAdsPerReq,
|
||||
Priority: entity.Priority,
|
||||
Status: entity.Status,
|
||||
CreatedAt: entity.CreatedAt.String(),
|
||||
UpdatedAt: entity.UpdatedAt.String(),
|
||||
CreatedBy: entity.CreatedBy,
|
||||
UpdatedBy: entity.UpdatedBy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetStrategyList 获取策略列表
|
||||
func (s *strategyService) GetStrategyList(ctx context.Context, req *dto.GetStrategyListReq) (res *dto.GetStrategyListRes, err error) {
|
||||
list, total, err := dao.Strategy.GetList(ctx, req.Page, req.Size, req.TenantLevel, req.Status)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var strategyList []*dto.StrategyRes
|
||||
for _, entity := range list {
|
||||
// 反序列化权重配置
|
||||
var weights map[string]int
|
||||
if entity.SourceWeights != "" {
|
||||
err = json.Unmarshal([]byte(entity.SourceWeights), &weights)
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "策略 %d 权重配置反序列化失败: %v", entity.Id, err)
|
||||
weights = make(map[string]int)
|
||||
}
|
||||
}
|
||||
|
||||
strategyList = append(strategyList, &dto.StrategyRes{
|
||||
Id: entity.Id,
|
||||
Name: entity.Name,
|
||||
Description: entity.Description,
|
||||
TenantLevel: entity.TenantLevel,
|
||||
MinConversion: entity.MinConversion,
|
||||
MaxConversion: entity.MaxConversion,
|
||||
SourceWeights: weights,
|
||||
MaxAdsPerReq: entity.MaxAdsPerReq,
|
||||
Priority: entity.Priority,
|
||||
Status: entity.Status,
|
||||
CreatedAt: entity.CreatedAt.String(),
|
||||
UpdatedAt: entity.UpdatedAt.String(),
|
||||
CreatedBy: entity.CreatedBy,
|
||||
UpdatedBy: entity.UpdatedBy,
|
||||
})
|
||||
}
|
||||
|
||||
return &dto.GetStrategyListRes{
|
||||
List: strategyList,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetStrategyByTenantLevel 根据租户级别获取策略
|
||||
func (s *strategyService) GetStrategyByTenantLevel(ctx context.Context, tenantLevel string) (strategy *entity.Strategy, err error) {
|
||||
return dao.Strategy.GetByTenantLevel(ctx, tenantLevel)
|
||||
}
|
||||
Reference in New Issue
Block a user