初始化项目
This commit is contained in:
261
README.md
261
README.md
@@ -1,99 +1,212 @@
|
||||
# CID广告管理系统
|
||||
# CID服务商项目
|
||||
|
||||
## 项目简介
|
||||
## 项目概述
|
||||
|
||||
CID广告管理系统是一个完整的广告投放和管理平台,支持广告主管理、广告管理、广告位管理和数据统计分析等功能。
|
||||
CID服务商项目是一个为企业提供CID(Click 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
BIN
cidService
Executable file
Binary file not shown.
86
config/config.example.yaml
Normal file
86
config/config.example.yaml
Normal 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"
|
||||
111
controller/ad_source_controller.go
Normal file
111
controller/ad_source_controller.go
Normal 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
|
||||
}
|
||||
62
controller/cid_controller.go
Normal file
62
controller/cid_controller.go
Normal 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
|
||||
}
|
||||
78
controller/strategy_controller.go
Normal file
78
controller/strategy_controller.go
Normal 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
91
dao/ad_source_dao.go
Normal 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
83
dao/cid_request_dao.go
Normal 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
100
dao/strategy_dao.go
Normal 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
78
database/init.sql
Normal 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
300
model/dto/ad_source_dto.go
Normal 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
81
model/dto/cid_dto.go
Normal 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
86
model/dto/strategy_dto.go
Normal 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
163
model/entity/ad_source.go
Normal 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
312
model/entity/cid_request.go
Normal 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
23
model/entity/strategy.go
Normal 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
9
model/types/tenant.go
Normal 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
|
||||
}
|
||||
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