初始化项目

This commit is contained in:
2025-12-06 10:38:48 +08:00
parent c9fcfc761e
commit 88a2753211
20 changed files with 2552 additions and 74 deletions

261
README.md
View File

@@ -1,99 +1,212 @@
# CID广告管理系统
# CID服务商项目
## 项目简介
## 项目概述
CID广告管理系统是一个完整的广告投放和管理平台,支持广告主管理、广告管理、广告位管理和数据统计分析等功能
CID服务商项目是一个为企业提供CIDClick ID服务的完整解决方案。该项目通过智能策略引擎为不同级别的租户提供定制化的广告匹配服务支持多广告源集成和转化率控制
## 功能模块
## 核心功能
### 1. 广告管理
- 广告创建、编辑、删除
- 广告审核流程
- 广告状态管理
- 广告投放设置
- 广告定向设置
- 广告统计数据
### 1. 租户管理系统
- **多租户架构**: 支持多个企业租户同时使用
- **租户级别**: Basic、Standard、Premium三个级别
- **用户认证集成**: 通过common模块获取用户信息
### 2. 广告管理
- 广告主注册、审核
- 广告主信息维护
- 广告主账户管理
- 充值和授信额度管理
- 广告主状态管理
### 2. 广告管理
- **自营广告**: 系统内置的广告库存
- **Google Ads**: 集成Google广告平台
- **Facebook Ads**: 集成Meta广告平台
- **扩展性**: 支持添加更多广告源
### 3. 广告位管理
- 广告位创建、编辑
- 广告位状态管理
- 广告位定价设置
- 广告位展示规则
- 广告位统计数据
### 3. 智能策略引擎
- **转化率控制**: 根据租户级别设置不同转化率范围
- **权重分配**: 为不同广告源配置权重比例
- **动态匹配**: 实时根据策略匹配最优广告
### 4. 广告统计与报表
- 广告效果统计
- 数据可视化仪表盘
- 自定义报表生成
- 报表导出功能
- 数据趋势分析
### 4. CID生成与追踪
- **唯一CID**: 为每次请求生成唯一标识
- **请求记录**: 完整的请求历史记录
- **性能统计**: 详细的性能和转化统计
### 5. 广告匹配与投放
- 基于用户画像的广告匹配
- 实时广告投放
- 广告频次控制
- 广告预算控制
## API接口
## 技术架构
### 租户管理
- `POST /tenant/create` - 创建租户
- `PUT /tenant/update` - 更新租户
- `DELETE /tenant/delete` - 删除租户
- `GET /tenant/info` - 获取租户信息
- `GET /tenant/list` - 获取租户列表
### 技术栈
- Go语言 + GoFrame框架
- MongoDB 数据库
- Redis 缓存
- RESTful API设计
### 广告源管理
- `POST /ad-source/create` - 创建广告源
- `PUT /ad-source/update` - 更新广告源
- `DELETE /ad-source/delete` - 删除广告源
- `GET /ad-source/info` - 获取广告源信息
- `GET /ad-source/list` - 获取广告源列表
### 策略管理
- `POST /strategy/create` - 创建策略
- `PUT /strategy/update` - 更新策略
- `DELETE /strategy/delete` - 删除策略
- `GET /strategy/info` - 获取策略信息
- `GET /strategy/list` - 获取策略列表
### CID核心服务
- `POST /cid/generate` - 生成CID广告
- `GET /cid/statistics` - 获取CID统计
- `GET /cid/history` - 获取CID历史记录
## 租户级别策略
### Basic级别
- 转化率范围: 1% - 5%
- 广告源: 仅自营广告
- 每次请求: 最多3个广告
### Standard级别
- 转化率范围: 5% - 15%
- 广告源: 自营(70%) + Google(20%) + Facebook(10%)
- 每次请求: 最多5个广告
### Premium级别
- 转化率范围: 15% - 100%
- 广告源: 自营(40%) + Google(30%) + Facebook(30%)
- 每次请求: 最多10个广告
## 项目结构
### 项目结构
```
cidservice/
├── consts/ # 常量定义
├── controller/ # 控制器层
│ ├── advertisement_controller.go
│ ├── advertiser_controller.go
│ ├── ad_position_controller.go
│ └── ad_statistics_controller.go
├── dao/ # 数据访问
│ ├── advertisement_dao.go
│ ├── advertiser_dao.go
│ ├── ad_position_dao.go
│ └── ad_statistics_dao.go
├── model/ # 模型定义
│ ├── dto/ # 数据传输对象
── entity/ # 实体对象
└── service/ # 服务层
── advertisement_service.go
├── advertiser_service.go
├── ad_position_service.go
── ad_statistics_service.go
│ ├── cid_controller.go
│ ├── ad_source_controller.go
│ ├── strategy_controller.go
│ └── ...
├── service/ # 服务
│ ├── cid_service.go
│ ├── ad_source_service.go
│ ├── strategy_service.go
│ └── ...
├── dao/ # 数据访问层
│ ├── cid_request_dao.go
── ad_source_dao.go
│ ├── strategy_dao.go
── ...
├── model/ # 数据模型
├── entity/ # 数据库实体
── dto/ # 数据传输对象
│ └── types/ # 类型定义
├── database/ # 数据库脚本
│ └── init.sql # 数据库初始化
├── config/ # 配置文件
│ └── config.example.yaml
└── README.md
```
## 架构说明
### 租户管理
- 租户信息不在当前项目中维护
- 通过common模块获取用户和租户信息
- 支持Basic、Standard、Premium三个级别的租户
### 广告源集成
- **自营广告**: 系统内置广告库存
- **Google Ads**: API集成
- **Facebook Ads**: API集成
- 可扩展支持更多广告源
### 策略引擎
- 基于租户级别的动态策略匹配
- 支持转化率阈值控制
- 灵活的广告源权重配置
## 使用示例
### 1. 生成CID广告
```json
POST /cid/generate
{
"request_type": "web_banner",
"position": "header",
"count": 5
}
Response:
{
"cid": "CID_1640995200000_1234",
"ads": [
{
"id": 10001,
"title": "优质产品推广",
"description": "高质量的产品广告",
"image_url": "https://example.com/ad.jpg",
"target_url": "https://example.com/product",
"conversion_rate": 0.08,
"source": "self",
"bid": 500
}
],
"total_ads": 1,
"tenant_id": 1,
"tenant_name": "示例公司",
"generated_at": "2023-12-31 16:00:00"
}
```
### 2. 创建策略
```json
POST /strategy/create
{
"name": "高级策略",
"description": "高级租户专用策略",
"tenant_level": "premium",
"min_conversion": 0.15,
"max_conversion": 1.0,
"source_weights": {
"self": 40,
"google": 30,
"facebook": 30
},
"max_ads_per_req": 10,
"priority": 100,
"status": "active"
}
```
## 部署说明
1. 配置MongoDB和Redis连接
2. 修改config.yml配置文件
3. 执行`go run main.go`启动服务
4. 服务默认运行在3002端口
1. 确保数据库连接配置正确
2. 执行数据库迁移脚本
3. 配置广告源API密钥
4. 启动服务
## API文档
## 扩展功能
API文档可以通过Swagger或Postman查看主要接口包括
### 添加新的广告源
1.`AdSource`表中添加新的广告源配置
2.`cid_service.go`中实现对应的广告获取方法
3. 在策略中配置相应权重
- 广告管理:/advertisement/add, /advertisement/update, /advertisement/list等
- 广告主管理:/advertiser/add, /advertiser/update, /advertiser/list等
- 广告位管理:/adposition/add, /adposition/update, /adposition/list等
- 广告统计:/statistics/list, /dashboard等
- 报表管理:/report/create, /report/list, /report/download等
### 自定义策略
通过策略管理API创建自定义匹配策略支持
- 自定义转化率阈值
- 灵活的权重分配
- 动态优先级调整
## 开发规范
## 监控与统计
项目遵循原customerservice项目的开发规范包括分层架构、命名规范和错误处理等。
系统提供完整的监控和统计功能:
- 请求量统计
- 成功率分析
- 处理时间监控
- 转化率追踪
- 广告源性能对比
## 扩展说明
## 安全特性
系统支持水平扩展可以通过增加广告服务实例来提高处理能力Redis用于缓存和队列MongoDB用于数据持久化。
- 用户身份验证
- 租户数据隔离
- API访问控制
- 敏感信息加密
这个CID服务商项目为企业提供了一个完整、可扩展的广告CID解决方案通过智能策略确保每个租户都能获得最适合其业务需求的广告服务。

BIN
cidService Executable file

Binary file not shown.

View File

@@ -0,0 +1,86 @@
# CID服务商项目配置文件示例
# 服务器配置
server:
address: ":8080"
dumpRouterMap: false
# 数据库配置
database:
default:
type: "mysql"
host: "localhost"
port: "3306"
user: "root"
pass: ""
name: "cid_service"
charset: "utf8mb4"
timezone: "Local"
maxIdle: 10
maxOpen: 100
maxLifetime: 30
# Redis配置
redis:
default:
address: "127.0.0.1:6379"
db: 1
pass: ""
# JWT配置
jwt:
secret: "your-secret-key"
expire: 7200 # 2小时
# 日志配置
logger:
level: "info"
stdout: true
path: "./logs"
file: "cid-service.log"
# 广告源配置
ad_sources:
google:
api_key: "your-google-ads-api-key"
customer_id: "your-customer-id"
developer_token: "your-developer-token"
facebook:
app_id: "your-facebook-app-id"
app_secret: "your-facebook-app-secret"
access_token: "your-facebook-access-token"
ad_account_id: "your-ad-account-id"
# 策略配置
strategy:
default:
basic:
min_conversion: 0.01
max_conversion: 0.05
source_weights:
self: 100
google: 0
facebook: 0
max_ads_per_req: 3
standard:
min_conversion: 0.05
max_conversion: 0.15
source_weights:
self: 70
google: 20
facebook: 10
max_ads_per_req: 5
premium:
min_conversion: 0.15
max_conversion: 1.0
source_weights:
self: 40
google: 30
facebook: 30
max_ads_per_req: 10
# 监控配置
monitoring:
enable_metrics: true
enable_tracing: true
jaeger_endpoint: "http://localhost:14268/api/traces"

View File

@@ -0,0 +1,111 @@
package controller
import (
"context"
"strconv"
"cidService/model/dto"
"cidService/service"
"github.com/gogf/gf/v2/errors/gerror"
)
var (
AdSource = cAdSource{}
)
type cAdSource struct{}
// Create 创建广告源
func (c *cAdSource) Create(ctx context.Context, req *dto.CreateAdSourceReq) (res *dto.GetAdSourceRes, err error) {
id, err := service.AdSource.CreateAdSource(ctx, req)
if err != nil {
return nil, err
}
adSource, err := service.AdSource.GetAdSourceByID(ctx, id)
if err != nil {
return nil, err
}
return &dto.GetAdSourceRes{
AdSource: adSource,
}, nil
}
// Update 更新广告源
func (c *cAdSource) Update(ctx context.Context, req *dto.UpdateAdSourceReq) (res *dto.GetAdSourceRes, err error) {
id, err := strconv.ParseInt(req.Id, 10, 64)
if err != nil {
return nil, gerror.New("无效的广告源ID")
}
affected, err := service.AdSource.UpdateAdSource(ctx, id, req)
if err != nil {
return nil, err
}
if affected == 0 {
return nil, gerror.New("广告源更新失败")
}
adSource, err := service.AdSource.GetAdSourceByID(ctx, id)
if err != nil {
return nil, err
}
return &dto.GetAdSourceRes{
AdSource: adSource,
}, nil
}
// Delete 删除广告源
func (c *cAdSource) Delete(ctx context.Context, req *dto.DeleteAdSourceReq) (res *dto.DeleteAdSourceRes, err error) {
id, err := strconv.ParseInt(req.Id, 10, 64)
if err != nil {
return nil, gerror.New("无效的广告源ID")
}
affected, err := service.AdSource.DeleteAdSource(ctx, id)
if err != nil {
return nil, err
}
if affected == 0 {
return nil, gerror.New("广告源删除失败")
}
return &dto.DeleteAdSourceRes{
Success: true,
}, nil
}
// GetByID 根据ID获取广告源
func (c *cAdSource) GetByID(ctx context.Context, req *dto.GetAdSourceReq) (res *dto.GetAdSourceRes, err error) {
id, err := strconv.ParseInt(req.Id, 10, 64)
if err != nil {
return nil, gerror.New("无效的广告源ID")
}
adSource, err := service.AdSource.GetAdSourceByID(ctx, id)
if err != nil {
return nil, err
}
if adSource == nil {
return nil, gerror.New("广告源不存在")
}
return &dto.GetAdSourceRes{
AdSource: adSource,
}, nil
}
// GetList 获取广告源列表
func (c *cAdSource) GetList(ctx context.Context, req *dto.ListAdSourceReq) (res *dto.ListAdSourceRes, err error) {
adSources, err := service.AdSource.GetAvailableSources(ctx)
if err != nil {
return nil, err
}
return &dto.ListAdSourceRes{
List: adSources,
Total: len(adSources),
}, nil
}

View File

@@ -0,0 +1,62 @@
package controller
import (
"context"
"cidService/model/dto"
"cidService/service"
"github.com/gogf/gf/v2/errors/gerror"
)
var (
CID = cCID{}
)
type cCID struct{}
// GenerateCID 生成CID广告
func (c *cCID) GenerateCID(ctx context.Context, req *dto.GenerateCIDReq) (res *dto.GenerateCIDRes, err error) {
if req == nil {
return nil, gerror.New("请求参数不能为空")
}
if req.RequestType == "" {
req.RequestType = "default" // 默认请求类型
}
result, err := service.CID.GenerateCID(ctx, req)
if err != nil {
return nil, err
}
return result, nil
}
// GetStatistics 获取CID统计信息
func (c *cCID) GetStatistics(ctx context.Context, req *dto.GetCIDStatisticsReq) (res *dto.GetCIDStatisticsRes, err error) {
if req == nil {
return nil, gerror.New("请求参数不能为空")
}
result, err := service.CID.GetCIDStatistics(ctx, req)
if err != nil {
return nil, err
}
return result, nil
}
// GetCIDHistory 获取CID历史记录
func (c *cCID) GetCIDHistory(ctx context.Context, req *dto.GetCIDHistoryReq) (res *dto.GetCIDHistoryRes, err error) {
if req == nil {
return nil, gerror.New("请求参数不能为空")
}
// 查询历史记录
history, err := service.CID.GetCIDHistory(ctx, 1, req.Page, req.Size) // 临时使用固定用户ID
if err != nil {
return nil, err
}
return history, nil
}

View File

@@ -0,0 +1,78 @@
package controller
import (
"context"
"cidService/model/dto"
"cidService/service"
"github.com/gogf/gf/v2/errors/gerror"
)
var (
Strategy = cStrategy{}
)
type cStrategy struct{}
// Create 创建策略
func (c *cStrategy) Create(ctx context.Context, req *dto.CreateStrategyReq) (res *dto.StrategyRes, err error) {
id, err := service.Strategy.CreateStrategy(ctx, req)
if err != nil {
return nil, err
}
strategy, err := service.Strategy.GetStrategyByID(ctx, id)
if err != nil {
return nil, err
}
return strategy, nil
}
// Update 更新策略
func (c *cStrategy) Update(ctx context.Context, req *dto.UpdateStrategyReq) (res *dto.StrategyRes, err error) {
affected, err := service.Strategy.UpdateStrategy(ctx, req)
if err != nil {
return nil, err
}
if affected == 0 {
return nil, gerror.New("策略更新失败")
}
strategy, err := service.Strategy.GetStrategyByID(ctx, req.Id)
if err != nil {
return nil, err
}
return strategy, nil
}
// Delete 删除策略
func (c *cStrategy) Delete(ctx context.Context, req *dto.DeleteStrategyReq) (res *dto.DeleteStrategyRes, err error) {
affected, err := service.Strategy.DeleteStrategy(ctx, req.Id)
if err != nil {
return nil, err
}
if affected == 0 {
return nil, gerror.New("策略删除失败")
}
return &dto.DeleteStrategyRes{
Success: true,
}, nil
}
// GetByID 根据ID获取策略
func (c *cStrategy) GetByID(ctx context.Context, req *dto.GetStrategyReq) (res *dto.StrategyRes, err error) {
strategy, err := service.Strategy.GetStrategyByID(ctx, req.Id)
if err != nil {
return nil, err
}
return strategy, nil
}
// GetList 获取策略列表
func (c *cStrategy) GetList(ctx context.Context, req *dto.GetStrategyListReq) (res *dto.GetStrategyListRes, err error) {
return service.Strategy.GetStrategyList(ctx, req)
}

91
dao/ad_source_dao.go Normal file
View File

@@ -0,0 +1,91 @@
package dao
import (
"cidService/model/entity"
"context"
"github.com/gogf/gf/v2/frame/g"
)
var (
AdSource = adSourceDao{}
)
type adSourceDao struct{}
// GetByName 根据名称获取广告源
func (d *adSourceDao) GetByName(ctx context.Context, name string) (adSource *entity.AdSource, err error) {
err = g.DB().Model("ad_sources").
Where("name = ?", name).
Scan(&adSource)
return
}
// GetAvailableSources 获取可用的广告源
func (d *adSourceDao) GetAvailableSources(ctx context.Context) (list []*entity.AdSource, err error) {
err = g.DB().Model("ad_sources").
Where("status = ?", "active").
Order("priority DESC, created_at ASC").
Scan(&list)
return
}
// GetSourcesByProvider 根据提供商获取广告源
func (d *adSourceDao) GetSourcesByProvider(ctx context.Context, provider string) (list []*entity.AdSource, err error) {
err = g.DB().Model("ad_sources").
Where("provider = ? AND status = ?", provider, "active").
Order("priority DESC").
Scan(&list)
return
}
// Create 创建广告源
func (d *adSourceDao) Create(ctx context.Context, adSource *entity.AdSource) (id int64, err error) {
result, err := g.DB().Model("ad_sources").Insert(adSource)
if err != nil {
return 0, err
}
id, err = result.LastInsertId()
return
}
// Update 更新广告源
func (d *adSourceDao) Update(ctx context.Context, adSource *entity.AdSource) (affected int64, err error) {
result, err := g.DB().Model("ad_sources").
Where("id = ?", adSource.Id).
Update(adSource)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
// Delete 删除广告源
func (d *adSourceDao) Delete(ctx context.Context, id int64) (affected int64, err error) {
result, err := g.DB().Model("ad_sources").
Where("id = ?", id).
Delete()
if err != nil {
return 0, err
}
return result.RowsAffected()
}
// GetByID 根据ID获取广告源
func (d *adSourceDao) GetByID(ctx context.Context, id int64) (adSource *entity.AdSource, err error) {
err = g.DB().Model("ad_sources").
Where("id = ?", id).
Scan(&adSource)
return
}
// UpdateFields 更新广告源部分字段
func (d *adSourceDao) UpdateFields(ctx context.Context, id int64, data *entity.AdSource) (affected int64, err error) {
result, err := g.DB().Model("ad_sources").
Where("id = ?", id).
Update(data)
if err != nil {
return 0, err
}
return result.RowsAffected()
}

83
dao/cid_request_dao.go Normal file
View File

@@ -0,0 +1,83 @@
package dao
import (
"cidService/model/entity"
"context"
"github.com/gogf/gf/v2/frame/g"
)
var (
CIDRequest = cidRequestDao{}
)
type cidRequestDao struct{}
// Create 创建CID请求记录
func (d *cidRequestDao) Create(ctx context.Context, request *entity.CidRequest) (id int64, err error) {
result, err := g.DB().Model("cid_requests").Insert(request)
if err != nil {
return 0, err
}
id, err = result.LastInsertId()
return
}
// GetHistory 获取CID请求历史
func (d *cidRequestDao) GetHistory(ctx context.Context, userId int64, page, size int) (list []*entity.CidRequest, total int64, err error) {
model := g.DB().Model("cid_requests")
// 根据用户ID筛选
model = model.Where("user_id = ?", userId)
// 获取总数
count, err := model.Count()
if err != nil {
return
}
total = int64(count)
// 分页查询
offset := (page - 1) * size
err = model.Order("created_at DESC").
Offset(offset).
Limit(size).
Scan(&list)
return
}
// GetStatistics 获取统计信息
func (d *cidRequestDao) GetStatistics(ctx context.Context, userId int64) (stats map[string]interface{}, err error) {
stats = make(map[string]interface{})
// 总请求数
totalRequests, err := g.DB().Model("cid_requests").
Where("user_id = ?", userId).
Count()
if err != nil {
return nil, err
}
stats["total_requests"] = totalRequests
// 成功请求数
successfulRequests, err := g.DB().Model("cid_requests").
Where("user_id = ? AND status = ?", userId, "completed").
Count()
if err != nil {
return nil, err
}
stats["successful_requests"] = successfulRequests
// 平均处理时间
avgProcessTime, err := g.DB().Model("cid_requests").
Fields("AVG(process_time)").
Where("user_id = ?", userId).
Value()
if err != nil {
return nil, err
}
stats["average_process_time"] = avgProcessTime
return
}

100
dao/strategy_dao.go Normal file
View File

@@ -0,0 +1,100 @@
package dao
import (
"cidService/model/entity"
"context"
"github.com/gogf/gf/v2/frame/g"
)
var (
Strategy = strategyDao{}
)
type strategyDao struct{}
// GetByName 根据名称获取策略
func (d *strategyDao) GetByName(ctx context.Context, name string) (strategy *entity.Strategy, err error) {
err = g.DB().Model("strategies").
Where("name = ?", name).
Scan(&strategy)
return
}
// GetByID 根据ID获取策略
func (d *strategyDao) GetByID(ctx context.Context, id int64) (strategy *entity.Strategy, err error) {
err = g.DB().Model("strategies").
Where("id = ?", id).
Scan(&strategy)
return
}
// GetByTenantLevel 根据租户级别获取策略
func (d *strategyDao) GetByTenantLevel(ctx context.Context, tenantLevel string) (strategy *entity.Strategy, err error) {
err = g.DB().Model("strategies").
Where("tenant_level = ? AND status = ?", tenantLevel, "active").
Order("priority DESC, created_at ASC").
Scan(&strategy)
return
}
// Create 创建策略
func (d *strategyDao) Create(ctx context.Context, strategy *entity.Strategy) (id int64, err error) {
result, err := g.DB().Model("strategies").Insert(strategy)
if err != nil {
return 0, err
}
id, err = result.LastInsertId()
return
}
// Update 更新策略
func (d *strategyDao) Update(ctx context.Context, strategy *entity.Strategy) (affected int64, err error) {
result, err := g.DB().Model("strategies").
Where("id = ?", strategy.Id).
Update(strategy)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
// Delete 删除策略
func (d *strategyDao) Delete(ctx context.Context, id int64) (affected int64, err error) {
result, err := g.DB().Model("strategies").
Where("id = ?", id).
Delete()
if err != nil {
return 0, err
}
return result.RowsAffected()
}
// GetList 获取策略列表
func (d *strategyDao) GetList(ctx context.Context, page, size int, tenantLevel, status string) (list []*entity.Strategy, total int64, err error) {
model := g.DB().Model("strategies")
// 筛选条件
if tenantLevel != "" {
model = model.Where("tenant_level = ?", tenantLevel)
}
if status != "" {
model = model.Where("status = ?", status)
}
// 获取总数
count, err := model.Count()
if err != nil {
return
}
total = int64(count)
// 分页查询
offset := (page - 1) * size
err = model.Order("priority DESC, created_at DESC").
Offset(offset).
Limit(size).
Scan(&list)
return
}

78
database/init.sql Normal file
View File

@@ -0,0 +1,78 @@
-- CID服务商项目数据库初始化脚本
-- 广告源表
CREATE TABLE IF NOT EXISTS `ad_sources` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '广告源名称',
`provider` varchar(50) NOT NULL COMMENT '提供商: self, google, facebook, etc.',
`api_endpoint` varchar(255) DEFAULT NULL COMMENT 'API端点',
`api_key` varchar(255) DEFAULT NULL COMMENT 'API密钥',
`config` text COMMENT '配置信息(JSON格式)',
`status` varchar(20) NOT NULL DEFAULT 'active' COMMENT '状态: active, inactive',
`priority` int(11) NOT NULL DEFAULT 0 COMMENT '优先级',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`created_by` bigint(20) DEFAULT NULL COMMENT '创建人',
`updated_by` bigint(20) DEFAULT NULL COMMENT '更新人',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_ad_sources_name` (`name`),
KEY `idx_ad_sources_provider` (`provider`),
KEY `idx_ad_sources_status` (`status`),
KEY `idx_ad_sources_priority` (`priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='广告源表';
-- 策略表
CREATE TABLE IF NOT EXISTS `strategies` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '策略名称',
`description` varchar(500) DEFAULT NULL COMMENT '描述',
`tenant_level` varchar(20) NOT NULL COMMENT '适用租户级别: basic, standard, premium',
`min_conversion` decimal(5,4) NOT NULL DEFAULT 0.0000 COMMENT '最低转化率',
`max_conversion` decimal(5,4) NOT NULL DEFAULT 1.0000 COMMENT '最高转化率',
`source_weights` text COMMENT '广告源权重配置(JSON格式)',
`max_ads_per_req` int(11) NOT NULL DEFAULT 5 COMMENT '每次请求最大广告数',
`priority` int(11) NOT NULL DEFAULT 0 COMMENT '优先级',
`status` varchar(20) NOT NULL DEFAULT 'active' COMMENT '状态: active, inactive',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`created_by` bigint(20) DEFAULT NULL COMMENT '创建人',
`updated_by` bigint(20) DEFAULT NULL COMMENT '更新人',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_strategies_name` (`name`),
KEY `idx_strategies_tenant_level` (`tenant_level`),
KEY `idx_strategies_status` (`status`),
KEY `idx_strategies_priority` (`priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='匹配策略表';
-- CID请求记录表
CREATE TABLE IF NOT EXISTS `cid_requests` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`tenant_id` bigint(20) NOT NULL COMMENT '租户ID',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`request_type` varchar(50) NOT NULL COMMENT '请求类型',
`parameters` text COMMENT '请求参数(JSON格式)',
`response_data` text COMMENT '响应数据(JSON格式)',
`status` varchar(20) NOT NULL DEFAULT 'pending' COMMENT '状态: pending, completed, failed',
`process_time` int(11) DEFAULT NULL COMMENT '处理时间(毫秒)',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_cid_requests_tenant_id` (`tenant_id`),
KEY `idx_cid_requests_user_id` (`user_id`),
KEY `idx_cid_requests_status` (`status`),
KEY `idx_cid_requests_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CID请求记录表';
-- 插入默认广告源
INSERT INTO `ad_sources` (`name`, `provider`, `status`, `priority`, `created_by`, `updated_by`) VALUES
('自营广告', 'self', 'active', 100, 1, 1),
('Google Ads', 'google', 'active', 80, 1, 1),
('Facebook Ads', 'facebook', 'active', 70, 1, 1)
ON DUPLICATE KEY UPDATE `updated_at` = CURRENT_TIMESTAMP;
-- 插入默认策略
INSERT INTO `strategies` (`name`, `description`, `tenant_level`, `min_conversion`, `max_conversion`, `source_weights`, `max_ads_per_req`, `priority`, `status`, `created_by`, `updated_by`) VALUES
('基础策略', '适用于基础租户的默认策略', 'basic', 0.0100, 0.0500, '{"self": 100, "google": 0, "facebook": 0}', 3, 10, 'active', 1, 1),
('标准策略', '适用于标准租户的默认策略', 'standard', 0.0500, 0.1500, '{"self": 70, "google": 20, "facebook": 10}', 5, 20, 'active', 1, 1),
('高级策略', '适用于高级租户的默认策略', 'premium', 0.1500, 1.0000, '{"self": 40, "google": 30, "facebook": 30}', 10, 30, 'active', 1, 1)
ON DUPLICATE KEY UPDATE `updated_at` = CURRENT_TIMESTAMP;

300
model/dto/ad_source_dto.go Normal file
View File

@@ -0,0 +1,300 @@
package dto
import (
"cidService/model/entity"
"gitee.com/red-future---jilin-g/common/http"
"github.com/gogf/gf/v2/frame/g"
)
// CreateAdSourceReq 创建广告源请求
type CreateAdSourceReq struct {
g.Meta `path:"/adsource/create" method:"post" tags:"广告源管理" summary:"创建广告源" dc:"创建新的广告源配置"`
// 基本信息
Name string `json:"name" v:"required"` // 广告源名称
Code string `json:"code" v:"required"` // 广告源编码,唯一标识
Provider string `json:"provider" v:"required"` // 提供商google、facebook、baidu、tencent、self等
Type string `json:"type" v:"required|in:self,third_party,exchange"` // 类型
Description string `json:"description"` // 描述
// 连接配置
APIEndpoint string `json:"apiEndpoint" v:"required"` // API端点
APIVersion string `json:"apiVersion"` // API版本
AuthType string `json:"authType" v:"required|in:api_key,oauth,basic"` // 认证类型
AuthConfig map[string]interface{} `json:"authConfig" v:"required"` // 认证配置
Headers map[string]string `json:"headers"` // 请求头配置
Timeout int `json:"timeout"` // 超时时间(毫秒)
RetryCount int `json:"retryCount"` // 重试次数
// 基础配置
SupportedFormats []string `json:"supportedFormats" v:"required"` // 支持的广告格式
SupportedSizes []string `json:"supportedSizes"` // 支持的尺寸
SupportedDevices []string `json:"supportedDevices"` // 支持的设备类型
SupportedOS []string `json:"supportedOS"` // 支持的操作系统
SupportedCountries []string `json:"supportedCountries"` // 支持的国家/地区
// 竞价配置
BiddingType string `json:"biddingType" v:"required|in:cpm,cpc,cpa,rtb"` // 竞价类型
MinBidAmount int64 `json:"minBidAmount"` // 最小出价(分)
MaxBidAmount int64 `json:"maxBidAmount"` // 最大出价(分)
BidIncrement int64 `json:"bidIncrement"` // 出价增量(分)
DefaultBidAmount int64 `json:"defaultBidAmount"` // 默认出价(分)
AutoOptimization bool `json:"autoOptimization"` // 是否自动优化
// 最大广告数
MaxAdsPerRequest int `json:"maxAdsPerRequest"` // 单次请求最大广告数量
// 其他配置
BrandSafety bool `json:"brandSafety"` // 品牌安全
Viewability bool `json:"viewability"` // 可见性支持
RealTimeBidding bool `json:"realTimeBidding"` // 实时竞价
HeaderBidding bool `json:"headerBidding"` // 标题竞价
// 财务设置
BillingModel string `json:"billingModel" v:"required|in:cpm,cpc,cpa,rev_share"` // 计费模式
PaymentTerms string `json:"paymentTerms" v:"in:net_30,net_60,net_90"` // 支付条款
RevShareRate float64 `json:"revShareRate" v:"between:0,1"` // 收入分成比例
MinPayment int64 `json:"minPayment"` // 最小支付金额(分)
Currency string `json:"currency"` // 货币单位
TaxInclusive bool `json:"taxInclusive"` // 是否含税
// 系统信息
Priority int `json:"priority"` // 优先级
}
type CreateAdSourceRes struct {
Id string `json:"id"` // 广告源ID
}
// GetAdSourceReq 获取广告源详情请求
type GetAdSourceReq struct {
g.Meta `path:"/adsource/one" method:"get" tags:"广告源管理" summary:"获取广告源详情" dc:"根据ID获取单个广告源详情"`
Id string `json:"id" v:"required"` // 广告源ID
}
type GetAdSourceRes struct {
*entity.AdSource
}
// ListAdSourceReq 获取广告源列表请求
type ListAdSourceReq struct {
g.Meta `path:"/adsource/list" method:"get" tags:"广告源管理" summary:"获取广告源列表" dc:"分页查询广告源列表,支持多条件筛选"`
http.Page
Name string `json:"name"` // 广告源名称模糊查询
Code string `json:"code"` // 广告源编码
Provider string `json:"provider"` // 提供商
Type string `json:"type"` // 类型
Status string `json:"status"` // 状态
Health string `json:"health"` // 健康状态
}
type ListAdSourceRes struct {
List []*entity.AdSource `json:"list"`
Total int `json:"total"`
}
// UpdateAdSourceReq 更新广告源请求
type UpdateAdSourceReq struct {
g.Meta `path:"/adsource/update" method:"post" tags:"广告源管理" summary:"更新广告源" dc:"更新广告源信息"`
Id string `json:"id" v:"required"` // 广告源ID
// 基本信息
Name string `json:"name"` // 广告源名称
Description string `json:"description"` // 描述
// 连接配置
APIEndpoint string `json:"apiEndpoint"` // API端点
APIVersion string `json:"apiVersion"` // API版本
AuthType string `json:"authType"` // 认证类型
AuthConfig map[string]interface{} `json:"authConfig"` // 认证配置
Headers map[string]string `json:"headers"` // 请求头配置
Timeout int `json:"timeout"` // 超时时间(毫秒)
RetryCount int `json:"retryCount"` // 重试次数
// 基础配置
SupportedFormats []string `json:"supportedFormats"` // 支持的广告格式
SupportedSizes []string `json:"supportedSizes"` // 支持的尺寸
SupportedDevices []string `json:"supportedDevices"` // 支持的设备类型
SupportedOS []string `json:"supportedOS"` // 支持的操作系统
SupportedCountries []string `json:"supportedCountries"` // 支持的国家/地区
// 竞价配置
BiddingType string `json:"biddingType"` // 竞价类型
MinBidAmount int64 `json:"minBidAmount"` // 最小出价(分)
MaxBidAmount int64 `json:"maxBidAmount"` // 最大出价(分)
BidIncrement int64 `json:"bidIncrement"` // 出价增量(分)
DefaultBidAmount int64 `json:"defaultBidAmount"` // 默认出价(分)
AutoOptimization bool `json:"autoOptimization"` // 是否自动优化
// 最大广告数
MaxAdsPerRequest int `json:"maxAdsPerRequest"` // 单次请求最大广告数量
// 其他配置
BrandSafety bool `json:"brandSafety"` // 品牌安全
Viewability bool `json:"viewability"` // 可见性支持
RealTimeBidding bool `json:"realTimeBidding"` // 实时竞价
HeaderBidding bool `json:"headerBidding"` // 标题竞价
// 财务设置
BillingModel string `json:"billingModel"` // 计费模式
PaymentTerms string `json:"paymentTerms"` // 支付条款
RevShareRate float64 `json:"revShareRate"` // 收入分成比例
MinPayment int64 `json:"minPayment"` // 最小支付金额(分)
Currency string `json:"currency"` // 货币单位
TaxInclusive bool `json:"taxInclusive"` // 是否含税
// 系统信息
Priority int `json:"priority"` // 优先级
}
// UpdateAdSourceStatusReq 更新广告源状态请求
type UpdateAdSourceStatusReq struct {
g.Meta `path:"/adsource/status" method:"post" tags:"广告源管理" summary:"更新广告源状态" dc:"更新广告源状态"`
Id string `json:"id" v:"required"` // 广告源ID
Status string `json:"status" v:"required"` // 广告源状态active、inactive、maintenance
}
// DeleteAdSourceReq 删除广告源请求
type DeleteAdSourceReq struct {
g.Meta `path:"/adsource/delete" method:"post" tags:"广告源管理" summary:"删除广告源" dc:"删除指定的广告源"`
Id string `json:"id" v:"required"` // 广告源ID
}
// TestAdSourceReq 测试广告源连接请求
type TestAdSourceReq struct {
g.Meta `path:"/adsource/test" method:"post" tags:"广告源管理" summary:"测试广告源连接" dc:"测试广告源的连接性和可用性"`
Id string `json:"id" v:"required"` // 广告源ID
}
type TestAdSourceRes struct {
Success bool `json:"success"` // 测试是否成功
ResponseTime int64 `json:"responseTime"` // 响应时间(毫秒)
ErrorMessage string `json:"errorMessage"` // 错误信息
SupportedFormats []string `json:"supportedFormats"` // 支持的广告格式
QualityMetrics *AdSourceTestMetrics `json:"qualityMetrics"` // 质量指标
}
// DeleteAdSourceRes 删除广告源响应
type DeleteAdSourceRes struct {
Success bool `json:"success"` // 删除是否成功
}
// AdSourceTestMetrics 广告源测试质量指标
type AdSourceTestMetrics struct {
SuccessRate float64 `json:"successRate"` // 成功率
AverageResponseTime float64 `json:"averageResponseTime"` // 平均响应时间(毫秒)
FillRate float64 `json:"fillRate"` // 填充率
CTR float64 `json:"ctr"` // 点击率
}
// GetAdSourceStatisticsReq 获取广告源统计数据请求
type GetAdSourceStatisticsReq struct {
g.Meta `path:"/adsource/statistics" method:"get" tags:"广告源管理" summary:"获取广告源统计数据" dc:"获取广告源的详细统计数据"`
Id string `json:"id" v:"required"` // 广告源ID
StartDate int64 `json:"startDate" v:"required"` // 开始日期
EndDate int64 `json:"endDate" v:"required"` // 结束日期
Dimension string `json:"dimension"` // 统计维度day、week、month
}
type GetAdSourceStatisticsRes struct {
// 概览数据
Overview AdSourceOverviewStats `json:"overview"`
// 趋势数据
Trends []AdSourceTrendData `json:"trends"`
// 性能数据
Performance AdSourcePerformanceStats `json:"performance"`
// 错误统计
Errors []AdSourceErrorStats `json:"errors"`
}
// AdSourceOverviewStats 广告源概览统计
type AdSourceOverviewStats struct {
TotalRequests int64 `json:"totalRequests"` // 总请求数
SuccessfulRequests int64 `json:"successfulRequests"` // 成功请求数
FailedRequests int64 `json:"failedRequests"` // 失败请求数
TotalImpressions int64 `json:"totalImpressions"` // 总展示次数
TotalClicks int64 `json:"totalClicks"` // 总点击次数
TotalConversions int64 `json:"totalConversions"` // 总转化次数
TotalRevenue int64 `json:"totalRevenue"` // 总收入(分)
SuccessRate float64 `json:"successRate"` // 成功率
ErrorRate float64 `json:"errorRate"` // 错误率
CTR float64 `json:"ctr"` // 点击率
CVR float64 `json:"cvr"` // 转化率
FillRate float64 `json:"fillRate"` // 填充率
eCPM int64 `json:"ecpm"` // 有效千次展示成本(分)
eCPC int64 `json:"ecpc"` // 有效点击成本(分)
AverageResponseTime float64 `json:"averageResponseTime"` // 平均响应时间(毫秒)
Uptime float64 `json:"uptime"` // 可用性(百分比)
}
// AdSourceTrendData 广告源趋势数据
type AdSourceTrendData struct {
Date int64 `json:"date"` // 日期
Requests int64 `json:"requests"` // 请求数
Impressions int64 `json:"impressions"` // 展示次数
Clicks int64 `json:"clicks"` // 点击次数
Conversions int64 `json:"conversions"` // 转化次数
Revenue int64 `json:"revenue"` // 收入(分)
SuccessRate float64 `json:"successRate"` // 成功率
ErrorRate float64 `json:"errorRate"` // 错误率
CTR float64 `json:"ctr"` // 点击率
CVR float64 `json:"cvr"` // 转化率
FillRate float64 `json:"fillRate"` // 填充率
eCPM int64 `json:"ecpm"` // 有效千次展示成本(分)
ResponseTime float64 `json:"responseTime"` // 平均响应时间(毫秒)
}
// AdSourcePerformanceStats 广告源性能统计
type AdSourcePerformanceStats struct {
// 响应时间分布
ResponseTimeDistribution map[string]int64 `json:"responseTimeDistribution"` // 响应时间分布
// 错误类型统计
ErrorTypes map[string]int64 `json:"errorTypes"` // 错误类型统计
// 地区性能
RegionalPerformance map[string]AdSourceRegionalStats `json:"regionalPerformance"` // 地区性能
// 设备性能
DevicePerformance map[string]AdSourceDeviceStats `json:"devicePerformance"` // 设备性能
}
// AdSourceErrorStats 广告源错误统计
type AdSourceErrorStats struct {
ErrorType string `json:"errorType"` // 错误类型
Count int64 `json:"count"` // 错误次数
Percentage float64 `json:"percentage"` // 占比
LastOccurred int64 `json:"lastOccurred"` // 最后发生时间
}
// AdSourceRegionalStats 广告源地区统计
type AdSourceRegionalStats struct {
Region string `json:"region"` // 地区
Requests int64 `json:"requests"` // 请求数
Impressions int64 `json:"impressions"` // 展示次数
Clicks int64 `json:"clicks"` // 点击次数
Revenue int64 `json:"revenue"` // 收入(分)
CTR float64 `json:"ctr"` // 点击率
ResponseTime float64 `json:"responseTime"` // 平均响应时间(毫秒)
}
// AdSourceDeviceStats 广告源设备统计
type AdSourceDeviceStats struct {
Device string `json:"device"` // 设备类型
Requests int64 `json:"requests"` // 请求数
Impressions int64 `json:"impressions"` // 展示次数
Clicks int64 `json:"clicks"` // 点击次数
Revenue int64 `json:"revenue"` // 收入(分)
CTR float64 `json:"ctr"` // 点击率
ResponseTime float64 `json:"responseTime"` // 平均响应时间(毫秒)
}

81
model/dto/cid_dto.go Normal file
View File

@@ -0,0 +1,81 @@
package dto
import (
"github.com/gogf/gf/v2/frame/g"
)
// GenerateCIDReq 生成CID请求
type GenerateCIDReq struct {
g.Meta `path:"/cid/generate" method:"post" tags:"CID服务" summary:"生成CID广告" dc:"为当前用户生成CID广告"`
UserId int64 `json:"user_id"` // 用户ID可选如果不提供则从token获取
RequestType string `json:"request_type"` // 请求类型
Parameters map[string]interface{} `json:"parameters"` // 请求参数
Position string `json:"position"` // 广告位置
Count int `json:"count"` // 广告数量
}
// AdInfo 广告信息
type AdInfo struct {
Id int64 `json:"id"` // 广告ID
Title string `json:"title"` // 广告标题
Description string `json:"description"` // 广告描述
ImageUrl string `json:"image_url"` // 广告图片URL
TargetUrl string `json:"target_url"` // 目标链接
ConversionRate float64 `json:"conversion_rate"` // 转化率
Source string `json:"source"` // 广告源
Bid int `json:"bid"` // 出价(分)
}
// GenerateCIDRes 生成CID响应
type GenerateCIDRes struct {
CID string `json:"cid"` // 唯一CID
Ads []*AdInfo `json:"ads"` // 广告列表
TotalAds int `json:"total_ads"` // 总广告数
TenantId int64 `json:"tenant_id"` // 租户ID
TenantName string `json:"tenant_name"` // 租户名称
GeneratedAt string `json:"generated_at"` // 生成时间
}
// GetCIDStatisticsReq 获取CID统计请求
type GetCIDStatisticsReq struct {
g.Meta `path:"/cid/statistics" method:"get" tags:"CID服务" summary:"获取CID统计" dc:"获取CID服务的统计信息"`
UserId int64 `json:"user_id"` // 用户ID可选
TenantId int64 `json:"tenant_id"` // 租户ID可选
DateFrom int64 `json:"date_from"` // 开始日期
DateTo int64 `json:"date_to"` // 结束日期
}
// GetCIDStatisticsRes 获取CID统计响应
type GetCIDStatisticsRes struct {
TotalRequests int64 `json:"total_requests"` // 总请求数
SuccessfulReq int64 `json:"successful_requests"` // 成功请求数
AverageProcessTime float64 `json:"average_process_time"` // 平均处理时间
TopSources []string `json:"top_sources"` // 主要广告源
ConversionStats map[string]float64 `json:"conversion_stats"` // 转化率统计
}
// CIDRequestHistory CID请求历史记录
type CIDRequestHistory struct {
Id int64 `json:"id"` // 记录ID
TenantId int64 `json:"tenant_id"` // 租户ID
UserId int64 `json:"user_id"` // 用户ID
RequestType string `json:"request_type"` // 请求类型
Status string `json:"status"` // 状态
ProcessTime int `json:"process_time"` // 处理时间(ms)
CreatedAt string `json:"created_at"` // 创建时间
}
// GetCIDHistoryReq 获取CID历史请求
type GetCIDHistoryReq struct {
g.Meta `path:"/cid/history" method:"get" tags:"CID服务" summary:"获取CID历史记录" dc:"分页获取用户的CID请求历史"`
Page int `json:"page" v:"required|min:1"` // 页码
Size int `json:"size" v:"required|min:1|max:100"` // 每页数量
}
// GetCIDHistoryRes 获取CID历史响应
type GetCIDHistoryRes struct {
List []*CIDRequestHistory `json:"list"` // 历史记录列表
Total int64 `json:"total"` // 总数
Page int `json:"page"` // 当前页
Size int `json:"size"` // 每页数量
}

86
model/dto/strategy_dto.go Normal file
View File

@@ -0,0 +1,86 @@
package dto
import (
"github.com/gogf/gf/v2/frame/g"
)
// CreateStrategyReq 创建策略请求
type CreateStrategyReq struct {
g.Meta `path:"/strategy/create" method:"post" tags:"策略管理" summary:"创建匹配策略" dc:"创建新的广告匹配策略"`
Name string `json:"name" v:"required|length:3,50"` // 策略名称
Description string `json:"description" v:"max:500"` // 描述
TenantLevel string `json:"tenant_level" v:"required|in:basic,standard,premium"` // 租户级别
MinConversion float64 `json:"min_conversion" v:"required|min:0|max:1"` // 最低转化率
MaxConversion float64 `json:"max_conversion" v:"required|min:0|max:1"` // 最高转化率
SourceWeights map[string]int `json:"source_weights" v:"required"` // 广告源权重
MaxAdsPerReq int `json:"max_ads_per_req" v:"required|min:1|max:50"` // 每次请求最大广告数
Priority int `json:"priority" v:"required|min:0|max:100"` // 优先级
Status string `json:"status" v:"required|in:active,inactive"` // 状态
}
// UpdateStrategyReq 更新策略请求
type UpdateStrategyReq struct {
g.Meta `path:"/strategy/update" method:"put" tags:"策略管理" summary:"更新匹配策略" dc:"更新现有的广告匹配策略"`
Id int64 `json:"id" v:"required"` // 策略ID
Name string `json:"name" v:"required|length:3,50"` // 策略名称
Description string `json:"description" v:"max:500"` // 描述
TenantLevel string `json:"tenant_level" v:"required|in:basic,standard,premium"` // 租户级别
MinConversion float64 `json:"min_conversion" v:"required|min:0|max:1"` // 最低转化率
MaxConversion float64 `json:"max_conversion" v:"required|min:0|max:1"` // 最高转化率
SourceWeights map[string]int `json:"source_weights" v:"required"` // 广告源权重
MaxAdsPerReq int `json:"max_ads_per_req" v:"required|min:1|max:50"` // 每次请求最大广告数
Priority int `json:"priority" v:"required|min:0|max:100"` // 优先级
Status string `json:"status" v:"required|in:active,inactive"` // 状态
}
// DeleteStrategyReq 删除策略请求
type DeleteStrategyReq struct {
g.Meta `path:"/strategy/delete" method:"delete" tags:"策略管理" summary:"删除匹配策略" dc:"删除指定的广告匹配策略"`
Id int64 `json:"id" v:"required"` // 策略ID
}
// GetStrategyReq 获取策略请求
type GetStrategyReq struct {
g.Meta `path:"/strategy/info" method:"get" tags:"策略管理" summary:"获取策略详情" dc:"获取指定策略的详细信息"`
Id int64 `json:"id" v:"required"` // 策略ID
}
// GetStrategyListReq 获取策略列表请求
type GetStrategyListReq struct {
g.Meta `path:"/strategy/list" method:"get" tags:"策略管理" summary:"获取策略列表" dc:"分页获取策略列表"`
Page int `json:"page" v:"required|min:1"` // 页码
Size int `json:"size" v:"required|min:1|max:100"` // 每页数量
TenantLevel string `json:"tenant_level"` // 租户级别筛选
Status string `json:"status"` // 状态筛选
}
// StrategyRes 策略响应
type StrategyRes struct {
Id int64 `json:"id"` // ID
Name string `json:"name"` // 策略名称
Description string `json:"description"` // 描述
TenantLevel string `json:"tenant_level"` // 租户级别
MinConversion float64 `json:"min_conversion"` // 最低转化率
MaxConversion float64 `json:"max_conversion"` // 最高转化率
SourceWeights map[string]int `json:"source_weights"` // 广告源权重
MaxAdsPerReq int `json:"max_ads_per_req"` // 每次请求最大广告数
Priority int `json:"priority"` // 优先级
Status string `json:"status"` // 状态
CreatedAt string `json:"created_at"` // 创建时间
UpdatedAt string `json:"updated_at"` // 更新时间
CreatedBy int64 `json:"created_by"` // 创建人
UpdatedBy int64 `json:"updated_by"` // 更新人
}
// GetStrategyListRes 获取策略列表响应
type GetStrategyListRes struct {
List []*StrategyRes `json:"list"` // 策略列表
Total int64 `json:"total"` // 总数
Page int `json:"page"` // 当前页
Size int `json:"size"` // 每页数量
}
// DeleteStrategyRes 删除策略响应
type DeleteStrategyRes struct {
Success bool `json:"success"` // 是否成功
}

163
model/entity/ad_source.go Normal file
View File

@@ -0,0 +1,163 @@
package entity
import (
"gitee.com/red-future---jilin-g/common/do"
)
const AdSourceCollection = "ad_source"
// AdSource 广告源实体
type AdSource struct {
do.MongoBaseDO `bson:",inline"` // 嵌入基础字段Id, Creator, CreatedAt, Updater, UpdatedAt, TenantId, IsDeleted
// 基本信息
Name string `bson:"name" json:"name"` // 广告源名称
Code string `bson:"code" json:"code"` // 广告源编码,唯一标识
Provider string `bson:"provider" json:"provider"` // 提供商google、facebook、baidu、tencent、self等
Type string `bson:"type" json:"type"` // 类型self(自营)、third_party(第三方)、exchange(广告交易平台)
Description string `bson:"description" json:"description"` // 描述
// 连接配置
Config *AdSourceConfig `bson:"config" json:"config"` // 广告源配置
// API配置
APIEndpoint string `bson:"apiEndpoint" json:"apiEndpoint"` // API端点
APIVersion string `bson:"apiVersion" json:"apiVersion"` // API版本
AuthType string `bson:"authType" json:"authType"` // 认证类型api_key、oauth、basic
AuthConfig map[string]interface{} `bson:"authConfig" json:"authConfig"` // 认证配置
Headers map[string]string `bson:"headers" json:"headers"` // 请求头配置
Timeout int `bson:"timeout" json:"timeout"` // 超时时间(毫秒)
RetryCount int `bson:"retryCount" json:"retryCount"` // 重试次数
// 广告源能力
Capabilities *AdSourceCapabilities `bson:"capabilities" json:"capabilities"` // 广告源能力
// 质量指标
QualityMetrics *AdSourceQualityMetrics `bson:"qualityMetrics" json:"qualityMetrics"` // 质量指标
// 财务设置
PaymentTerms *PaymentTerms `bson:"paymentTerms" json:"paymentTerms"` // 支付条款
// 状态信息
Status string `bson:"status" json:"status"` // 广告源状态active、inactive、maintenance
Health string `bson:"health" json:"health"` // 健康状态healthy、degraded、unhealthy
LastCheckAt int64 `bson:"lastCheckAt" json:"lastCheckAt"` // 最后检查时间
// 统计信息
TotalRequests int64 `bson:"totalRequests" json:"totalRequests"` // 总请求数
SuccessfulRequests int64 `bson:"successfulRequests" json:"successfulRequests"` // 成功请求数
FailedRequests int64 `bson:"failedRequests" json:"failedRequests"` // 失败请求数
AverageResponseTime float64 `bson:"averageResponseTime" json:"averageResponseTime"` // 平均响应时间(毫秒)
FillRate float64 `bson:"fillRate" json:"fillRate"` // 填充率
CTR float64 `bson:"ctr" json:"ctr"` // 点击率
CVR float64 `bson:"cvr" json:"cvr"` // 转化率
// 系统信息
Priority int `bson:"priority" json:"priority"` // 优先级,数值越高优先级越高
}
// AdSourceConfig 广告源配置
type AdSourceConfig struct {
// 基础配置
SupportedFormats []string `bson:"supportedFormats" json:"supportedFormats"` // 支持的广告格式
SupportedSizes []string `bson:"supportedSizes" json:"supportedSizes"` // 支持的尺寸
SupportedDevices []string `bson:"supportedDevices" json:"supportedDevices"` // 支持的设备类型
SupportedOS []string `bson:"supportedOS" json:"supportedOS"` // 支持的操作系统
SupportedCountries []string `bson:"supportedCountries" json:"supportedCountries"` // 支持的国家/地区
// 竞价配置
BiddingType string `bson:"biddingType" json:"biddingType"` // 竞价类型cpm、cpc、cpa、rtb
MinBidAmount int64 `bson:"minBidAmount" json:"minBidAmount"` // 最小出价(分)
MaxBidAmount int64 `bson:"maxBidAmount" json:"maxBidAmount"` // 最大出价(分)
BidIncrement int64 `bson:"bidIncrement" json:"bidIncrement"` // 出价增量(分)
DefaultBidAmount int64 `bson:"defaultBidAmount" json:"defaultBidAmount"` // 默认出价(分)
AutoOptimization bool `bson:"autoOptimization" json:"autoOptimization"` // 是否自动优化
// 定向配置
TargetingSupport *TargetingSupport `bson:"targetingSupport" json:"targetingSupport"` // 定向支持
// 其他配置
MaxAdsPerRequest int `bson:"maxAdsPerRequest" json:"maxAdsPerRequest"` // 单次请求最大广告数量
BrandSafety bool `bson:"brandSafety" json:"brandSafety"` // 品牌安全
Viewability bool `bson:"viewability" json:"viewability"` // 可见性支持
}
// TargetingSupport 定向支持
type TargetingSupport struct {
GeoTargeting bool `bson:"geoTargeting" json:"geoTargeting"` // 地理定向
DemographicTargeting bool `bson:"demographicTargeting" json:"demographicTargeting"` // 人口统计定向
BehavioralTargeting bool `bson:"behavioralTargeting" json:"behavioralTargeting"` // 行为定向
ContextualTargeting bool `bson:"contextualTargeting" json:"contextualTargeting"` // 上下文定向
DeviceTargeting bool `bson:"deviceTargeting" json:"deviceTargeting"` // 设备定向
TimeTargeting bool `bson:"timeTargeting" json:"timeTargeting"` // 时间定向
Retargeting bool `bson:"retargeting" json:"retargeting"` // 重定向
CookieTargeting bool `bson:"cookieTargeting" json:"cookieTargeting"` // Cookie定向
}
// AdSourceCapabilities 广告源能力
type AdSourceCapabilities struct {
// 广告格式
SupportedFormats []AdFormat `bson:"supportedFormats" json:"supportedFormats"` // 支持的广告格式
// 功能特性
RealTimeBidding bool `bson:"realTimeBidding" json:"realTimeBidding"` // 实时竞价
HeaderBidding bool `bson:"headerBidding" json:"headerBidding"` // 标题竞价
ProgrammaticDirect bool `bson:"programmaticDirect" json:"programmaticDirect"` // 程序化直购
PrivateMarketplace bool `bson:"privateMarketplace" json:"privateMarketplace"` // 私有交易市场
// 质量控制
FraudDetection bool `bson:"fraudDetection" json:"fraudDetection"` // 反欺诈检测
BrandSafety bool `bson:"brandSafety" json:"brandSafety"` // 品牌安全
Viewability bool `bson:"viewability" json:"viewability"` // 可见度验证
CreativeApproval bool `bson:"creativeApproval" json:"creativeApproval"` // 创意审核
// 数据能力
AudienceTargeting bool `bson:"audienceTargeting" json:"audienceTargeting"` // 受众定向
ContextualTargeting bool `bson:"contextualTargeting" json:"contextualTargeting"` // 上下文定向
CrossDeviceTargeting bool `bson:"crossDeviceTargeting" json:"crossDeviceTargeting"` // 跨设备定向
}
// AdFormat 广告格式
type AdFormat struct {
Type string `bson:"type" json:"type"` // 格式类型banner、video、native、interstitial等
Name string `bson:"name" json:"name"` // 格式名称
Width int `bson:"width" json:"width"` // 宽度
Height int `bson:"height" json:"height"` // 高度
MimeType string `bson:"mimeType" json:"mimeType"` // MIME类型
}
// AdSourceQualityMetrics 广告源质量指标
type AdSourceQualityMetrics struct {
// 性能指标
AverageResponseTime float64 `bson:"averageResponseTime" json:"averageResponseTime"` // 平均响应时间(毫秒)
SuccessRate float64 `bson:"successRate" json:"successRate"` // 成功率
ErrorRate float64 `bson:"errorRate" json:"errorRate"` // 错误率
Uptime float64 `bson:"uptime" json:"uptime"` // 可用性(百分比)
// 广告质量
CTR float64 `bson:"ctr" json:"ctr"` // 点击率
CVR float64 `bson:"cvr" json:"cvr"` // 转化率
FillRate float64 `bson:"fillRate" json:"fillRate"` // 填充率
ViewabilityRate float64 `bson:"viewabilityRate" json:"viewabilityRate"` // 可见率
BrandSafetyScore float64 `bson:"brandSafetyScore" json:"brandSafetyScore"` // 品牌安全评分
// 财务指标
eCPM int64 `bson:"ecpm" json:"ecpm"` // 有效千次展示成本(分)
eCPC int64 `bson:"ecpc" json:"ecpc"` // 有效点击成本(分)
RevenuePerRequest int64 `bson:"revenuePerRequest" json:"revenuePerRequest"` // 每请求收入(分)
// 时间指标
LastUpdated int64 `bson:"lastUpdated" json:"lastUpdated"` // 最后更新时间
MetricsUpdateWindow int `bson:"metricsUpdateWindow" json:"metricsUpdateWindow"` // 指标更新窗口(分钟)
}
// PaymentTerms 支付条款
type PaymentTerms struct {
BillingModel string `bson:"billingModel" json:"billingModel"` // 计费模式cpm、cpc、cpa、rev_share
PaymentTerms string `bson:"paymentTerms" json:"paymentTerms"` // 支付条款net_30、net_60、net_90
RevShareRate float64 `bson:"revShareRate" json:"revShareRate"` // 收入分成比例(0-1)
MinPayment int64 `bson:"minPayment" json:"minPayment"` // 最小支付金额(分)
Currency string `bson:"currency" json:"currency"` // 货币单位
TaxInclusive bool `bson:"taxInclusive" json:"taxInclusive"` // 是否含税
EarlyPaymentDiscount float64 `bson:"earlyPaymentDiscount" json:"earlyPaymentDiscount"` // 提前付款折扣
}

312
model/entity/cid_request.go Normal file
View File

@@ -0,0 +1,312 @@
package entity
import (
"gitee.com/red-future---jilin-g/common/do"
)
const CidRequestCollection = "cid_request"
// CidRequest CID请求实体
type CidRequest struct {
do.MongoBaseDO `bson:",inline"` // 嵌入基础字段Id, Creator, CreatedAt, Updater, UpdatedAt, TenantId, IsDeleted
// 请求信息
RequestID string `bson:"requestId" json:"requestId"` // 请求唯一ID
SessionID string `bson:"sessionId" json:"sessionId"` // 会话ID
UserID string `bson:"userId" json:"userId"` // 用户ID
TenantID string `bson:"tenantId" json:"tenantId"` // 租户ID
IPAddress string `bson:"ipAddress" json:"ipAddress"` // IP地址
UserAgent string `bson:"userAgent" json:"userAgent"` // 用户代理
Referer string `bson:"referer" json:"referer"` // 来源页面
// 广告位信息
PositionCode string `bson:"positionCode" json:"positionCode"` // 广告位编码
PositionSize string `bson:"positionSize" json:"positionSize"` // 广告位尺寸
PositionFormat string `bson:"positionFormat" json:"positionFormat"` // 广告位格式
PositionType string `bson:"positionType" json:"positionType"` // 广告位类型
// 页面信息
PageURL string `bson:"pageUrl" json:"pageUrl"` // 页面URL
PageTitle string `bson:"pageTitle" json:"pageTitle"` // 页面标题
PageCategory string `bson:"pageCategory" json:"pageCategory"` // 页面分类
PageKeywords []string `bson:"pageKeywords" json:"pageKeywords"` // 页面关键词
PageTags map[string]string `bson:"pageTags" json:"pageTags"` // 页面标签
// 用户信息
UserContext *UserContext `bson:"userContext" json:"userContext"` // 用户上下文
DeviceInfo *DeviceInfo `bson:"deviceInfo" json:"deviceInfo"` // 设备信息
LocationInfo *LocationInfo `bson:"locationInfo" json:"locationInfo"` // 位置信息
TemporalInfo *TemporalInfo `bson:"temporalInfo" json:"temporalInfo"` // 时间信息
// 请求参数
RequestParams *RequestParams `bson:"requestParams" json:"requestParams"` // 请求参数
TargetingRules *TargetingRules `bson:"targetingRules" json:"targetingRules"` // 定向规则
// 策略配置
StrategyConfig *StrategyConfig `bson:"strategyConfig" json:"strategyConfig"` // 策略配置
// 响应信息
Response *CidResponse `bson:"response" json:"response"` // 响应结果
ProcessingTime int64 `bson:"processingTime" json:"processingTime"` // 处理时间(毫秒)
ResponseTime int64 `bson:"responseTime" json:"responseTime"` // 响应时间(毫秒)
// 状态信息
Status string `bson:"status" json:"status"` // 请求状态pending、processing、completed、failed、timeout
ErrorMessage string `bson:"errorMessage" json:"errorMessage"` // 错误信息
ErrorCode string `bson:"errorCode" json:"errorCode"` // 错误代码
// 广告源信息
RequestedAdSources []string `bson:"requestedAdSources" json:"requestedAdSources"` // 请求的广告源列表
RespondedAdSources []string `bson:"respondedAdSources" json:"respondedAdSources"` // 响应的广告源列表
AdSourceResponses map[string]*AdSourceResponse `bson:"adSourceResponses" json:"adSourceResponses"` // 各广告源响应
// 统计信息
TotalAdsReturned int `bson:"totalAdsReturned" json:"totalAdsReturned"` // 返回的广告总数
ValidAdsReturned int `bson:"validAdsReturned" json:"validAdsReturned"` // 有效广告数
FilteredAds int `bson:"filteredAds" json:"filteredAds"` // 过滤的广告数
DuplicateAds int `bson:"duplicateAds" json:"duplicateAds"` // 重复广告数
// 系统信息
ServerInstance string `bson:"serverInstance" json:"serverInstance"` // 服务实例ID
Region string `bson:"region" json:"region"` // 服务区域
Version string `bson:"version" json:"version"` // 系统版本
}
// CidResponse CID响应
type CidResponse struct {
Ads []Ad `bson:"ads" json:"ads"` // 广告列表
TrackingInfo *TrackingInfo `bson:"trackingInfo" json:"trackingInfo"` // 跟踪信息
Metadata *ResponseMetadata `bson:"metadata" json:"metadata"` // 响应元数据
}
// Ad 广告
type Ad struct {
ID string `bson:"id" json:"id"` // 广告ID
AdSource string `bson:"adSource" json:"adSource"` // 广告源
Advertiser string `bson:"advertiser" json:"advertiser"` // 广告主
Title string `bson:"title" json:"title"` // 广告标题
Description string `bson:"description" json:"description"` // 广告描述
CreativeURL string `bson:"creativeUrl" json:"creativeUrl"` // 创意URL
LandingURL string `bson:"landingUrl" json:"landingUrl"` // 落地页URL
DisplayURL string `bson:"displayUrl" json:"displayUrl"` // 显示URL
AdType string `bson:"adType" json:"adType"` // 广告类型
Format string `bson:"format" json:"format"` // 广告格式
Width int `bson:"width" json:"width"` // 宽度
Height int `bson:"height" json:"height"` // 高度
MimeType string `bson:"mimeType" json:"mimeType"` // MIME类型
BidAmount int64 `bson:"bidAmount" json:"bidAmount"` // 出价(分)
Revenue int64 `bson:"revenue" json:"revenue"` // 预估收入(分)
CTR float64 `bson:"ctr" json:"ctr"` // 点击率
CVR float64 `bson:"cvr" json:"cvr"` // 转化率
Targeting map[string]interface{} `bson:"targeting" json:"targeting"` // 定向条件
Restrictions map[string]interface{} `bson:"restrictions" json:"restrictions"` // 限制条件
TrackingPixels []string `bson:"trackingPixels" json:"trackingPixels"` // 跟踪像素
CustomData map[string]interface{} `bson:"customData" json:"customData"` // 自定义数据
ExpiresAt int64 `bson:"expiresAt" json:"expiresAt"` // 过期时间
Priority int `bson:"priority" json:"priority"` // 优先级
Score float64 `bson:"score" json:"score"` // 评分
}
// TrackingInfo 跟踪信息
type TrackingInfo struct {
ImpressionURLs []string `bson:"impressionUrls" json:"impressionUrls"` // 展示跟踪URL
ClickURLs []string `bson:"clickUrls" json:"clickUrls"` // 点击跟踪URL
ConversionURLs []string `bson:"conversionUrls" json:"conversionUrls"` // 转化跟踪URL
ViewThroughURLs []string `bson:"viewThroughUrls" json:"viewThroughUrls"` // 查看跟踪URL
EventURLs map[string][]string `bson:"eventUrls" json:"eventUrls"` // 事件跟踪URL
BeaconURLs []string `bson:"beaconUrls" json:"beaconUrls"` // 信标URL
}
// ResponseMetadata 响应元数据
type ResponseMetadata struct {
TotalAvailableAds int `bson:"totalAvailableAds" json:"totalAvailableAds"` // 总可用广告数
SelectedAds int `bson:"selectedAds" json:"selectedAds"` // 选择的广告数
FilteredAds int `bson:"filteredAds" json:"filteredAds"` // 过滤的广告数
DuplicateAds int `bson:"duplicateAds" json:"duplicateAds"` // 重复的广告数
AverageBidAmount int64 `bson:"averageBidAmount" json:"averageBidAmount"` // 平均出价
HighestBidAmount int64 `bson:"highestBidAmount" json:"highestBidAmount"` // 最高出价
LowestBidAmount int64 `bson:"lowestBidAmount" json:"lowestBidAmount"` // 最低出价
AverageCTR float64 `bson:"averageCTR" json:"averageCTR"` // 平均点击率
AverageCVR float64 `bson:"averageCVR" json:"averageCVR"` // 平均转化率
ResponseTime int64 `bson:"responseTime" json:"responseTime"` // 响应时间(毫秒)
CacheHit bool `bson:"cacheHit" json:"cacheHit"` // 是否命中缓存
StrategyUsed string `bson:"strategyUsed" json:"strategyUsed"` // 使用的策略
AdSourcesUsed []string `bson:"adSourcesUsed" json:"adSourcesUsed"` // 使用的广告源
}
// AdSourceResponse 广告源响应
type AdSourceResponse struct {
AdSource string `bson:"adSource" json:"adSource"` // 广告源名称
Status string `bson:"status" json:"status"` // 响应状态success、timeout、error
ResponseTime int64 `bson:"responseTime" json:"responseTime"` // 响应时间(毫秒)
AdsReturned int `bson:"adsReturned" json:"adsReturned"` // 返回的广告数
AdsAccepted int `bson:"adsAccepted" json:"adsAccepted"` // 接受的广告数
AdsFiltered int `bson:"adsFiltered" json:"adsFiltered"` // 过滤的广告数
ErrorMessage string `bson:"errorMessage" json:"errorMessage"` // 错误信息
ErrorCode string `bson:"errorCode" json:"errorCode"` // 错误代码
RetryCount int `bson:"retryCount" json:"retryCount"` // 重试次数
CacheHit bool `bson:"cacheHit" json:"cacheHit"` // 是否命中缓存
TotalRevenue int64 `bson:"totalRevenue" json:"totalRevenue"` // 总收入(分)
AverageBidAmount int64 `bson:"averageBidAmount" json:"averageBidAmount"` // 平均出价(分)
}
// UserContext 用户上下文
type UserContext struct {
UserID string `bson:"userId" json:"userId"` // 用户ID
SessionID string `bson:"sessionId" json:"sessionId"` // 会话ID
CookieID string `bson:"cookieId" json:"cookieId"` // Cookie ID
IP string `bson:"ip" json:"ip"` // IP地址
UserAgent string `bson:"userAgent" json:"userAgent"` // 用户代理
Language string `bson:"language" json:"language"` // 语言
Timezone string `bson:"timezone" json:"timezone"` // 时区
CustomData map[string]interface{} `bson:"customData" json:"customData"` // 自定义数据
}
// DeviceInfo 设备信息
type DeviceInfo struct {
Type string `bson:"type" json:"type"` // 设备类型desktop、mobile、tablet
Brand string `bson:"brand" json:"brand"` // 设备品牌
Model string `bson:"model" json:"model"` // 设备型号
OS string `bson:"os" json:"os"` // 操作系统
OSVersion string `bson:"osVersion" json:"osVersion"` // 操作系统版本
Browser string `bson:"browser" json:"browser"` // 浏览器
BrowserVersion string `bson:"browserVersion" json:"browserVersion"` // 浏览器版本
ScreenWidth int `bson:"screenWidth" json:"screenWidth"` // 屏幕宽度
ScreenHeight int `bson:"screenHeight" json:"screenHeight"` // 屏幕高度
ViewportWidth int `bson:"viewportWidth" json:"viewportWidth"` // 视口宽度
ViewportHeight int `bson:"viewportHeight" json:"viewportHeight"` // 视口高度
DPI int `bson:"dpi" json:"dpi"` // 设备DPI
IsJavaScript bool `bson:"isJavaScript" json:"isJavaScript"` // 是否支持JavaScript
IsCookie bool `bson:"isCookie" json:"isCookie"` // 是否支持Cookie
IsFlash bool `bson:"isFlash" json:"isFlash"` // 是否支持Flash
IsHTTPS bool `bson:"isHTTPS" json:"isHTTPS"` // 是否HTTPS连接
}
// LocationInfo 位置信息
type LocationInfo struct {
Country string `bson:"country" json:"country"` // 国家
Region string `bson:"region" json:"region"` // 地区/省份
City string `bson:"city" json:"city"` // 城市
PostalCode string `bson:"postalCode" json:"postalCode"` // 邮政编码
Latitude float64 `bson:"latitude" json:"latitude"` // 纬度
Longitude float64 `bson:"longitude" json:"longitude"` // 经度
Timezone string `bson:"timezone" json:"timezone"` // 时区
Metro string `bson:"metro" json:"metro"` // 都市区
Area string `bson:"area" json:"area"` // 区域
Network string `bson:"network" json:"network"` // 网络运营商
ConnectionType string `bson:"connectionType" json:"connectionType"` // 连接类型
ISP string `bson:"isp" json:"isp"` // 互联网服务提供商
}
// TemporalInfo 时间信息
type TemporalInfo struct {
Timestamp int64 `bson:"timestamp" json:"timestamp"` // 时间戳(秒)
Milliseconds int64 `bson:"milliseconds" json:"milliseconds"` // 毫秒数
Timezone string `bson:"timezone" json:"timezone"` // 时区
DayOfWeek int `bson:"dayOfWeek" json:"dayOfWeek"` // 星期几(0-6)
HourOfDay int `bson:"hourOfDay" json:"hourOfDay"` // 小时(0-23)
DayOfMonth int `bson:"dayOfMonth" json:"dayOfMonth"` // 月份中的天数
Month int `bson:"month" json:"month"` // 月份(1-12)
Year int `bson:"year" json:"year"` // 年份
IsWeekend bool `bson:"isWeekend" json:"isWeekend"` // 是否周末
IsBusinessHours bool `bson:"isBusinessHours" json:"isBusinessHours"` // 是否营业时间
Season string `bson:"season" json:"season"` // 季节
Holiday string `bson:"holiday" json:"holiday"` // 节假日
}
// RequestParams 请求参数
type RequestParams struct {
AdCount int `bson:"adCount" json:"adCount"` // 请求的广告数量
AdTypes []string `bson:"adTypes" json:"adTypes"` // 广告类型
AdSizes []string `bson:"adSizes" json:"adSizes"` // 广告尺寸
ExcludedAdSources []string `bson:"excludedAdSources" json:"excludedAdSources"` // 排除的广告源
RequiredAdSources []string `bson:"requiredAdSources" json:"requiredAdSources"` // 必需的广告源
MinBidAmount int64 `bson:"minBidAmount" json:"minBidAmount"` // 最小出价(分)
MaxBidAmount int64 `bson:"maxBidAmount" json:"maxBidAmount"` // 最大出价(分)
AllowDuplicates bool `bson:"allowDuplicates" json:"allowDuplicates"` // 是否允许重复广告
FloorPrice int64 `bson:"floorPrice" json:"floorPrice"` // 底价(分)
CeilingPrice int64 `bson:"ceilingPrice" json:"ceilingPrice"` // 封顶价(分)
CustomParams map[string]interface{} `bson:"customParams" json:"customParams"` // 自定义参数
}
// TargetingRules 定向规则
type TargetingRules struct {
GeoTargeting *GeoTargeting `bson:"geoTargeting" json:"geoTargeting"` // 地理定向
DemographicTargeting *DemographicTargeting `bson:"demographicTargeting" json:"demographicTargeting"` // 人口统计定向
BehavioralTargeting *BehavioralTargeting `bson:"behavioralTargeting" json:"behavioralTargeting"` // 行为定向
ContextualTargeting *ContextualTargeting `bson:"contextualTargeting" json:"contextualTargeting"` // 上下文定向
DeviceTargeting *DeviceTargeting `bson:"deviceTargeting" json:"deviceTargeting"` // 设备定向
TimeTargeting *TimeTargeting `bson:"timeTargeting" json:"timeTargeting"` // 时间定向
CustomTargeting map[string]interface{} `bson:"customTargeting" json:"customTargeting"` // 自定义定向
}
// GeoTargeting 地理定向
type GeoTargeting struct {
Countries []string `bson:"countries" json:"countries"` // 国家列表
Regions []string `bson:"regions" json:"regions"` // 地区列表
Cities []string `bson:"cities" json:"cities"` // 城市列表
PostalCodes []string `bson:"postalCodes" json:"postalCodes"` // 邮政编码列表
GeoTargets []string `bson:"geoTargets" json:"geoTargets"` // 地理目标
}
// DemographicTargeting 人口统计定向
type DemographicTargeting struct {
AgeRange *AgeRange `bson:"ageRange" json:"ageRange"` // 年龄范围
Gender []string `bson:"gender" json:"gender"` // 性别
Income []string `bson:"income" json:"income"` // 收入水平
Education []string `bson:"education" json:"education"` // 教育程度
Occupation []string `bson:"occupation" json:"occupation"` // 职业类型
Interests []string `bson:"interests" json:"interests"` // 兴趣标签
Lifestyle []string `bson:"lifestyle" json:"lifestyle"` // 生活方式
}
// BehavioralTargeting 行为定向
type BehavioralTargeting struct {
SearchHistory []string `bson:"searchHistory" json:"searchHistory"` // 搜索历史
BrowseHistory []string `bson:"browseHistory" json:"browseHistory"` // 浏览历史
PurchaseHistory []string `bson:"purchaseHistory" json:"purchaseHistory"` // 购买历史
AdInteractions []string `bson:"adInteractions" json:"adInteractions"` // 广告互动
Behaviors []string `bson:"behaviors" json:"behaviors"` // 行为标签
Segments []string `bson:"segments" json:"segments"` // 用户分群
}
// ContextualTargeting 上下文定向
type ContextualTargeting struct {
Categories []string `bson:"categories" json:"categories"` // 内容分类
Keywords []string `bson:"keywords" json:"keywords"` // 关键词
Tags []string `bson:"tags" json:"tags"` // 标签
Sentiment string `bson:"sentiment" json:"sentiment"` // 情感倾向
ContentType string `bson:"contentType" json:"contentType"` // 内容类型
ContentRating string `bson:"contentRating" json:"contentRating"` // 内容评级
}
// DeviceTargeting 设备定向
type DeviceTargeting struct {
DeviceTypes []string `bson:"deviceTypes" json:"deviceTypes"` // 设备类型
OS []string `bson:"os" json:"os"` // 操作系统
Browsers []string `bson:"browsers" json:"browsers"` // 浏览器
Carriers []string `bson:"carriers" json:"carriers"` // 运营商
ConnectionTypes []string `bson:"connectionTypes" json:"connectionTypes"` // 连接类型
}
// TimeTargeting 时间定向
type TimeTargeting struct {
TimeSlots []TimeSlot `bson:"timeSlots" json:"timeSlots"` // 时间段
DaysOfWeek []int `bson:"daysOfWeek" json:"daysOfWeek"` // 星期几
Dates []string `bson:"dates" json:"dates"` // 日期范围
Timezone string `bson:"timezone" json:"timezone"` // 时区
ExcludeHolidays bool `bson:"excludeHolidays" json:"excludeHolidays"` // 排除节假日
}
// StrategyConfig 策略配置
type StrategyConfig struct {
StrategyType string `bson:"strategyType" json:"strategyType"` // 策略类型
Priority int `bson:"priority" json:"priority"` // 优先级
Weight float64 `bson:"weight" json:"weight"` // 权重
MinAds int `bson:"minAds" json:"minAds"` // 最小广告数
MaxAds int `bson:"maxAds" json:"maxAds"` // 最大广告数
AllowDuplicates bool `bson:"allowDuplicates" json:"allowDuplicates"` // 是否允许重复
Timeout int64 `bson:"timeout" json:"timeout"` // 超时时间(毫秒)
RetryCount int `bson:"retryCount" json:"retryCount"` // 重试次数
CustomSettings map[string]interface{} `bson:"customSettings" json:"customSettings"` // 自定义设置
}

23
model/entity/strategy.go Normal file
View File

@@ -0,0 +1,23 @@
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// Strategy 匹配策略表
type Strategy struct {
Id int64 `json:"id" orm:"id,primary"` // ID
Name string `json:"name" orm:"name"` // 策略名称
Description string `json:"description" orm:"description"` // 描述
TenantLevel string `json:"tenant_level" orm:"tenant_level"` // 适用租户级别
MinConversion float64 `json:"min_conversion" orm:"min_conversion"` // 最低转化率
MaxConversion float64 `json:"max_conversion" orm:"max_conversion"` // 最高转化率
SourceWeights string `json:"source_weights" orm:"source_weights"` // 广告源权重 (JSON格式)
MaxAdsPerReq int `json:"max_ads_per_req" orm:"max_ads_per_req"` // 每次请求最大广告数
Priority int `json:"priority" orm:"priority"` // 优先级
Status string `json:"status" orm:"status"` // 状态: active, inactive
CreatedAt *gtime.Time `json:"created_at" orm:"created_at"` // 创建时间
UpdatedAt *gtime.Time `json:"updated_at" orm:"updated_at"` // 更新时间
CreatedBy int64 `json:"created_by" orm:"created_by"` // 创建人
UpdatedBy int64 `json:"updated_by" orm:"updated_by"` // 更新人
}

9
model/types/tenant.go Normal file
View File

@@ -0,0 +1,9 @@
package types
// Tenant 租户信息类型
type Tenant struct {
Id int64 `json:"id"` // 租户ID
Name string `json:"name"` // 租户名称
Level string `json:"level"` // 租户级别: basic, standard, premium
Status string `json:"status"` // 状态: active, inactive
}

View 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
View 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
View 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)
}