初始化项目
This commit is contained in:
BIN
cidService
BIN
cidService
Binary file not shown.
@@ -1,11 +1,18 @@
|
||||
server:
|
||||
address : ":3002"
|
||||
address : ":3004"
|
||||
name: "cidService"
|
||||
jwt:
|
||||
secret: "abcdefghijklmnopqrstuvwxyz"
|
||||
rate:
|
||||
limit: 200
|
||||
burst: 300
|
||||
|
||||
# 租户限流配置
|
||||
tenantRateLimit:
|
||||
enabled: true # 是否启用租户限流
|
||||
requestsPerHour: 3600 # 每小时最大请求数
|
||||
window: 3600 # 时间窗口(秒)
|
||||
burst: 100 # 突发请求数
|
||||
mongo:
|
||||
logger:
|
||||
level: "all"
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
# 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"
|
||||
93
consts/consts.go
Normal file
93
consts/consts.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package consts
|
||||
|
||||
// Redis键前缀
|
||||
const (
|
||||
AdRequestLimitKeyPrefix = "ad_request_limit:" // 广告请求限流键前缀
|
||||
RateLimitKeyPrefix = "rate_limit:" // 通用限流键前缀
|
||||
SessionCacheKeyPrefix = "session_cache:" // 会话缓存键前缀
|
||||
)
|
||||
|
||||
// 广告源状态
|
||||
const (
|
||||
AdSourceStatusActive = "active" // 活跃
|
||||
AdSourceStatusInactive = "inactive" // 非活跃
|
||||
AdSourceStatusMaintenance = "maintenance" // 维护中
|
||||
)
|
||||
|
||||
// 广告源健康状态
|
||||
const (
|
||||
AdSourceHealthHealthy = "healthy" // 健康
|
||||
AdSourceHealthDegraded = "degraded" // 降级
|
||||
AdSourceHealthUnhealthy = "unhealthy" // 不健康
|
||||
)
|
||||
|
||||
// 广告源类型
|
||||
const (
|
||||
AdSourceTypeSelf = "self" // 自营
|
||||
AdSourceTypeThirdParty = "third_party" // 第三方
|
||||
AdSourceTypeExchange = "exchange" // 广告交易平台
|
||||
)
|
||||
|
||||
// 广告源提供商
|
||||
const (
|
||||
AdSourceProviderGoogle = "google" // Google
|
||||
AdSourceProviderBaidu = "baidu" // 百度
|
||||
AdSourceProviderTencent = "tencent" // 腾讯
|
||||
AdSourceProviderSelf = "self" // 自营
|
||||
)
|
||||
|
||||
// 认证类型
|
||||
const (
|
||||
AuthTypeAPIKey = "api_key" // API密钥
|
||||
AuthTypeOAuth = "oauth" // OAuth
|
||||
AuthTypeBasic = "basic" // Basic认证
|
||||
)
|
||||
|
||||
// 竞价类型
|
||||
const (
|
||||
BiddingTypeCPM = "cpm" // 千次展示成本
|
||||
BiddingTypeCPC = "cpc" // 每次点击成本
|
||||
BiddingTypeCPA = "cpa" // 每次行动成本
|
||||
BiddingTypeRTB = "rtb" // 实时竞价
|
||||
)
|
||||
|
||||
// 广告格式类型
|
||||
const (
|
||||
AdFormatTypeBanner = "banner" // 横幅广告
|
||||
AdFormatTypeVideo = "video" // 视频广告
|
||||
AdFormatTypeNative = "native" // 原生广告
|
||||
AdFormatTypeInterstitial = "interstitial" // 插屏广告
|
||||
)
|
||||
|
||||
// 计费模式
|
||||
const (
|
||||
BillingModelCPM = "cpm" // 千次展示成本
|
||||
BillingModelCPC = "cpc" // 每次点击成本
|
||||
BillingModelCPA = "cpa" // 每次行动成本
|
||||
BillingModelRevShare = "rev_share" // 收入分成
|
||||
)
|
||||
|
||||
// 支付条款
|
||||
const (
|
||||
PaymentTermsNet30 = "net_30" // 30天
|
||||
PaymentTermsNet60 = "net_60" // 60天
|
||||
PaymentTermsNet90 = "net_90" // 90天
|
||||
)
|
||||
|
||||
// 默认配置值
|
||||
const (
|
||||
DefaultTimeout = 5000 // 默认超时时间(毫秒)
|
||||
DefaultRetryCount = 3 // 默认重试次数
|
||||
DefaultPriority = 1 // 默认优先级
|
||||
)
|
||||
|
||||
// 错误消息
|
||||
const (
|
||||
ErrAdSourceNotFound = "广告源不存在"
|
||||
ErrAdSourceNameExists = "广告源名称已存在"
|
||||
ErrAdSourceCodeExists = "广告源编码已存在"
|
||||
ErrAdSourceInactive = "广告源非活跃状态"
|
||||
ErrAdSourceUnhealthy = "广告源健康状态异常"
|
||||
ErrRateLimitExceeded = "请求频率超限"
|
||||
ErrInvalidConfiguration = "配置参数无效"
|
||||
)
|
||||
@@ -31,7 +31,6 @@ const (
|
||||
|
||||
// 限流键
|
||||
const (
|
||||
AdRequestLimitKeyPrefix = "cid:limit:req:" // 广告请求限流键前缀
|
||||
ApiRequestLimitKeyPrefix = "cid:limit:api:" // API请求限流键前缀
|
||||
)
|
||||
|
||||
|
||||
@@ -3,50 +3,50 @@ package controller
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidService/model/dto"
|
||||
"cidService/service"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/service"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
)
|
||||
|
||||
type cAdPosition struct{}
|
||||
type adPosition struct{}
|
||||
|
||||
var AdPosition = &cAdPosition{}
|
||||
var AdPosition = &adPosition{}
|
||||
|
||||
// Add 添加广告位
|
||||
func (c *cAdPosition) Add(ctx context.Context, req *dto.AddAdPositionReq) (res *dto.AddAdPositionRes, err error) {
|
||||
func (c *adPosition) Add(ctx context.Context, req *dto.AddAdPositionReq) (res *dto.AddAdPositionRes, err error) {
|
||||
return service.AdPosition.Add(ctx, req)
|
||||
}
|
||||
|
||||
// Update 更新广告位
|
||||
func (c *cAdPosition) Update(ctx context.Context, req *dto.UpdateAdPositionReq) (res *http.ResponseEmpty, err error) {
|
||||
func (c *adPosition) Update(ctx context.Context, req *dto.UpdateAdPositionReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.AdPosition.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告位状态
|
||||
func (c *cAdPosition) UpdateStatus(ctx context.Context, req *dto.UpdateAdPositionStatusReq) (res *http.ResponseEmpty, err error) {
|
||||
func (c *adPosition) UpdateStatus(ctx context.Context, req *dto.UpdateAdPositionStatusReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.AdPosition.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取广告位详情
|
||||
func (c *cAdPosition) GetOne(ctx context.Context, req *dto.GetAdPositionReq) (res *dto.GetAdPositionRes, err error) {
|
||||
func (c *adPosition) GetOne(ctx context.Context, req *dto.GetAdPositionReq) (res *dto.GetAdPositionRes, err error) {
|
||||
return service.AdPosition.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// List 获取广告位列表
|
||||
func (c *cAdPosition) List(ctx context.Context, req *dto.ListAdPositionReq) (res *dto.ListAdPositionRes, err error) {
|
||||
func (c *adPosition) List(ctx context.Context, req *dto.ListAdPositionReq) (res *dto.ListAdPositionRes, err error) {
|
||||
return service.AdPosition.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetStatistics 获取广告位统计数据
|
||||
func (c *cAdPosition) GetStatistics(ctx context.Context, req *dto.GetAdPositionStatisticsReq) (res *dto.GetAdPositionStatisticsRes, err error) {
|
||||
func (c *adPosition) GetStatistics(ctx context.Context, req *dto.GetAdPositionStatisticsReq) (res *dto.GetAdPositionStatisticsRes, err error) {
|
||||
return service.AdPosition.GetStatistics(ctx, req)
|
||||
}
|
||||
|
||||
// GetAvailableAdPositions 获取可用的广告位列表
|
||||
func (c *cAdPosition) GetAvailableAdPositions(ctx context.Context, req *dto.GetAvailableAdPositionsReq) (res *dto.GetAvailableAdPositionsRes, err error) {
|
||||
func (c *adPosition) GetAvailableAdPositions(ctx context.Context, req *dto.GetAvailableAdPositionsReq) (res *dto.GetAvailableAdPositionsRes, err error) {
|
||||
list, err := service.AdPosition.GetAvailableAdPositions(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -58,7 +58,7 @@ func (c *cAdPosition) GetAvailableAdPositions(ctx context.Context, req *dto.GetA
|
||||
}
|
||||
|
||||
// MatchAd 匹配广告
|
||||
func (c *cAdPosition) MatchAd(ctx context.Context, req *dto.MatchAdReq) (res *dto.MatchAdRes, err error) {
|
||||
func (c *adPosition) MatchAd(ctx context.Context, req *dto.MatchAdReq) (res *dto.MatchAdRes, err error) {
|
||||
ad, err := service.AdPosition.MatchAd(ctx, req.PositionCode, req.UserInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -4,19 +4,20 @@ import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"cidService/model/dto"
|
||||
"cidService/service"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/service"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
var (
|
||||
AdSource = cAdSource{}
|
||||
AdSource = adSource{}
|
||||
)
|
||||
|
||||
type cAdSource struct{}
|
||||
type adSource struct{}
|
||||
|
||||
// Create 创建广告源
|
||||
func (c *cAdSource) Create(ctx context.Context, req *dto.CreateAdSourceReq) (res *dto.GetAdSourceRes, err error) {
|
||||
func (c *adSource) 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
|
||||
@@ -33,7 +34,7 @@ func (c *cAdSource) Create(ctx context.Context, req *dto.CreateAdSourceReq) (res
|
||||
}
|
||||
|
||||
// Update 更新广告源
|
||||
func (c *cAdSource) Update(ctx context.Context, req *dto.UpdateAdSourceReq) (res *dto.GetAdSourceRes, err error) {
|
||||
func (c *adSource) 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")
|
||||
@@ -58,7 +59,7 @@ func (c *cAdSource) Update(ctx context.Context, req *dto.UpdateAdSourceReq) (res
|
||||
}
|
||||
|
||||
// Delete 删除广告源
|
||||
func (c *cAdSource) Delete(ctx context.Context, req *dto.DeleteAdSourceReq) (res *dto.DeleteAdSourceRes, err error) {
|
||||
func (c *adSource) 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")
|
||||
@@ -78,7 +79,7 @@ func (c *cAdSource) Delete(ctx context.Context, req *dto.DeleteAdSourceReq) (res
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取广告源
|
||||
func (c *cAdSource) GetByID(ctx context.Context, req *dto.GetAdSourceReq) (res *dto.GetAdSourceRes, err error) {
|
||||
func (c *adSource) 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")
|
||||
@@ -98,7 +99,7 @@ func (c *cAdSource) GetByID(ctx context.Context, req *dto.GetAdSourceReq) (res *
|
||||
}
|
||||
|
||||
// GetList 获取广告源列表
|
||||
func (c *cAdSource) GetList(ctx context.Context, req *dto.ListAdSourceReq) (res *dto.ListAdSourceRes, err error) {
|
||||
func (c *adSource) GetList(ctx context.Context, req *dto.ListAdSourceReq) (res *dto.ListAdSourceRes, err error) {
|
||||
adSources, err := service.AdSource.GetAvailableSources(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -3,26 +3,26 @@ package controller
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidService/model/dto"
|
||||
"cidService/service"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/service"
|
||||
)
|
||||
|
||||
type cAdStatistics struct{}
|
||||
type adStatistics struct{}
|
||||
|
||||
var AdStatistics = &cAdStatistics{}
|
||||
var AdStatistics = &adStatistics{}
|
||||
|
||||
// GetStatistics 获取统计数据
|
||||
func (c *cAdStatistics) GetStatistics(ctx context.Context, req *dto.GetAdStatisticsReq) (res *dto.GetAdStatisticsRes, err error) {
|
||||
func (c *adStatistics) GetStatistics(ctx context.Context, req *dto.GetAdStatisticsReq) (res *dto.GetAdStatisticsRes, err error) {
|
||||
return service.AdStatistics.GetStatistics(ctx, req)
|
||||
}
|
||||
|
||||
// GetDashboard 获取仪表盘数据
|
||||
func (c *cAdStatistics) GetDashboard(ctx context.Context, req *dto.GetDashboardReq) (res *dto.GetDashboardRes, err error) {
|
||||
func (c *adStatistics) GetDashboard(ctx context.Context, req *dto.GetDashboardReq) (res *dto.GetDashboardRes, err error) {
|
||||
return service.AdStatistics.GetDashboard(ctx, req)
|
||||
}
|
||||
|
||||
// GenerateDailyStatistics 生成每日统计数据
|
||||
func (c *cAdStatistics) GenerateDailyStatistics(ctx context.Context, req *dto.GenerateDailyStatisticsReq) (res *dto.GenerateDailyStatisticsRes, err error) {
|
||||
func (c *adStatistics) GenerateDailyStatistics(ctx context.Context, req *dto.GenerateDailyStatisticsReq) (res *dto.GenerateDailyStatisticsRes, err error) {
|
||||
err = service.AdStatistics.GenerateDailyStatistics(ctx, req.Date)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"cidService/model/dto"
|
||||
"cidService/service"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/service"
|
||||
"context"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
)
|
||||
|
||||
type cAdvertisement struct{}
|
||||
type advertisement struct{}
|
||||
|
||||
var Advertisement = &cAdvertisement{}
|
||||
var Advertisement = &advertisement{}
|
||||
|
||||
// Add 添加广告
|
||||
func (c *cAdvertisement) Add(ctx context.Context, req *dto.AddAdvertisementReq) (res *dto.AddAdvertisementRes, err error) {
|
||||
func (c *advertisement) Add(ctx context.Context, req *dto.AddAdvertisementReq) (res *dto.AddAdvertisementRes, err error) {
|
||||
return service.Advertisement.Add(ctx, req)
|
||||
}
|
||||
|
||||
// Update 更新广告
|
||||
func (c *cAdvertisement) Update(ctx context.Context, req *dto.UpdateAdvertisementReq) (res *http.ResponseEmpty, err error) {
|
||||
func (c *advertisement) Update(ctx context.Context, req *dto.UpdateAdvertisementReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.Advertisement.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告状态
|
||||
func (c *cAdvertisement) UpdateStatus(ctx context.Context, req *dto.UpdateAdStatusReq) (res *http.ResponseEmpty, err error) {
|
||||
func (c *advertisement) UpdateStatus(ctx context.Context, req *dto.UpdateAdStatusReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.Advertisement.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// Audit 审核广告
|
||||
func (c *cAdvertisement) Audit(ctx context.Context, req *dto.AuditAdvertisementReq) (res *http.ResponseEmpty, err error) {
|
||||
func (c *advertisement) Audit(ctx context.Context, req *dto.AuditAdvertisementReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.Advertisement.Audit(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取广告详情
|
||||
func (c *cAdvertisement) GetOne(ctx context.Context, req *dto.GetAdvertisementReq) (res *dto.GetAdvertisementRes, err error) {
|
||||
func (c *advertisement) GetOne(ctx context.Context, req *dto.GetAdvertisementReq) (res *dto.GetAdvertisementRes, err error) {
|
||||
return service.Advertisement.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// List 获取广告列表
|
||||
func (c *cAdvertisement) List(ctx context.Context, req *dto.ListAdvertisementReq) (res *dto.ListAdvertisementRes, err error) {
|
||||
func (c *advertisement) List(ctx context.Context, req *dto.ListAdvertisementReq) (res *dto.ListAdvertisementRes, err error) {
|
||||
return service.Advertisement.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetStatistics 获取广告统计数据
|
||||
func (c *cAdvertisement) GetStatistics(ctx context.Context, req *dto.GetAdStatisticsForAdvertisementReq) (res *dto.GetAdStatisticsForAdvertisementRes, err error) {
|
||||
func (c *advertisement) GetStatistics(ctx context.Context, req *dto.GetAdStatisticsForAdvertisementReq) (res *dto.GetAdStatisticsForAdvertisementRes, err error) {
|
||||
return service.Advertisement.GetStatistics(ctx, req)
|
||||
}
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"cidService/model/dto"
|
||||
"cidService/service"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/service"
|
||||
"context"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
)
|
||||
|
||||
type cAdvertiser struct{}
|
||||
type advertiser struct{}
|
||||
|
||||
var Advertiser = &cAdvertiser{}
|
||||
var Advertiser = &advertiser{}
|
||||
|
||||
// Add 添加广告主
|
||||
func (c *cAdvertiser) Add(ctx context.Context, req *dto.AddAdvertiserReq) (res *dto.AddAdvertiserRes, err error) {
|
||||
func (c *advertiser) Add(ctx context.Context, req *dto.AddAdvertiserReq) (res *dto.AddAdvertiserRes, err error) {
|
||||
return service.Advertiser.Add(ctx, req)
|
||||
}
|
||||
|
||||
// Update 更新广告主
|
||||
func (c *cAdvertiser) Update(ctx context.Context, req *dto.UpdateAdvertiserReq) (res *http.ResponseEmpty, err error) {
|
||||
func (c *advertiser) Update(ctx context.Context, req *dto.UpdateAdvertiserReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.Advertiser.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告主状态
|
||||
func (c *cAdvertiser) UpdateStatus(ctx context.Context, req *dto.UpdateAdvertiserStatusReq) (res *http.ResponseEmpty, err error) {
|
||||
func (c *advertiser) UpdateStatus(ctx context.Context, req *dto.UpdateAdvertiserStatusReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.Advertiser.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// Audit 审核广告主
|
||||
func (c *cAdvertiser) Audit(ctx context.Context, req *dto.AuditAdvertiserReq) (res *http.ResponseEmpty, err error) {
|
||||
func (c *advertiser) Audit(ctx context.Context, req *dto.AuditAdvertiserReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.Advertiser.Audit(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// Recharge 充值
|
||||
func (c *cAdvertiser) Recharge(ctx context.Context, req *dto.RechargeAdvertiserReq) (res *http.ResponseEmpty, err error) {
|
||||
func (c *advertiser) Recharge(ctx context.Context, req *dto.RechargeAdvertiserReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.Advertiser.Recharge(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateCreditLimit 更新授信额度
|
||||
func (c *cAdvertiser) UpdateCreditLimit(ctx context.Context, req *dto.UpdateCreditLimitReq) (res *http.ResponseEmpty, err error) {
|
||||
func (c *advertiser) UpdateCreditLimit(ctx context.Context, req *dto.UpdateCreditLimitReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.Advertiser.UpdateCreditLimit(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取广告主详情
|
||||
func (c *cAdvertiser) GetOne(ctx context.Context, req *dto.GetAdvertiserReq) (res *dto.GetAdvertiserRes, err error) {
|
||||
func (c *advertiser) GetOne(ctx context.Context, req *dto.GetAdvertiserReq) (res *dto.GetAdvertiserRes, err error) {
|
||||
return service.Advertiser.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// List 获取广告主列表
|
||||
func (c *cAdvertiser) List(ctx context.Context, req *dto.ListAdvertiserReq) (res *dto.ListAdvertiserRes, err error) {
|
||||
func (c *advertiser) List(ctx context.Context, req *dto.ListAdvertiserReq) (res *dto.ListAdvertiserRes, err error) {
|
||||
return service.Advertiser.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetBalance 获取广告主余额
|
||||
func (c *cAdvertiser) GetBalance(ctx context.Context, req *dto.GetAdvertiserBalanceReq) (res *dto.GetAdvertiserBalanceRes, err error) {
|
||||
func (c *advertiser) GetBalance(ctx context.Context, req *dto.GetAdvertiserBalanceReq) (res *dto.GetAdvertiserBalanceRes, err error) {
|
||||
balance, creditLimit, err := service.Advertiser.GetBalance(ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
147
controller/application_controller.go
Normal file
147
controller/application_controller.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidservice/model/dto"
|
||||
"cidservice/service"
|
||||
)
|
||||
|
||||
var (
|
||||
Application = application{}
|
||||
)
|
||||
|
||||
type application struct{}
|
||||
|
||||
// CreateApplication 创建应用
|
||||
func (c *application) CreateApplication(ctx context.Context, req *dto.CreateApplicationReq) (res *dto.CreateApplicationRes, err error) {
|
||||
id, err := service.Application.CreateApplication(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.CreateApplicationRes{
|
||||
ID: id,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateApplication 更新应用
|
||||
func (c *application) UpdateApplication(ctx context.Context, req *dto.UpdateApplicationReq) (res *dto.UpdateApplicationRes, err error) {
|
||||
affected, err := service.Application.UpdateApplication(ctx, req.ID, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.UpdateApplicationRes{
|
||||
Success: affected > 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetApplication 获取应用信息
|
||||
func (c *application) GetApplication(ctx context.Context, req *dto.GetApplicationReq) (res *dto.GetApplicationRes, err error) {
|
||||
app, err := service.Application.GetApplicationByID(ctx, req.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.GetApplicationRes{
|
||||
ID: app.Id,
|
||||
TenantID: app.TenantId,
|
||||
Name: app.Name,
|
||||
Code: app.Code,
|
||||
Description: app.Description,
|
||||
Platform: app.Platform,
|
||||
PackageName: app.PackageName,
|
||||
AppStoreURL: app.AppStoreURL,
|
||||
Categories: app.Categories,
|
||||
Tags: app.Tags,
|
||||
AdTypes: app.AdTypes,
|
||||
Status: app.Status,
|
||||
AppKey: app.AppKey,
|
||||
CallbackURL: app.CallbackURL,
|
||||
CreatedAt: app.CreatedAt.Unix(),
|
||||
UpdatedAt: app.UpdatedAt.Unix(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListApplications 获取应用列表
|
||||
func (c *application) ListApplications(ctx context.Context, req *dto.ListApplicationsReq) (res *dto.ListApplicationsRes, err error) {
|
||||
list, total, err := service.Application.GetApplicationsByTenant(ctx, req.TenantID, req.Platform, req.Status, req.Page, req.Size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为响应格式
|
||||
appItems := make([]dto.ApplicationItem, len(list))
|
||||
for i, app := range list {
|
||||
appItems[i] = dto.ApplicationItem{
|
||||
ID: app.Id,
|
||||
Name: app.Name,
|
||||
Code: app.Code,
|
||||
Description: app.Description,
|
||||
Platform: app.Platform,
|
||||
PackageName: app.PackageName,
|
||||
Categories: app.Categories,
|
||||
Tags: app.Tags,
|
||||
AdTypes: app.AdTypes,
|
||||
Status: app.Status,
|
||||
DailyRequests: app.DailyRequests,
|
||||
MonthlyRequests: app.MonthlyRequests,
|
||||
CreatedAt: app.CreatedAt.Unix(),
|
||||
}
|
||||
}
|
||||
|
||||
return &dto.ListApplicationsRes{
|
||||
List: appItems,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ResetAPIKeys 重置API密钥
|
||||
func (c *application) ResetAPIKeys(ctx context.Context, req *dto.ResetAPIKeysReq) (res *dto.ResetAPIKeysRes, err error) {
|
||||
appKey, appSecret, err := service.Application.ResetAPIKeys(ctx, req.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.ResetAPIKeysRes{
|
||||
AppKey: appKey,
|
||||
AppSecret: appSecret,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ValidateApplication 验证应用权限
|
||||
func (c *application) ValidateApplication(ctx context.Context, req *dto.ValidateApplicationReq) (res *dto.ValidateApplicationRes, err error) {
|
||||
app, err := service.Application.ValidateApplication(ctx, req.AppKey, req.AppSecret)
|
||||
if err != nil {
|
||||
return &dto.ValidateApplicationRes{
|
||||
Valid: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
tentantName := ""
|
||||
|
||||
return &dto.ValidateApplicationRes{
|
||||
Valid: true,
|
||||
AppID: app.Id,
|
||||
AppName: app.Name,
|
||||
TenantID: app.TenantId,
|
||||
TenantName: tentantName,
|
||||
Platform: app.Platform,
|
||||
AdTypes: app.AdTypes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteApplication 删除应用
|
||||
func (c *application) DeleteApplication(ctx context.Context, req *dto.DeleteApplicationReq) (res *dto.DeleteApplicationRes, err error) {
|
||||
affected, err := service.Application.DeleteApplication(ctx, req.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.DeleteApplicationRes{
|
||||
Success: affected > 0,
|
||||
}, nil
|
||||
}
|
||||
@@ -3,19 +3,20 @@ package controller
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidService/model/dto"
|
||||
"cidService/service"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/service"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
var (
|
||||
CID = cCID{}
|
||||
CID = cid{}
|
||||
)
|
||||
|
||||
type cCID struct{}
|
||||
type cid struct{}
|
||||
|
||||
// GenerateCID 生成CID广告
|
||||
func (c *cCID) GenerateCID(ctx context.Context, req *dto.GenerateCIDReq) (res *dto.GenerateCIDRes, err error) {
|
||||
func (c *cid) GenerateCID(ctx context.Context, req *dto.GenerateCIDReq) (res *dto.GenerateCIDRes, err error) {
|
||||
if req == nil {
|
||||
return nil, gerror.New("请求参数不能为空")
|
||||
}
|
||||
@@ -33,7 +34,7 @@ func (c *cCID) GenerateCID(ctx context.Context, req *dto.GenerateCIDReq) (res *d
|
||||
}
|
||||
|
||||
// GetStatistics 获取CID统计信息
|
||||
func (c *cCID) GetStatistics(ctx context.Context, req *dto.GetCIDStatisticsReq) (res *dto.GetCIDStatisticsRes, err error) {
|
||||
func (c *cid) GetStatistics(ctx context.Context, req *dto.GetCIDStatisticsReq) (res *dto.GetCIDStatisticsRes, err error) {
|
||||
if req == nil {
|
||||
return nil, gerror.New("请求参数不能为空")
|
||||
}
|
||||
@@ -47,7 +48,7 @@ func (c *cCID) GetStatistics(ctx context.Context, req *dto.GetCIDStatisticsReq)
|
||||
}
|
||||
|
||||
// GetCIDHistory 获取CID历史记录
|
||||
func (c *cCID) GetCIDHistory(ctx context.Context, req *dto.GetCIDHistoryReq) (res *dto.GetCIDHistoryRes, err error) {
|
||||
func (c *cid) GetCIDHistory(ctx context.Context, req *dto.GetCIDHistoryReq) (res *dto.GetCIDHistoryRes, err error) {
|
||||
if req == nil {
|
||||
return nil, gerror.New("请求参数不能为空")
|
||||
}
|
||||
|
||||
39
controller/rate_limit_controller.go
Normal file
39
controller/rate_limit_controller.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidservice/model/dto"
|
||||
"cidservice/service"
|
||||
)
|
||||
|
||||
var (
|
||||
RateLimit = rateLimit{}
|
||||
)
|
||||
|
||||
type rateLimit struct{}
|
||||
|
||||
// SetTenantRateLimit 设置租户限流配置
|
||||
func (c *rateLimit) SetTenantRateLimit(ctx context.Context, req *dto.SetTenantRateLimitReq) (res *dto.SetTenantRateLimitRes, err error) {
|
||||
// 注意:实际使用的是config.yml中的全局配置,此接口仅用于兼容旧API
|
||||
// 实际限流参数请修改config.yml中的tenantRateLimit部分
|
||||
|
||||
return &dto.SetTenantRateLimitRes{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetTenantRateLimitUsage 获取租户限流使用情况
|
||||
func (c *rateLimit) GetTenantRateLimitUsage(ctx context.Context, req *dto.GetTenantRateLimitUsageReq) (res *dto.GetTenantRateLimitUsageRes, err error) {
|
||||
current, max, err := service.RateLimit.GetTenantCurrentUsage(ctx, req.TenantID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.GetTenantRateLimitUsageRes{
|
||||
TenantID: req.TenantID,
|
||||
CurrentUsed: current,
|
||||
MaxAllowed: max,
|
||||
UsagePercent: float64(current) / float64(max) * 100,
|
||||
}, nil
|
||||
}
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
|
||||
"cidService/model/dto"
|
||||
"cidService/service"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/service"
|
||||
)
|
||||
|
||||
type report struct{}
|
||||
@@ -31,12 +31,14 @@ func (c *report) List(ctx context.Context, req *dto.ListReportReq) (res *dto.Lis
|
||||
// Update 更新报表
|
||||
func (c *report) Update(ctx context.Context, req *dto.UpdateReportReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.Report.Update(ctx, req)
|
||||
res = &http.ResponseEmpty{}
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除报表
|
||||
func (c *report) Delete(ctx context.Context, req *dto.DeleteReportReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.Report.Delete(ctx, req)
|
||||
res = &http.ResponseEmpty{}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -48,5 +50,6 @@ func (c *report) Download(ctx context.Context, req *dto.DownloadReportReq) (res
|
||||
// Generate 生成报表
|
||||
func (c *report) Generate(ctx context.Context, req *dto.GenerateReportReq) (res *http.ResponseEmpty, err error) {
|
||||
err = service.Report.Generate(ctx, req)
|
||||
res = &http.ResponseEmpty{}
|
||||
return
|
||||
}
|
||||
|
||||
147
controller/stat_report_controller.go
Normal file
147
controller/stat_report_controller.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidservice/model/dto"
|
||||
"cidservice/service"
|
||||
)
|
||||
|
||||
var (
|
||||
StatReport = &statReport{}
|
||||
)
|
||||
|
||||
type statReport struct{}
|
||||
|
||||
// GenerateReport 生成报表
|
||||
func (c *statReport) GenerateReport(ctx context.Context, req *dto.ReportGenerateReq) (res *dto.ReportGenerateRes, err error) {
|
||||
var resp *dto.ReportGenerateResp
|
||||
|
||||
switch req.ReportType {
|
||||
case "daily":
|
||||
resp, err = service.StatReport.GenerateDailyReport(ctx, req)
|
||||
case "monthly":
|
||||
resp, err = service.StatReport.GenerateMonthlyReport(ctx, req)
|
||||
case "quarterly":
|
||||
resp, err = service.StatReport.GenerateQuarterlyReport(ctx, req)
|
||||
case "yearly":
|
||||
resp, err = service.StatReport.GenerateYearlyReport(ctx, req)
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.ReportGenerateRes{
|
||||
Data: resp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetReportList 获取报表列表
|
||||
func (c *statReport) GetReportList(ctx context.Context, req *dto.ReportListReq) (res *dto.ReportListRes, err error) {
|
||||
resp, err := service.StatReport.GetReportList(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.ReportListRes{
|
||||
Data: resp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetReportDetail 获取报表详情
|
||||
func (c *statReport) GetReportDetail(ctx context.Context, req *dto.ReportDetailReq) (res *dto.ReportDetailRes, err error) {
|
||||
resp, err := service.StatReport.GetReportDetail(ctx, req.ReportID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.ReportDetailRes{
|
||||
Data: resp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// QueryStats 统计查询
|
||||
func (c *statReport) QueryStats(ctx context.Context, req *dto.StatQueryReq) (res *dto.StatQueryRes, err error) {
|
||||
// 这里调用统计查询服务
|
||||
// resp, err := service.StatReport.QueryStats(ctx, req)
|
||||
// 暂时返回示例数据
|
||||
resp := &dto.StatQueryResp{
|
||||
Data: []*dto.StatDataPoint{
|
||||
{
|
||||
Date: "2024-01-01",
|
||||
Impressions: 1000,
|
||||
Clicks: 50,
|
||||
Revenue: 500.0,
|
||||
CTR: 5.0,
|
||||
AvgDuration: 30.5,
|
||||
},
|
||||
},
|
||||
Summary: &dto.StatSummary{
|
||||
TotalImpressions: 1000,
|
||||
TotalClicks: 50,
|
||||
TotalRevenue: 500.0,
|
||||
AvgCTR: 5.0,
|
||||
AvgDuration: 30.5,
|
||||
GrowthRate: &dto.GrowthRate{
|
||||
Impressions: 10.5,
|
||||
Clicks: 8.2,
|
||||
Revenue: 12.3,
|
||||
CTR: -1.2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return &dto.StatQueryRes{
|
||||
Data: resp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RealTimeStats 实时统计
|
||||
func (c *statReport) RealTimeStats(ctx context.Context, req *dto.RealTimeStatReq) (res *dto.RealTimeStatRes, err error) {
|
||||
// 这里调用实时统计服务
|
||||
// resp, err := service.StatReport.GetRealTimeStats(ctx, req)
|
||||
// 暂时返回示例数据
|
||||
resp := &dto.RealTimeStatResp{
|
||||
CurrentHour: &dto.HourlyStat{
|
||||
Hour: "14:00",
|
||||
Impressions: 120,
|
||||
Clicks: 6,
|
||||
Revenue: 60.0,
|
||||
},
|
||||
Last24Hours: []*dto.HourlyStat{
|
||||
{
|
||||
Hour: "13:00",
|
||||
Impressions: 110,
|
||||
Clicks: 5,
|
||||
Revenue: 55.0,
|
||||
},
|
||||
{
|
||||
Hour: "12:00",
|
||||
Impressions: 100,
|
||||
Clicks: 4,
|
||||
Revenue: 50.0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return &dto.RealTimeStatRes{
|
||||
Data: resp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportReport 导出报表
|
||||
func (c *statReport) ExportReport(ctx context.Context, req *dto.ReportDetailReq) (res *dto.ExportReportRes, err error) {
|
||||
// 获取报表详情
|
||||
resp, err := service.StatReport.GetReportDetail(ctx, req.ReportID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 返回导出数据,由上层处理HTTP响应
|
||||
return &dto.ExportReportRes{
|
||||
ReportData: resp,
|
||||
}, nil
|
||||
}
|
||||
@@ -3,19 +3,20 @@ package controller
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidService/model/dto"
|
||||
"cidService/service"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/service"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
var (
|
||||
Strategy = cStrategy{}
|
||||
Strategy = strategy{}
|
||||
)
|
||||
|
||||
type cStrategy struct{}
|
||||
type strategy struct{}
|
||||
|
||||
// Create 创建策略
|
||||
func (c *cStrategy) Create(ctx context.Context, req *dto.CreateStrategyReq) (res *dto.StrategyRes, err error) {
|
||||
func (c *strategy) 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
|
||||
@@ -30,7 +31,7 @@ func (c *cStrategy) Create(ctx context.Context, req *dto.CreateStrategyReq) (res
|
||||
}
|
||||
|
||||
// Update 更新策略
|
||||
func (c *cStrategy) Update(ctx context.Context, req *dto.UpdateStrategyReq) (res *dto.StrategyRes, err error) {
|
||||
func (c *strategy) 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
|
||||
@@ -48,7 +49,7 @@ func (c *cStrategy) Update(ctx context.Context, req *dto.UpdateStrategyReq) (res
|
||||
}
|
||||
|
||||
// Delete 删除策略
|
||||
func (c *cStrategy) Delete(ctx context.Context, req *dto.DeleteStrategyReq) (res *dto.DeleteStrategyRes, err error) {
|
||||
func (c *strategy) 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
|
||||
@@ -63,7 +64,7 @@ func (c *cStrategy) Delete(ctx context.Context, req *dto.DeleteStrategyReq) (res
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取策略
|
||||
func (c *cStrategy) GetByID(ctx context.Context, req *dto.GetStrategyReq) (res *dto.StrategyRes, err error) {
|
||||
func (c *strategy) 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
|
||||
@@ -73,6 +74,6 @@ func (c *cStrategy) GetByID(ctx context.Context, req *dto.GetStrategyReq) (res *
|
||||
}
|
||||
|
||||
// GetList 获取策略列表
|
||||
func (c *cStrategy) GetList(ctx context.Context, req *dto.GetStrategyListReq) (res *dto.GetStrategyListRes, err error) {
|
||||
func (c *strategy) GetList(ctx context.Context, req *dto.GetStrategyListReq) (res *dto.GetStrategyListRes, err error) {
|
||||
return service.Strategy.GetStrategyList(ctx, req)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
"context"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"cidService/model/entity"
|
||||
"context"
|
||||
|
||||
"cidservice/model/entity"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ package dao
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
|
||||
97
dao/application_dao.go
Normal file
97
dao/application_dao.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidservice/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// applicationDao 应用DAO
|
||||
type applicationDao struct{}
|
||||
|
||||
var Application = &applicationDao{}
|
||||
|
||||
// Ctx 获取数据库上下文
|
||||
func (d *applicationDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return g.DB().Model("application").Ctx(ctx)
|
||||
}
|
||||
|
||||
// Create 创建应用
|
||||
func (d *applicationDao) Create(ctx context.Context, app *entity.Application) (int64, error) {
|
||||
result, err := d.Ctx(ctx).Insert(app)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
id, _ := result.LastInsertId()
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取应用
|
||||
func (d *applicationDao) GetByID(ctx context.Context, id int64) (*entity.Application, error) {
|
||||
var app *entity.Application
|
||||
err := d.Ctx(ctx).Where("id", id).Scan(&app)
|
||||
return app, err
|
||||
}
|
||||
|
||||
// GetByTenantID 根据租户ID获取应用列表
|
||||
func (d *applicationDao) GetByTenantID(ctx context.Context, tenantID int64) ([]*entity.Application, error) {
|
||||
var apps []*entity.Application
|
||||
err := d.Ctx(ctx).Where("tenant_id", tenantID).Scan(&apps)
|
||||
return apps, err
|
||||
}
|
||||
|
||||
// GetByAPIKey 根据API密钥获取应用
|
||||
func (d *applicationDao) GetByAPIKey(ctx context.Context, apiKey string) (*entity.Application, error) {
|
||||
var app *entity.Application
|
||||
err := d.Ctx(ctx).Where("app_key", apiKey).Scan(&app)
|
||||
return app, err
|
||||
}
|
||||
|
||||
// Update 更新应用
|
||||
func (d *applicationDao) Update(ctx context.Context, app *entity.Application) error {
|
||||
_, err := d.Ctx(ctx).Where("id", app.Id).Update(app)
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete 删除应用
|
||||
func (d *applicationDao) Delete(ctx context.Context, id int64) error {
|
||||
_, err := d.Ctx(ctx).Where("id", id).Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
// List 应用列表
|
||||
func (d *applicationDao) List(ctx context.Context, tenantID int64, page, pageSize int) ([]*entity.Application, int, error) {
|
||||
model := d.Ctx(ctx)
|
||||
if tenantID > 0 {
|
||||
model = model.Where("tenant_id", tenantID)
|
||||
}
|
||||
|
||||
var apps []*entity.Application
|
||||
err := model.Page(page, pageSize).OrderDesc("created_at").Scan(&apps)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
total, err := model.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return apps, total, nil
|
||||
}
|
||||
|
||||
// GetByName 根据名称获取应用
|
||||
func (d *applicationDao) GetByName(ctx context.Context, name string) (*entity.Application, error) {
|
||||
var app *entity.Application
|
||||
err := d.Ctx(ctx).Where("name", name).Scan(&app)
|
||||
return app, err
|
||||
}
|
||||
|
||||
// UpdateFields 更新应用部分字段
|
||||
func (d *applicationDao) UpdateFields(ctx context.Context, id int64, data *entity.Application) error {
|
||||
_, err := d.Ctx(ctx).Where("id", id).Update(data)
|
||||
return err
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/entity"
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
@@ -3,8 +3,8 @@ package dao
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
90
dao/stat_report_dao.go
Normal file
90
dao/stat_report_dao.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidservice/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// statReportDao 统计报表DAO
|
||||
type statReportDao struct{}
|
||||
|
||||
var StatReport = &statReportDao{}
|
||||
|
||||
// Ctx 获取数据库上下文
|
||||
func (d *statReportDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return g.DB().Model("stat_report").Ctx(ctx)
|
||||
}
|
||||
|
||||
// Create 创建统计报表
|
||||
func (d *statReportDao) Create(ctx context.Context, report *entity.StatReport) (int64, error) {
|
||||
result, err := d.Ctx(ctx).Insert(report)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
id, _ := result.LastInsertId()
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取统计报表
|
||||
func (d *statReportDao) GetByID(ctx context.Context, id int64) (*entity.StatReport, error) {
|
||||
var report *entity.StatReport
|
||||
err := d.Ctx(ctx).Where("id", id).Scan(&report)
|
||||
return report, err
|
||||
}
|
||||
|
||||
// GetByTenantAndDate 根据租户和日期获取统计报表
|
||||
func (d *statReportDao) GetByTenantAndDate(ctx context.Context, tenantID int64, reportType, date string) (*entity.StatReport, error) {
|
||||
var report *entity.StatReport
|
||||
err := d.Ctx(ctx).Where("tenant_id", tenantID).Where("report_type", reportType).Where("report_date", date).Scan(&report)
|
||||
return report, err
|
||||
}
|
||||
|
||||
// Update 更新统计报表
|
||||
func (d *statReportDao) Update(ctx context.Context, report *entity.StatReport) error {
|
||||
_, err := d.Ctx(ctx).Where("id", report.Id).Update(report)
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete 删除统计报表
|
||||
func (d *statReportDao) Delete(ctx context.Context, id int64) error {
|
||||
_, err := d.Ctx(ctx).Where("id", id).Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
// List 统计报表列表
|
||||
func (d *statReportDao) List(ctx context.Context, tenantID, appID int64, reportType, startDate, endDate string, page, pageSize int) ([]*entity.StatReport, int, error) {
|
||||
model := d.Ctx(ctx)
|
||||
|
||||
if tenantID > 0 {
|
||||
model = model.Where("tenant_id", tenantID)
|
||||
}
|
||||
if appID > 0 {
|
||||
model = model.Where("app_id", appID)
|
||||
}
|
||||
if reportType != "" {
|
||||
model = model.Where("report_type", reportType)
|
||||
}
|
||||
if startDate != "" {
|
||||
model = model.WhereGTE("report_date", startDate)
|
||||
}
|
||||
if endDate != "" {
|
||||
model = model.WhereLTE("report_date", endDate)
|
||||
}
|
||||
|
||||
var reports []*entity.StatReport
|
||||
err := model.Page(page, pageSize).OrderDesc("generated_at").Scan(&reports)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
total, err := model.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return reports, total, nil
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/entity"
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
79
dao/tenant_dao.go
Normal file
79
dao/tenant_dao.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cidservice/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
var Tenant = tenantDao{}
|
||||
|
||||
type tenantDao struct{}
|
||||
|
||||
// Create 创建租户
|
||||
func (d *tenantDao) Create(ctx context.Context, tenant *entity.Tenant) (id int64, err error) {
|
||||
result, err := g.DB().Model("tenant").Ctx(ctx).Insert(tenant)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
id, _ = result.LastInsertId()
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取租户
|
||||
func (d *tenantDao) GetByID(ctx context.Context, id int64) (tenant *entity.Tenant, err error) {
|
||||
err = g.DB().Model("tenant").Ctx(ctx).Where("id = ? AND is_deleted = ?", id, false).Scan(&tenant)
|
||||
return
|
||||
}
|
||||
|
||||
// GetByCode 根据编码获取租户
|
||||
func (d *tenantDao) GetByCode(ctx context.Context, code string) (tenant *entity.Tenant, err error) {
|
||||
err = g.DB().Model("tenant").Ctx(ctx).Where("code = ? AND is_deleted = ?", code, false).Scan(&tenant)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateFields 更新租户字段
|
||||
func (d *tenantDao) UpdateFields(ctx context.Context, id int64, updateData *entity.Tenant) (affected int64, err error) {
|
||||
result, err := g.DB().Model("tenant").Ctx(ctx).Where("id = ? AND is_deleted = ?", id, false).Update(updateData)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
rowsAffected, _ := result.RowsAffected()
|
||||
return rowsAffected, nil
|
||||
}
|
||||
|
||||
// Delete 删除租户
|
||||
func (d *tenantDao) Delete(ctx context.Context, id int64) (affected int64, err error) {
|
||||
result, err := g.DB().Model("tenant").Ctx(ctx).Where("id = ?", id).Update(gdb.Map{"is_deleted": true})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
rowsAffected, _ := result.RowsAffected()
|
||||
return rowsAffected, nil
|
||||
}
|
||||
|
||||
// List 获取租户列表
|
||||
func (d *tenantDao) List(ctx context.Context, page, size int, filter map[string]interface{}) (list []*entity.Tenant, total int64, err error) {
|
||||
model := g.DB().Model("tenant").Ctx(ctx).Where("is_deleted = ?", false)
|
||||
|
||||
// 应用过滤条件
|
||||
if filter != nil {
|
||||
for key, value := range filter {
|
||||
model = model.Where(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
count, err := model.Count()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
total = int64(count)
|
||||
|
||||
// 分页查询
|
||||
err = model.Page(page, size).OrderDesc("created_at").Scan(&list)
|
||||
return
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
-- 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;
|
||||
4
go.mod
4
go.mod
@@ -1,4 +1,4 @@
|
||||
module cidService
|
||||
module cidservice
|
||||
|
||||
go 1.25.3
|
||||
|
||||
@@ -10,7 +10,7 @@ require (
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0
|
||||
golang.org/x/net v0.47.0
|
||||
)
|
||||
|
||||
replace gitee.com/red-future---jilin-g/common v0.1.9 => ../common
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/armon/go-metrics v0.4.1 // indirect
|
||||
|
||||
5
main.go
5
main.go
@@ -1,7 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"cidService/controller"
|
||||
"cidservice/controller"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"gitee.com/red-future---jilin-g/common/jaeger"
|
||||
@@ -20,6 +20,9 @@ func main() {
|
||||
controller.AdPosition,
|
||||
controller.AdStatistics,
|
||||
controller.Report,
|
||||
//controller.RateLimit,
|
||||
//controller.Application,
|
||||
//controller.StatReport,
|
||||
})
|
||||
select {}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/entity"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
// AddAdPositionReq 添加广告位请求
|
||||
type AddAdPositionReq struct {
|
||||
g.Meta `path:"/adposition/add" method:"post" tags:"广告位管理" summary:"添加广告位" dc:"添加新的广告位"`
|
||||
g.Meta `path:"/add" method:"post" tags:"广告位管理" summary:"添加广告位" dc:"添加新的广告位"`
|
||||
|
||||
// 基本信息
|
||||
Name string `json:"name" v:"required"` // 广告位名称
|
||||
@@ -51,7 +51,7 @@ type AddAdPositionRes struct {
|
||||
|
||||
// UpdateAdPositionReq 更新广告位请求
|
||||
type UpdateAdPositionReq struct {
|
||||
g.Meta `path:"/adposition/update" method:"post" tags:"广告位管理" summary:"更新广告位" dc:"更新广告位信息"`
|
||||
g.Meta `path:"/update" method:"put" tags:"广告位管理" summary:"更新广告位" dc:"更新广告位信息"`
|
||||
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
|
||||
@@ -91,7 +91,7 @@ type UpdateAdPositionReq struct {
|
||||
|
||||
// GetAdPositionReq 获取广告位详情请求
|
||||
type GetAdPositionReq struct {
|
||||
g.Meta `path:"/adposition/one" method:"get" tags:"广告位管理" summary:"获取广告位详情" dc:"根据ID获取单个广告位详情"`
|
||||
g.Meta `path:"/one" method:"get" tags:"广告位管理" summary:"获取广告位详情" dc:"根据ID获取单个广告位详情"`
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ type GetAdPositionRes struct {
|
||||
|
||||
// ListAdPositionReq 获取广告位列表请求
|
||||
type ListAdPositionReq struct {
|
||||
g.Meta `path:"/adposition/list" method:"get" tags:"广告位管理" summary:"获取广告位列表" dc:"分页查询广告位列表,支持多条件筛选"`
|
||||
g.Meta `path:"/list" method:"get" tags:"广告位管理" summary:"获取广告位列表" dc:"分页查询广告位列表,支持多条件筛选"`
|
||||
http.Page
|
||||
|
||||
Name string `json:"name"` // 广告位名称模糊查询
|
||||
@@ -120,7 +120,7 @@ type ListAdPositionRes struct {
|
||||
|
||||
// UpdateAdPositionStatusReq 更新广告位状态请求
|
||||
type UpdateAdPositionStatusReq struct {
|
||||
g.Meta `path:"/adposition/status" method:"post" tags:"广告位管理" summary:"更新广告位状态" dc:"更新广告位状态"`
|
||||
g.Meta `path:"/updateStatus" method:"patch" tags:"广告位管理" summary:"更新广告位状态" dc:"更新广告位状态"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告位ID
|
||||
Status string `json:"status" v:"required"` // 广告位状态:启用、禁用、测试
|
||||
@@ -128,7 +128,7 @@ type UpdateAdPositionStatusReq struct {
|
||||
|
||||
// GetAdPositionStatisticsReq 获取广告位统计数据请求
|
||||
type GetAdPositionStatisticsReq struct {
|
||||
g.Meta `path:"/adposition/statistics" method:"get" tags:"广告位管理" summary:"获取广告位统计数据" dc:"获取广告位的统计数据"`
|
||||
g.Meta `path:"getStatisticsAdPosition" method:"get" tags:"广告位管理" summary:"获取广告位统计数据" dc:"获取广告位的统计数据"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告位ID
|
||||
StatType string `json:"statType" v:"required"` // 统计类型:天、周、月
|
||||
@@ -143,7 +143,7 @@ type GetAdPositionStatisticsRes struct {
|
||||
|
||||
// GetAvailableAdPositionsReq 获取可用广告位请求
|
||||
type GetAvailableAdPositionsReq struct {
|
||||
g.Meta `path:"/adposition/available" method:"get" tags:"广告位管理" summary:"获取可用广告位列表" dc:"获取所有启用的广告位列表"`
|
||||
g.Meta `path:"getAvailableAdPositions" method:"get" tags:"广告位管理" summary:"获取可用广告位列表" dc:"获取所有启用的广告位列表"`
|
||||
}
|
||||
|
||||
type GetAvailableAdPositionsRes struct {
|
||||
@@ -152,7 +152,7 @@ type GetAvailableAdPositionsRes struct {
|
||||
|
||||
// MatchAdReq 匹配广告请求
|
||||
type MatchAdReq struct {
|
||||
g.Meta `path:"/adposition/match" method:"post" tags:"广告位管理" summary:"匹配广告" dc:"根据广告位编码和用户信息匹配适合的广告"`
|
||||
g.Meta `path:"matchAdAdPosition" method:"post" tags:"广告位管理" summary:"匹配广告" dc:"根据广告位编码和用户信息匹配适合的广告"`
|
||||
|
||||
PositionCode string `json:"positionCode" v:"required"` // 广告位编码
|
||||
UserInfo map[string]interface{} `json:"userInfo"` // 用户信息
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/entity"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
// CreateAdSourceReq 创建广告源请求
|
||||
type CreateAdSourceReq struct {
|
||||
g.Meta `path:"/adsource/create" method:"post" tags:"广告源管理" summary:"创建广告源" dc:"创建新的广告源配置"`
|
||||
g.Meta `path:"createAdSource" method:"post" tags:"广告源管理" summary:"创建广告源" dc:"创建新的广告源配置"`
|
||||
|
||||
// 基本信息
|
||||
Name string `json:"name" v:"required"` // 广告源名称
|
||||
@@ -69,7 +69,7 @@ type CreateAdSourceRes struct {
|
||||
|
||||
// GetAdSourceReq 获取广告源详情请求
|
||||
type GetAdSourceReq struct {
|
||||
g.Meta `path:"/adsource/one" method:"get" tags:"广告源管理" summary:"获取广告源详情" dc:"根据ID获取单个广告源详情"`
|
||||
g.Meta `path:"getByIDAdSource" method:"get" tags:"广告源管理" summary:"获取广告源详情" dc:"根据ID获取单个广告源详情"`
|
||||
Id string `json:"id" v:"required"` // 广告源ID
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ type GetAdSourceRes struct {
|
||||
|
||||
// ListAdSourceReq 获取广告源列表请求
|
||||
type ListAdSourceReq struct {
|
||||
g.Meta `path:"/adsource/list" method:"get" tags:"广告源管理" summary:"获取广告源列表" dc:"分页查询广告源列表,支持多条件筛选"`
|
||||
g.Meta `path:"getListAdSource" method:"get" tags:"广告源管理" summary:"获取广告源列表" dc:"分页查询广告源列表,支持多条件筛选"`
|
||||
http.Page
|
||||
|
||||
Name string `json:"name"` // 广告源名称模糊查询
|
||||
@@ -97,7 +97,7 @@ type ListAdSourceRes struct {
|
||||
|
||||
// UpdateAdSourceReq 更新广告源请求
|
||||
type UpdateAdSourceReq struct {
|
||||
g.Meta `path:"/adsource/update" method:"post" tags:"广告源管理" summary:"更新广告源" dc:"更新广告源信息"`
|
||||
g.Meta `path:"updateAdSource" method:"put" tags:"广告源管理" summary:"更新广告源" dc:"更新广告源信息"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告源ID
|
||||
|
||||
@@ -152,7 +152,7 @@ type UpdateAdSourceReq struct {
|
||||
|
||||
// UpdateAdSourceStatusReq 更新广告源状态请求
|
||||
type UpdateAdSourceStatusReq struct {
|
||||
g.Meta `path:"/adsource/status" method:"post" tags:"广告源管理" summary:"更新广告源状态" dc:"更新广告源状态"`
|
||||
g.Meta `path:"/adsource" method:"patch" tags:"广告源管理" summary:"更新广告源状态" dc:"更新广告源状态"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告源ID
|
||||
Status string `json:"status" v:"required"` // 广告源状态:active、inactive、maintenance
|
||||
@@ -160,14 +160,14 @@ type UpdateAdSourceStatusReq struct {
|
||||
|
||||
// DeleteAdSourceReq 删除广告源请求
|
||||
type DeleteAdSourceReq struct {
|
||||
g.Meta `path:"/adsource/delete" method:"post" tags:"广告源管理" summary:"删除广告源" dc:"删除指定的广告源"`
|
||||
g.Meta `path:"deleteAdSource" method:"delete" tags:"广告源管理" summary:"删除广告源" dc:"删除指定的广告源"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告源ID
|
||||
}
|
||||
|
||||
// TestAdSourceReq 测试广告源连接请求
|
||||
type TestAdSourceReq struct {
|
||||
g.Meta `path:"/adsource/test" method:"post" tags:"广告源管理" summary:"测试广告源连接" dc:"测试广告源的连接性和可用性"`
|
||||
g.Meta `path:"/adsource-test" method:"post" tags:"广告源管理" summary:"测试广告源连接" dc:"测试广告源的连接性和可用性"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告源ID
|
||||
}
|
||||
@@ -195,7 +195,7 @@ type AdSourceTestMetrics struct {
|
||||
|
||||
// GetAdSourceStatisticsReq 获取广告源统计数据请求
|
||||
type GetAdSourceStatisticsReq struct {
|
||||
g.Meta `path:"/adsource/statistics" method:"get" tags:"广告源管理" summary:"获取广告源统计数据" dc:"获取广告源的详细统计数据"`
|
||||
g.Meta `path:"/adsource-statistics" method:"get" tags:"广告源管理" summary:"获取广告源统计数据" dc:"获取广告源的详细统计数据"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告源ID
|
||||
StartDate int64 `json:"startDate" v:"required"` // 开始日期
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/entity"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
// GetAdStatisticsReq 获取广告统计数据请求
|
||||
type GetAdStatisticsReq struct {
|
||||
g.Meta `path:"/statistics/list" method:"get" tags:"广告统计" summary:"获取广告统计数据" dc:"获取广告的统计数据"`
|
||||
g.Meta `path:"getStatisticsAdStatistics" method:"get" tags:"广告统计" summary:"获取广告统计数据" dc:"获取广告的统计数据"`
|
||||
|
||||
// 分页参数
|
||||
http.Page
|
||||
@@ -42,7 +42,7 @@ type GetAdStatisticsRes struct {
|
||||
|
||||
// GetDashboardReq 获取仪表盘数据请求
|
||||
type GetDashboardReq struct {
|
||||
g.Meta `path:"/dashboard" method:"get" tags:"广告仪表盘" summary:"获取仪表盘数据" dc:"获取广告系统的仪表盘统计数据"`
|
||||
g.Meta `path:"getDashboardAdStatistics" method:"get" tags:"广告仪表盘" summary:"获取仪表盘数据" dc:"获取广告系统的仪表盘统计数据"`
|
||||
|
||||
// 时间范围
|
||||
StartDate int64 `json:"startDate" v:"required"` // 开始日期
|
||||
@@ -103,7 +103,7 @@ type RankData struct {
|
||||
|
||||
// GenerateDailyStatisticsReq 生成每日统计数据请求
|
||||
type GenerateDailyStatisticsReq struct {
|
||||
g.Meta `path:"/statistics/generate-daily" method:"post" tags:"广告统计" summary:"生成每日统计数据" dc:"手动生成指定日期的广告统计数据"`
|
||||
g.Meta `path:"generateDailyStatisticsAdStatistics" method:"post" tags:"广告统计" summary:"生成每日统计数据" dc:"手动生成指定日期的广告统计数据"`
|
||||
|
||||
Date int64 `json:"date" v:"required"` // 日期时间戳
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/entity"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
// AddAdvertisementReq 添加广告请求
|
||||
type AddAdvertisementReq struct {
|
||||
g.Meta `path:"/advertisement/add" method:"post" tags:"广告管理" summary:"添加广告" dc:"添加新的广告"`
|
||||
g.Meta `path:"addAdvertisement" method:"post" tags:"广告管理" summary:"添加广告" dc:"添加新的广告"`
|
||||
|
||||
// 广告基本信息
|
||||
Title string `json:"title" v:"required"` // 广告标题
|
||||
@@ -40,7 +40,7 @@ type AddAdvertisementRes struct {
|
||||
|
||||
// UpdateAdvertisementReq 更新广告请求
|
||||
type UpdateAdvertisementReq struct {
|
||||
g.Meta `path:"/advertisement/update" method:"post" tags:"广告管理" summary:"更新广告" dc:"更新广告信息"`
|
||||
g.Meta `path:"updateAdvertisement" method:"put" tags:"广告管理" summary:"更新广告" dc:"更新广告信息"`
|
||||
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
|
||||
@@ -74,7 +74,7 @@ type UpdateAdvertisementReq struct {
|
||||
|
||||
// GetAdvertisementReq 获取广告详情请求
|
||||
type GetAdvertisementReq struct {
|
||||
g.Meta `path:"/advertisement/one" method:"get" tags:"广告管理" summary:"获取广告详情" dc:"根据ID获取单个广告详情"`
|
||||
g.Meta `path:"getOneAdvertisement" method:"get" tags:"广告管理" summary:"获取广告详情" dc:"根据ID获取单个广告详情"`
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ type GetAdvertisementRes struct {
|
||||
|
||||
// ListAdvertisementReq 获取广告列表请求
|
||||
type ListAdvertisementReq struct {
|
||||
g.Meta `path:"/advertisement/list" method:"get" tags:"广告管理" summary:"获取广告列表" dc:"分页查询广告列表,支持多条件筛选"`
|
||||
g.Meta `path:"listAdvertisement" method:"get" tags:"广告管理" summary:"获取广告列表" dc:"分页查询广告列表,支持多条件筛选"`
|
||||
http.Page
|
||||
|
||||
AdvertiserId string `json:"advertiserId"` // 广告主ID
|
||||
@@ -103,7 +103,7 @@ type ListAdvertisementRes struct {
|
||||
|
||||
// AuditAdvertisementReq 审核广告请求
|
||||
type AuditAdvertisementReq struct {
|
||||
g.Meta `path:"/advertisement/audit" method:"post" tags:"广告管理" summary:"审核广告" dc:"审核广告,通过或拒绝"`
|
||||
g.Meta `path:"auditAdvertisement" method:"post" tags:"广告管理" summary:"审核广告" dc:"审核广告,通过或拒绝"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告ID
|
||||
AuditStatus string `json:"auditStatus" v:"required"` // 审核状态:通过、拒绝
|
||||
@@ -112,7 +112,7 @@ type AuditAdvertisementReq struct {
|
||||
|
||||
// UpdateAdStatusReq 更新广告状态请求
|
||||
type UpdateAdStatusReq struct {
|
||||
g.Meta `path:"/advertisement/status" method:"post" tags:"广告管理" summary:"更新广告状态" dc:"更新广告状态"`
|
||||
g.Meta `path:"updateStatusAdvertisement" method:"patch" tags:"广告管理" summary:"更新广告状态" dc:"更新广告状态"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告ID
|
||||
Status string `json:"status" v:"required"` // 广告状态:启用、禁用
|
||||
@@ -120,7 +120,7 @@ type UpdateAdStatusReq struct {
|
||||
|
||||
// GetAdStatisticsReq 获取广告统计数据请求
|
||||
type GetAdStatisticsForAdvertisementReq struct {
|
||||
g.Meta `path:"/advertisement/statistics" method:"get" tags:"广告管理" summary:"获取广告统计数据" dc:"获取广告的统计数据"`
|
||||
g.Meta `path:"getStatisticsAdvertisement" method:"get" tags:"广告管理" summary:"获取广告统计数据" dc:"获取广告的统计数据"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告ID
|
||||
StatType string `json:"statType" v:"required"` // 统计类型:天、周、月
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/entity"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
// AddAdvertiserReq 添加广告主请求
|
||||
type AddAdvertiserReq struct {
|
||||
g.Meta `path:"/advertiser/add" method:"post" tags:"广告主管理" summary:"添加广告主" dc:"添加新的广告主"`
|
||||
g.Meta `path:"addAdvertiser" method:"post" tags:"广告主管理" summary:"添加广告主" dc:"添加新的广告主"`
|
||||
|
||||
// 基本信息
|
||||
Name string `json:"name" v:"required"` // 广告主名称
|
||||
@@ -49,7 +49,7 @@ type AddAdvertiserRes struct {
|
||||
|
||||
// UpdateAdvertiserReq 更新广告主请求
|
||||
type UpdateAdvertiserReq struct {
|
||||
g.Meta `path:"/advertiser/update" method:"post" tags:"广告主管理" summary:"更新广告主" dc:"更新广告主信息"`
|
||||
g.Meta `path:"updateAdvertiser" method:"put" tags:"广告主管理" summary:"更新广告主" dc:"更新广告主信息"`
|
||||
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
|
||||
@@ -92,7 +92,7 @@ type UpdateAdvertiserReq struct {
|
||||
|
||||
// GetAdvertiserReq 获取广告主详情请求
|
||||
type GetAdvertiserReq struct {
|
||||
g.Meta `path:"/advertiser/one" method:"get" tags:"广告主管理" summary:"获取广告主详情" dc:"根据ID获取单个广告主详情"`
|
||||
g.Meta `path:"getOneAdvertiser" method:"get" tags:"广告主管理" summary:"获取广告主详情" dc:"根据ID获取单个广告主详情"`
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ type GetAdvertiserRes struct {
|
||||
|
||||
// ListAdvertiserReq 获取广告主列表请求
|
||||
type ListAdvertiserReq struct {
|
||||
g.Meta `path:"/advertiser/list" method:"get" tags:"广告主管理" summary:"获取广告主列表" dc:"分页查询广告主列表,支持多条件筛选"`
|
||||
g.Meta `path:"listAdvertiser" method:"get" tags:"广告主管理" summary:"获取广告主列表" dc:"分页查询广告主列表,支持多条件筛选"`
|
||||
http.Page
|
||||
|
||||
Name string `json:"name"` // 广告主名称模糊查询
|
||||
@@ -121,7 +121,7 @@ type ListAdvertiserRes struct {
|
||||
|
||||
// AuditAdvertiserReq 审核广告主请求
|
||||
type AuditAdvertiserReq struct {
|
||||
g.Meta `path:"/advertiser/audit" method:"post" tags:"广告主管理" summary:"审核广告主" dc:"审核广告主,通过或拒绝"`
|
||||
g.Meta `path:"auditAdvertiser" method:"post" tags:"广告主管理" summary:"审核广告主" dc:"审核广告主,通过或拒绝"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告主ID
|
||||
AuditStatus string `json:"auditStatus" v:"required"` // 审核状态:通过、拒绝
|
||||
@@ -130,7 +130,7 @@ type AuditAdvertiserReq struct {
|
||||
|
||||
// UpdateAdvertiserStatusReq 更新广告主状态请求
|
||||
type UpdateAdvertiserStatusReq struct {
|
||||
g.Meta `path:"/advertiser/status" method:"post" tags:"广告主管理" summary:"更新广告主状态" dc:"更新广告主状态"`
|
||||
g.Meta `path:"updateStatusAdvertiser" method:"patch" tags:"广告主管理" summary:"更新广告主状态" dc:"更新广告主状态"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告主ID
|
||||
Status string `json:"status" v:"required"` // 广告主状态:启用、禁用、冻结
|
||||
@@ -138,7 +138,7 @@ type UpdateAdvertiserStatusReq struct {
|
||||
|
||||
// RechargeAdvertiserReq 广告主充值请求
|
||||
type RechargeAdvertiserReq struct {
|
||||
g.Meta `path:"/advertiser/recharge" method:"post" tags:"广告主管理" summary:"广告主充值" dc:"为广告主账户充值"`
|
||||
g.Meta `path:"rechargeAdvertiser" method:"post" tags:"广告主管理" summary:"广告主充值" dc:"为广告主账户充值"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告主ID
|
||||
Amount int64 `json:"amount" v:"required"` // 充值金额(分)
|
||||
@@ -147,7 +147,7 @@ type RechargeAdvertiserReq struct {
|
||||
|
||||
// UpdateCreditLimitReq 更新授信额度请求
|
||||
type UpdateCreditLimitReq struct {
|
||||
g.Meta `path:"/advertiser/credit" method:"post" tags:"广告主管理" summary:"更新授信额度" dc:"更新广告主的授信额度"`
|
||||
g.Meta `path:"updateCreditLimitAdvertiser" method:"post" tags:"广告主管理" summary:"更新授信额度" dc:"更新广告主的授信额度"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告主ID
|
||||
CreditLimit int64 `json:"creditLimit" v:"required"` // 授信额度(分)
|
||||
@@ -156,7 +156,7 @@ type UpdateCreditLimitReq struct {
|
||||
|
||||
// GetAdvertiserBalanceReq 获取广告主余额请求
|
||||
type GetAdvertiserBalanceReq struct {
|
||||
g.Meta `path:"/advertiser/balance" method:"get" tags:"广告主管理" summary:"获取广告主余额" dc:"根据ID获取广告主账户余额和授信额度"`
|
||||
g.Meta `path:"getBalanceAdvertiser" method:"get" tags:"广告主管理" summary:"获取广告主余额" dc:"根据ID获取广告主账户余额和授信额度"`
|
||||
Id string `json:"id" v:"required"` // 广告主ID
|
||||
}
|
||||
|
||||
|
||||
157
model/dto/application_dto.go
Normal file
157
model/dto/application_dto.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreateApplicationReq 创建应用请求
|
||||
type CreateApplicationReq struct {
|
||||
g.Meta `path:"createApplication" method:"post" summary:"创建应用"`
|
||||
|
||||
TenantID int64 `json:"tenantId" v:"required#租户ID不能为空"`
|
||||
Name string `json:"name" v:"required#应用名称不能为空"`
|
||||
Code string `json:"code" v:"required#应用编码不能为空"`
|
||||
Description string `json:"description"`
|
||||
Platform string `json:"platform" v:"required#平台不能为空|in:web,h5,android,ios#平台类型错误"`
|
||||
PackageName string `json:"packageName"`
|
||||
AppStoreURL string `json:"appStoreUrl"`
|
||||
Categories []string `json:"categories"`
|
||||
Tags []string `json:"tags"`
|
||||
AdTypes []string `json:"adTypes"`
|
||||
CallbackURL string `json:"callbackUrl"`
|
||||
}
|
||||
|
||||
// CreateApplicationRes 创建应用响应
|
||||
type CreateApplicationRes struct {
|
||||
ID int64 `json:"id"`
|
||||
AppKey string `json:"appKey"`
|
||||
AppSecret string `json:"appSecret"`
|
||||
}
|
||||
|
||||
// UpdateApplicationReq 更新应用请求
|
||||
type UpdateApplicationReq struct {
|
||||
g.Meta `path:"updateApplication" method:"put" summary:"更新应用"`
|
||||
|
||||
ID int64 `json:"id" v:"required#应用ID不能为空"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Platform string `json:"platform" v:"in:web,h5,android,ios#平台类型错误"`
|
||||
PackageName string `json:"packageName"`
|
||||
AppStoreURL string `json:"appStoreUrl"`
|
||||
Categories []string `json:"categories"`
|
||||
Tags []string `json:"tags"`
|
||||
AdTypes []string `json:"adTypes"`
|
||||
CallbackURL string `json:"callbackUrl"`
|
||||
}
|
||||
|
||||
// UpdateApplicationRes 更新应用响应
|
||||
type UpdateApplicationRes struct {
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
// GetApplicationReq 获取应用请求
|
||||
type GetApplicationReq struct {
|
||||
g.Meta `path:"getApplication" method:"get" summary:"获取应用信息"`
|
||||
|
||||
ID int64 `json:"id" v:"required#应用ID不能为空"`
|
||||
}
|
||||
|
||||
// GetApplicationRes 获取应用响应
|
||||
type GetApplicationRes struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenantId"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Description string `json:"description"`
|
||||
Platform string `json:"platform"`
|
||||
PackageName string `json:"packageName"`
|
||||
AppStoreURL string `json:"appStoreUrl"`
|
||||
Categories []string `json:"categories"`
|
||||
Tags []string `json:"tags"`
|
||||
AdTypes []string `json:"adTypes"`
|
||||
Status string `json:"status"`
|
||||
AppKey string `json:"appKey"`
|
||||
CallbackURL string `json:"callbackUrl"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// ListApplicationsReq 获取应用列表请求
|
||||
type ListApplicationsReq struct {
|
||||
g.Meta `path:"listApplications" method:"get" summary:"获取应用列表"`
|
||||
|
||||
TenantID int64 `json:"tenantId" v:"required#租户ID不能为空"`
|
||||
Platform string `json:"platform"`
|
||||
Status string `json:"status"`
|
||||
Page int `json:"page" d:"1"`
|
||||
Size int `json:"size" d:"20"`
|
||||
}
|
||||
|
||||
// ListApplicationsRes 获取应用列表响应
|
||||
type ListApplicationsRes struct {
|
||||
List []ApplicationItem `json:"list"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
Size int `json:"size"`
|
||||
}
|
||||
|
||||
// ApplicationItem 应用列表项
|
||||
type ApplicationItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Description string `json:"description"`
|
||||
Platform string `json:"platform"`
|
||||
PackageName string `json:"packageName"`
|
||||
Categories []string `json:"categories"`
|
||||
Tags []string `json:"tags"`
|
||||
AdTypes []string `json:"adTypes"`
|
||||
Status string `json:"status"`
|
||||
DailyRequests int64 `json:"dailyRequests"`
|
||||
MonthlyRequests int64 `json:"monthlyRequests"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
}
|
||||
|
||||
// ResetAPIKeysReq 重置API密钥请求
|
||||
type ResetAPIKeysReq struct {
|
||||
g.Meta `path:"/applications-reset-keys" method:"post" summary:"重置API密钥"`
|
||||
|
||||
ID int64 `json:"id" v:"required#应用ID不能为空"`
|
||||
}
|
||||
|
||||
// ResetAPIKeysRes 重置API密钥响应
|
||||
type ResetAPIKeysRes struct {
|
||||
AppKey string `json:"appKey"`
|
||||
AppSecret string `json:"appSecret"`
|
||||
}
|
||||
|
||||
// ValidateApplicationReq 验证应用请求
|
||||
type ValidateApplicationReq struct {
|
||||
g.Meta `path:"/applications-validate" method:"post" summary:"验证应用权限"`
|
||||
|
||||
AppKey string `json:"appKey" v:"required#应用密钥不能为空"`
|
||||
AppSecret string `json:"appSecret" v:"required#应用密钥不能为空"`
|
||||
}
|
||||
|
||||
// ValidateApplicationRes 验证应用响应
|
||||
type ValidateApplicationRes struct {
|
||||
Valid bool `json:"valid"`
|
||||
AppID int64 `json:"appId"`
|
||||
AppName string `json:"appName"`
|
||||
TenantID int64 `json:"tenantId"`
|
||||
TenantName string `json:"tenantName"`
|
||||
Platform string `json:"platform"`
|
||||
AdTypes []string `json:"adTypes"`
|
||||
}
|
||||
|
||||
// DeleteApplicationReq 删除应用请求
|
||||
type DeleteApplicationReq struct {
|
||||
g.Meta `path:"/applications" method:"delete" summary:"删除应用"`
|
||||
|
||||
ID int64 `json:"id" v:"required#应用ID不能为空"`
|
||||
}
|
||||
|
||||
// DeleteApplicationRes 删除应用响应
|
||||
type DeleteApplicationRes struct {
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
// GenerateCIDReq 生成CID请求
|
||||
type GenerateCIDReq struct {
|
||||
g.Meta `path:"/cid/generate" method:"post" tags:"CID服务" summary:"生成CID广告" dc:"为当前用户生成CID广告"`
|
||||
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"` // 请求参数
|
||||
@@ -38,7 +38,7 @@ type GenerateCIDRes struct {
|
||||
|
||||
// GetCIDStatisticsReq 获取CID统计请求
|
||||
type GetCIDStatisticsReq struct {
|
||||
g.Meta `path:"/cid/statistics" method:"get" tags:"CID服务" summary:"获取CID统计" dc:"获取CID服务的统计信息"`
|
||||
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"` // 开始日期
|
||||
@@ -67,7 +67,7 @@ type CIDRequestHistory struct {
|
||||
|
||||
// GetCIDHistoryReq 获取CID历史请求
|
||||
type GetCIDHistoryReq struct {
|
||||
g.Meta `path:"/cid/history" method:"get" tags:"CID服务" summary:"获取CID历史记录" dc:"分页获取用户的CID请求历史"`
|
||||
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"` // 每页数量
|
||||
}
|
||||
|
||||
35
model/dto/rate_limit_dto.go
Normal file
35
model/dto/rate_limit_dto.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// SetTenantRateLimitReq 设置租户限流配置请求
|
||||
type SetTenantRateLimitReq struct {
|
||||
g.Meta `path:"/ratelimit-tenant-set" method:"post" tags:"租户限流" summary:"设置租户限流配置" dc:"设置指定租户的请求次数限制配置(实际使用全局配置)"`
|
||||
|
||||
TenantID int64 `json:"tenant_id" v:"required"` // 租户ID(仅用于记录,实际使用全局配置)
|
||||
RequestsPerSecond float64 `json:"requests_per_second" v:"required"` // 每秒请求数
|
||||
Burst int `json:"burst" v:"required"` // 突发请求数
|
||||
WindowSeconds int `json:"window_seconds" v:"required"` // 时间窗口(秒)
|
||||
}
|
||||
|
||||
// SetTenantRateLimitRes 设置租户限流配置响应
|
||||
type SetTenantRateLimitRes struct {
|
||||
Success bool `json:"success"` // 是否成功
|
||||
}
|
||||
|
||||
// GetTenantRateLimitUsageReq 获取租户限流使用情况请求
|
||||
type GetTenantRateLimitUsageReq struct {
|
||||
g.Meta `path:"/ratelimit-tenant-usage" method:"get" tags:"租户限流" summary:"获取租户限流使用情况" dc:"获取指定租户的请求次数使用情况"`
|
||||
|
||||
TenantID int64 `json:"tenant_id" v:"required"` // 租户ID
|
||||
}
|
||||
|
||||
// GetTenantRateLimitUsageRes 获取租户限流使用情况响应
|
||||
type GetTenantRateLimitUsageRes struct {
|
||||
TenantID int64 `json:"tenant_id"` // 租户ID
|
||||
CurrentUsed int64 `json:"current_used"` // 当前已使用请求数
|
||||
MaxAllowed int64 `json:"max_allowed"` // 最大允许请求数(基于全局配置)
|
||||
UsagePercent float64 `json:"usage_percent"` // 使用率百分比
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"cidService/model/entity"
|
||||
"cidservice/model/entity"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
168
model/dto/stat_report_dto.go
Normal file
168
model/dto/stat_report_dto.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package dto
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// 报表生成请求
|
||||
type ReportGenerateReq struct {
|
||||
g.Meta `path:"/report/generate" method:"post"`
|
||||
TenantID int64 `json:"tenant_id" v:"required"`
|
||||
AppID int64 `json:"app_id"`
|
||||
ReportType string `json:"report_type" v:"required|in:daily,monthly,quarterly,yearly"`
|
||||
Date string `json:"date"` // 格式: 2024-01-01 (daily), 2024-01 (monthly), 2024-Q1 (quarterly), 2024 (yearly)
|
||||
}
|
||||
|
||||
// 报表生成响应
|
||||
type ReportGenerateResp struct {
|
||||
ReportID int64 `json:"report_id"`
|
||||
ReportType string `json:"report_type"`
|
||||
ReportDate string `json:"report_date"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// 报表列表请求
|
||||
type ReportListReq struct {
|
||||
g.Meta `path:"/report/list" method:"get"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
AppID int64 `json:"app_id"`
|
||||
ReportType string `json:"report_type"`
|
||||
StartDate string `json:"start_date"`
|
||||
EndDate string `json:"end_date"`
|
||||
Page int `json:"page" d:"1"`
|
||||
PageSize int `json:"page_size" d:"20"`
|
||||
}
|
||||
|
||||
// 报表列表响应
|
||||
type ReportListResp struct {
|
||||
Reports []*ReportDTO `json:"reports"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// 报表详情请求
|
||||
type ReportDetailReq struct {
|
||||
g.Meta `path:"/report/detail" method:"get"`
|
||||
ReportID int64 `json:"report_id" v:"required"`
|
||||
}
|
||||
|
||||
// 报表详情响应
|
||||
type ReportDetailResp struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
AppID int64 `json:"app_id"`
|
||||
ReportType string `json:"report_type"`
|
||||
ReportDate string `json:"report_date"`
|
||||
GeneratedAt string `json:"generated_at"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// 报表DTO
|
||||
type ReportDTO struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
AppID int64 `json:"app_id"`
|
||||
ReportType string `json:"report_type"`
|
||||
ReportDate string `json:"report_date"`
|
||||
GeneratedAt string `json:"generated_at"`
|
||||
}
|
||||
|
||||
// 统计查询请求
|
||||
type StatQueryReq struct {
|
||||
g.Meta `path:"/stat/query" method:"get"`
|
||||
TenantID int64 `json:"tenant_id" v:"required"`
|
||||
AppID int64 `json:"app_id"`
|
||||
AdType string `json:"ad_type"`
|
||||
Platform string `json:"platform"`
|
||||
Region string `json:"region"`
|
||||
StartDate string `json:"start_date" v:"required"`
|
||||
EndDate string `json:"end_date" v:"required"`
|
||||
Granularity string `json:"granularity" v:"in:daily,weekly,monthly" d:"daily"` // 统计粒度
|
||||
}
|
||||
|
||||
// 统计查询响应
|
||||
type StatQueryResp struct {
|
||||
Data []*StatDataPoint `json:"data"`
|
||||
Summary *StatSummary `json:"summary"`
|
||||
}
|
||||
|
||||
// 统计数据点
|
||||
type StatDataPoint struct {
|
||||
Date string `json:"date"`
|
||||
Impressions int64 `json:"impressions"`
|
||||
Clicks int64 `json:"clicks"`
|
||||
Revenue float64 `json:"revenue"`
|
||||
CTR float64 `json:"ctr"`
|
||||
AvgDuration float64 `json:"avg_duration"`
|
||||
}
|
||||
|
||||
// 统计摘要
|
||||
type StatSummary struct {
|
||||
TotalImpressions int64 `json:"total_impressions"`
|
||||
TotalClicks int64 `json:"total_clicks"`
|
||||
TotalRevenue float64 `json:"total_revenue"`
|
||||
AvgCTR float64 `json:"avg_ctr"`
|
||||
AvgDuration float64 `json:"avg_duration"`
|
||||
GrowthRate *GrowthRate `json:"growth_rate"`
|
||||
}
|
||||
|
||||
// 增长率统计
|
||||
type GrowthRate struct {
|
||||
Impressions float64 `json:"impressions"`
|
||||
Clicks float64 `json:"clicks"`
|
||||
Revenue float64 `json:"revenue"`
|
||||
CTR float64 `json:"ctr"`
|
||||
}
|
||||
|
||||
// 实时统计请求
|
||||
type RealTimeStatReq struct {
|
||||
g.Meta `path:"/stat/realtime" method:"get"`
|
||||
TenantID int64 `json:"tenant_id" v:"required"`
|
||||
AppID int64 `json:"app_id"`
|
||||
Hours int `json:"hours" d:"24"` // 过去多少小时的统计
|
||||
}
|
||||
|
||||
// 实时统计响应
|
||||
type RealTimeStatResp struct {
|
||||
CurrentHour *HourlyStat `json:"current_hour"`
|
||||
Last24Hours []*HourlyStat `json:"last_24_hours"`
|
||||
}
|
||||
|
||||
// 小时统计
|
||||
type HourlyStat struct {
|
||||
Hour string `json:"hour"`
|
||||
Impressions int64 `json:"impressions"`
|
||||
Clicks int64 `json:"clicks"`
|
||||
Revenue float64 `json:"revenue"`
|
||||
}
|
||||
|
||||
// Controller响应结构
|
||||
|
||||
// 生成报表响应
|
||||
type ReportGenerateRes struct {
|
||||
Data *ReportGenerateResp `json:"data"`
|
||||
}
|
||||
|
||||
// 报表列表响应
|
||||
type ReportListRes struct {
|
||||
Data *ReportListResp `json:"data"`
|
||||
}
|
||||
|
||||
// 报表详情响应
|
||||
type ReportDetailRes struct {
|
||||
Data *ReportDetailResp `json:"data"`
|
||||
}
|
||||
|
||||
// 统计查询响应
|
||||
type StatQueryRes struct {
|
||||
Data *StatQueryResp `json:"data"`
|
||||
}
|
||||
|
||||
// 实时统计响应
|
||||
type RealTimeStatRes struct {
|
||||
Data *RealTimeStatResp `json:"data"`
|
||||
}
|
||||
|
||||
// 导出报表响应
|
||||
type ExportReportRes struct {
|
||||
ReportData *ReportDetailResp `json:"report_data"`
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
// CreateStrategyReq 创建策略请求
|
||||
type CreateStrategyReq struct {
|
||||
g.Meta `path:"/strategy/create" method:"post" tags:"策略管理" summary:"创建匹配策略" dc:"创建新的广告匹配策略"`
|
||||
g.Meta `path:"/strategy" 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"` // 租户级别
|
||||
@@ -14,13 +14,14 @@ type CreateStrategyReq struct {
|
||||
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"` // 每次请求最大广告数
|
||||
MaxReqPerHour int `json:"max_req_per_hour" v:"required|min:1"` // 每小时最大请求次数
|
||||
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:"更新现有的广告匹配策略"`
|
||||
g.Meta `path:"/strategy" 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"` // 描述
|
||||
@@ -29,25 +30,26 @@ type UpdateStrategyReq struct {
|
||||
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"` // 每次请求最大广告数
|
||||
MaxReqPerHour int `json:"max_req_per_hour" v:"required|min:1"` // 每小时最大请求次数
|
||||
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:"删除指定的广告匹配策略"`
|
||||
g.Meta `path:"/strategy" 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:"获取指定策略的详细信息"`
|
||||
g.Meta `path:"/strategy" 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:"分页获取策略列表"`
|
||||
g.Meta `path:"/strategies" 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"` // 租户级别筛选
|
||||
@@ -56,20 +58,21 @@ type GetStrategyListReq struct {
|
||||
|
||||
// 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"` // 更新人
|
||||
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"` // 每次请求最大广告数
|
||||
MaxReqPerHour int `json:"max_req_per_hour"` // 每小时最大请求次数
|
||||
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 获取策略列表响应
|
||||
|
||||
@@ -1,163 +1,167 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"gitee.com/red-future---jilin-g/common/do"
|
||||
"time"
|
||||
)
|
||||
|
||||
const AdSourceCollection = "ad_source"
|
||||
|
||||
// AdSource 广告源实体
|
||||
type AdSource struct {
|
||||
do.MongoBaseDO `bson:",inline"` // 嵌入基础字段:Id, Creator, CreatedAt, Updater, UpdatedAt, TenantId, IsDeleted
|
||||
Id int64 `json:"id"` // 主键ID
|
||||
CreatedAt time.Time `json:"createdAt"` // 创建时间
|
||||
UpdatedAt time.Time `json:"updatedAt"` // 更新时间
|
||||
Creator string `json:"creator"` // 创建者
|
||||
Updater string `json:"updater"` // 更新者
|
||||
TenantId int64 `json:"tenantId"` // 租户ID
|
||||
IsDeleted bool `json:"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"` // 描述
|
||||
Name string `json:"name"` // 广告源名称
|
||||
Code string `json:"code"` // 广告源编码,唯一标识
|
||||
Provider string `json:"provider"` // 提供商:google、facebook、baidu、tencent、self等
|
||||
Type string `json:"type"` // 类型:self(自营)、third_party(第三方)、exchange(广告交易平台)
|
||||
Description string `json:"description"` // 描述
|
||||
|
||||
// 连接配置
|
||||
Config *AdSourceConfig `bson:"config" json:"config"` // 广告源配置
|
||||
Config string `json:"config"` // 广告源配置(JSON字符串)
|
||||
|
||||
// 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"` // 重试次数
|
||||
APIEndpoint string `json:"apiEndpoint"` // API端点
|
||||
APIVersion string `json:"apiVersion"` // API版本
|
||||
AuthType string `json:"authType"` // 认证类型:api_key、oauth、basic
|
||||
AuthConfig string `json:"authConfig"` // 认证配置(JSON字符串)
|
||||
Headers string `json:"headers"` // 请求头配置(JSON字符串)
|
||||
Timeout int `json:"timeout"` // 超时时间(毫秒)
|
||||
RetryCount int `json:"retryCount"` // 重试次数
|
||||
|
||||
// 广告源能力
|
||||
Capabilities *AdSourceCapabilities `bson:"capabilities" json:"capabilities"` // 广告源能力
|
||||
Capabilities string `json:"capabilities"` // 广告源能力(JSON字符串)
|
||||
|
||||
// 质量指标
|
||||
QualityMetrics *AdSourceQualityMetrics `bson:"qualityMetrics" json:"qualityMetrics"` // 质量指标
|
||||
QualityMetrics string `json:"qualityMetrics"` // 质量指标(JSON字符串)
|
||||
|
||||
// 财务设置
|
||||
PaymentTerms *PaymentTerms `bson:"paymentTerms" json:"paymentTerms"` // 支付条款
|
||||
PaymentTerms string `json:"paymentTerms"` // 支付条款(JSON字符串)
|
||||
|
||||
// 状态信息
|
||||
Status string `bson:"status" json:"status"` // 广告源状态:active、inactive、maintenance
|
||||
Health string `bson:"health" json:"health"` // 健康状态:healthy、degraded、unhealthy
|
||||
LastCheckAt int64 `bson:"lastCheckAt" json:"lastCheckAt"` // 最后检查时间
|
||||
Status string `json:"status"` // 广告源状态:active、inactive、maintenance
|
||||
Health string `json:"health"` // 健康状态:healthy、degraded、unhealthy
|
||||
LastCheckAt int64 `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"` // 转化率
|
||||
TotalRequests int64 `json:"totalRequests"` // 总请求数
|
||||
SuccessfulRequests int64 `json:"successfulRequests"` // 成功请求数
|
||||
FailedRequests int64 `json:"failedRequests"` // 失败请求数
|
||||
AverageResponseTime float64 `json:"averageResponseTime"` // 平均响应时间(毫秒)
|
||||
FillRate float64 `json:"fillRate"` // 填充率
|
||||
CTR float64 `json:"ctr"` // 点击率
|
||||
CVR float64 `json:"cvr"` // 转化率
|
||||
|
||||
// 系统信息
|
||||
Priority int `bson:"priority" json:"priority"` // 优先级,数值越高优先级越高
|
||||
Priority int `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"` // 支持的国家/地区
|
||||
SupportedFormats []string `json:"supportedFormats"` // 支持的广告格式
|
||||
SupportedSizes []string `json:"supportedSizes"` // 支持的尺寸
|
||||
SupportedDevices []string `json:"supportedDevices"` // 支持的设备类型
|
||||
SupportedOS []string `json:"supportedOS"` // 支持的操作系统
|
||||
SupportedCountries []string `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"` // 是否自动优化
|
||||
BiddingType string `json:"biddingType"` // 竞价类型:cpm、cpc、cpa、rtb
|
||||
MinBidAmount int64 `json:"minBidAmount"` // 最小出价(分)
|
||||
MaxBidAmount int64 `json:"maxBidAmount"` // 最大出价(分)
|
||||
BidIncrement int64 `json:"bidIncrement"` // 出价增量(分)
|
||||
DefaultBidAmount int64 `json:"defaultBidAmount"` // 默认出价(分)
|
||||
AutoOptimization bool `json:"autoOptimization"` // 是否自动优化
|
||||
|
||||
// 定向配置
|
||||
TargetingSupport *TargetingSupport `bson:"targetingSupport" json:"targetingSupport"` // 定向支持
|
||||
TargetingSupport *TargetingSupport `json:"targetingSupport"` // 定向支持
|
||||
|
||||
// 其他配置
|
||||
MaxAdsPerRequest int `bson:"maxAdsPerRequest" json:"maxAdsPerRequest"` // 单次请求最大广告数量
|
||||
BrandSafety bool `bson:"brandSafety" json:"brandSafety"` // 品牌安全
|
||||
Viewability bool `bson:"viewability" json:"viewability"` // 可见性支持
|
||||
MaxAdsPerRequest int `json:"maxAdsPerRequest"` // 单次请求最大广告数量
|
||||
BrandSafety bool `json:"brandSafety"` // 品牌安全
|
||||
Viewability bool `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定向
|
||||
GeoTargeting bool `json:"geoTargeting"` // 地理定向
|
||||
DemographicTargeting bool `json:"demographicTargeting"` // 人口统计定向
|
||||
BehavioralTargeting bool `json:"behavioralTargeting"` // 行为定向
|
||||
ContextualTargeting bool `json:"contextualTargeting"` // 上下文定向
|
||||
DeviceTargeting bool `json:"deviceTargeting"` // 设备定向
|
||||
TimeTargeting bool `json:"timeTargeting"` // 时间定向
|
||||
Retargeting bool `json:"retargeting"` // 重定向
|
||||
CookieTargeting bool `json:"cookieTargeting"` // Cookie定向
|
||||
}
|
||||
|
||||
// AdSourceCapabilities 广告源能力
|
||||
type AdSourceCapabilities struct {
|
||||
// 广告格式
|
||||
SupportedFormats []AdFormat `bson:"supportedFormats" json:"supportedFormats"` // 支持的广告格式
|
||||
SupportedFormats []AdFormat `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"` // 私有交易市场
|
||||
RealTimeBidding bool `json:"realTimeBidding"` // 实时竞价
|
||||
HeaderBidding bool `json:"headerBidding"` // 标题竞价
|
||||
ProgrammaticDirect bool `json:"programmaticDirect"` // 程序化直购
|
||||
PrivateMarketplace bool `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"` // 创意审核
|
||||
FraudDetection bool `json:"fraudDetection"` // 反欺诈检测
|
||||
BrandSafety bool `json:"brandSafety"` // 品牌安全
|
||||
Viewability bool `json:"viewability"` // 可见度验证
|
||||
CreativeApproval bool `json:"creativeApproval"` // 创意审核
|
||||
|
||||
// 数据能力
|
||||
AudienceTargeting bool `bson:"audienceTargeting" json:"audienceTargeting"` // 受众定向
|
||||
ContextualTargeting bool `bson:"contextualTargeting" json:"contextualTargeting"` // 上下文定向
|
||||
CrossDeviceTargeting bool `bson:"crossDeviceTargeting" json:"crossDeviceTargeting"` // 跨设备定向
|
||||
AudienceTargeting bool `json:"audienceTargeting"` // 受众定向
|
||||
ContextualTargeting bool `json:"contextualTargeting"` // 上下文定向
|
||||
CrossDeviceTargeting bool `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类型
|
||||
Type string `json:"type"` // 格式类型:banner、video、native、interstitial等
|
||||
Name string `json:"name"` // 格式名称
|
||||
Width int `json:"width"` // 宽度
|
||||
Height int `json:"height"` // 高度
|
||||
MimeType string `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"` // 可用性(百分比)
|
||||
AverageResponseTime float64 `json:"averageResponseTime"` // 平均响应时间(毫秒)
|
||||
SuccessRate float64 `json:"successRate"` // 成功率
|
||||
ErrorRate float64 `json:"errorRate"` // 错误率
|
||||
Uptime float64 `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"` // 品牌安全评分
|
||||
CTR float64 `json:"ctr"` // 点击率
|
||||
CVR float64 `json:"cvr"` // 转化率
|
||||
FillRate float64 `json:"fillRate"` // 填充率
|
||||
ViewabilityRate float64 `json:"viewabilityRate"` // 可见率
|
||||
BrandSafetyScore float64 `json:"brandSafetyScore"` // 品牌安全评分
|
||||
|
||||
// 财务指标
|
||||
eCPM int64 `bson:"ecpm" json:"ecpm"` // 有效千次展示成本(分)
|
||||
eCPC int64 `bson:"ecpc" json:"ecpc"` // 有效点击成本(分)
|
||||
RevenuePerRequest int64 `bson:"revenuePerRequest" json:"revenuePerRequest"` // 每请求收入(分)
|
||||
Ecpm int64 `json:"ecpm"` // 有效千次展示成本(分)
|
||||
Ecpc int64 `json:"ecpc"` // 有效点击成本(分)
|
||||
RevenuePerRequest int64 `json:"revenuePerRequest"` // 每请求收入(分)
|
||||
|
||||
// 时间指标
|
||||
LastUpdated int64 `bson:"lastUpdated" json:"lastUpdated"` // 最后更新时间
|
||||
MetricsUpdateWindow int `bson:"metricsUpdateWindow" json:"metricsUpdateWindow"` // 指标更新窗口(分钟)
|
||||
LastUpdated int64 `json:"lastUpdated"` // 最后更新时间
|
||||
MetricsUpdateWindow int `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"` // 提前付款折扣
|
||||
BillingModel string `json:"billingModel"` // 计费模式:cpm、cpc、cpa、rev_share
|
||||
PaymentTerms string `json:"paymentTerms"` // 支付条款:net_30、net_60、net_90
|
||||
RevShareRate float64 `json:"revShareRate"` // 收入分成比例(0-1)
|
||||
MinPayment int64 `json:"minPayment"` // 最小支付金额(分)
|
||||
Currency string `json:"currency"` // 货币单位
|
||||
TaxInclusive bool `json:"taxInclusive"` // 是否含税
|
||||
EarlyPaymentDiscount float64 `json:"earlyPaymentDiscount"` // 提前付款折扣
|
||||
}
|
||||
|
||||
44
model/entity/ad_type.go
Normal file
44
model/entity/ad_type.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"gitee.com/red-future---jilin-g/common/do"
|
||||
)
|
||||
|
||||
const AdTypeCollection = "ad_type"
|
||||
|
||||
// AdType 广告类型实体
|
||||
type AdType struct {
|
||||
do.MongoBaseDO `bson:",inline"`
|
||||
|
||||
// 广告类型信息
|
||||
Name string `bson:"name" json:"name"` // 广告类型名称
|
||||
Code string `bson:"code" json:"code"` // 广告类型编码
|
||||
Description string `bson:"description" json:"description"` // 广告类型描述
|
||||
Icon string `bson:"icon" json:"icon"` // 广告类型图标
|
||||
|
||||
// 类型配置
|
||||
Category string `bson:"category" json:"category"` // 分类:display, video, native, interstitial
|
||||
Platforms []string `bson:"platforms" json:"platforms"` // 支持的平台
|
||||
Formats []string `bson:"formats" json:"formats"` // 支持格式
|
||||
Dimensions []string `bson:"dimensions" json:"dimensions"` // 尺寸规格
|
||||
|
||||
// 技术要求
|
||||
MaxFileSize int64 `bson:"maxFileSize" json:"maxFileSize"` // 最大文件大小(bytes)
|
||||
MaxDuration int64 `bson:"maxDuration" json:"maxDuration"` // 最大时长(秒)
|
||||
SupportedMimeTypes []string `bson:"supportedMimeTypes" json:"supportedMimeTypes"` // 支持的MIME类型
|
||||
|
||||
// 业务配置
|
||||
BidType string `bson:"bidType" json:"bidType"` // 竞价类型:CPM, CPC, CPA
|
||||
MinBidPrice int64 `bson:"minBidPrice" json:"minBidPrice"` // 最低出价(分)
|
||||
MaxBidPrice int64 `bson:"maxBidPrice" json:"maxBidPrice"` // 最高出价(分)
|
||||
|
||||
// 状态信息
|
||||
Status string `bson:"status" json:"status"` // 状态:active, inactive
|
||||
SortOrder int `bson:"sortOrder" json:"sortOrder"` // 排序顺序
|
||||
|
||||
// 统计信息
|
||||
DailyImpression int64 `bson:"dailyImpression" json:"dailyImpression"` // 日展示量
|
||||
DailyClick int64 `bson:"dailyClick" json:"dailyClick"` // 日点击量
|
||||
|
||||
Remark string `bson:"remark" json:"remark"` // 备注
|
||||
}
|
||||
51
model/entity/application.go
Normal file
51
model/entity/application.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Application 应用实体
|
||||
type Application struct {
|
||||
Id int64 `json:"id"` // 主键ID
|
||||
CreatedAt time.Time `json:"createdAt"` // 创建时间
|
||||
UpdatedAt time.Time `json:"updatedAt"` // 更新时间
|
||||
Creator string `json:"creator"` // 创建者
|
||||
Updater string `json:"updater"` // 更新者
|
||||
TenantId int64 `json:"tenantId"` // 租户ID
|
||||
IsDeleted bool `json:"isDeleted"` // 是否删除
|
||||
|
||||
// 应用信息
|
||||
Name string `json:"name"` // 应用名称
|
||||
Code string `json:"code"` // 应用编码
|
||||
Description string `json:"description"` // 应用描述
|
||||
Icon string `json:"icon"` // 应用图标
|
||||
|
||||
// 平台信息
|
||||
Platform string `json:"platform"` // 平台:web, h5, android, ios
|
||||
PackageName string `json:"packageName"` // 包名(Android)/Bundle ID(iOS)
|
||||
AppStoreURL string `json:"appStoreUrl"` // 应用商店链接
|
||||
|
||||
// 配置信息
|
||||
Categories []string `json:"categories"` // 应用分类
|
||||
Tags []string `json:"tags"` // 应用标签
|
||||
Config string `json:"config"` // 应用配置(JSON格式)
|
||||
AdTypes []string `json:"adTypes"` // 支持的广告类型
|
||||
|
||||
// 状态信息
|
||||
Status string `json:"status"` // 状态:active, inactive, audit
|
||||
AuditStatus string `json:"auditStatus"` // 审核状态
|
||||
AuditReason string `json:"auditReason"` // 审核原因
|
||||
|
||||
// 统计信息
|
||||
DailyRequests int64 `json:"dailyRequests"` // 日请求量
|
||||
MonthlyRequests int64 `json:"monthlyRequests"` // 月请求量
|
||||
|
||||
// API密钥
|
||||
AppKey string `json:"appKey"` // 应用密钥
|
||||
AppSecret string `json:"appSecret"` // 应用密钥
|
||||
|
||||
// 回调信息
|
||||
CallbackURL string `json:"callbackUrl"` // 回调URL
|
||||
|
||||
Remark string `json:"remark"` // 备注
|
||||
}
|
||||
26
model/entity/stat_report.go
Normal file
26
model/entity/stat_report.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// StatReport 统计报表实体
|
||||
type StatReport struct {
|
||||
Id int64 `json:"id"` // 主键ID
|
||||
CreatedAt time.Time `json:"createdAt"` // 创建时间
|
||||
UpdatedAt time.Time `json:"updatedAt"` // 更新时间
|
||||
Creator string `json:"creator"` // 创建者
|
||||
Updater string `json:"updater"` // 更新者
|
||||
TenantId int64 `json:"tenantId"` // 租户ID
|
||||
IsDeleted bool `json:"isDeleted"` // 是否删除
|
||||
|
||||
// 报表基本信息
|
||||
AppID int64 `json:"appId"` // 应用ID
|
||||
ReportType string `json:"reportType"` // 报表类型:daily, weekly, monthly, quarterly, yearly
|
||||
ReportDate time.Time `json:"reportDate"` // 报表日期
|
||||
GeneratedAt time.Time `json:"generatedAt"` // 生成时间
|
||||
ReportData string `json:"reportData"` // 报表数据(JSON格式)
|
||||
|
||||
// 状态信息
|
||||
Status string `json:"status"` // 状态:generated, processing, completed
|
||||
}
|
||||
@@ -6,18 +6,19 @@ import (
|
||||
|
||||
// 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"` // 更新人
|
||||
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"` // 每次请求最大广告数
|
||||
MaxReqPerHour int `json:"max_req_per_hour" orm:"max_req_per_hour"` // 每小时最大请求次数
|
||||
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"` // 更新人
|
||||
}
|
||||
|
||||
39
model/entity/tenant.go
Normal file
39
model/entity/tenant.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"gitee.com/red-future---jilin-g/common/do"
|
||||
)
|
||||
|
||||
const TenantCollection = "tenant"
|
||||
|
||||
// Tenant 租户实体
|
||||
type Tenant struct {
|
||||
do.MongoBaseDO `bson:",inline"`
|
||||
|
||||
// 租户信息
|
||||
Name string `bson:"name" json:"name"` // 租户名称
|
||||
Code string `bson:"code" json:"code"` // 租户编码
|
||||
Description string `bson:"description" json:"description"` // 租户描述
|
||||
Logo string `bson:"logo" json:"logo"` // 租户Logo
|
||||
Domain string `bson:"domain" json:"domain"` // 租户域名
|
||||
|
||||
// 联系信息
|
||||
ContactName string `bson:"contactName" json:"contactName"` // 联系人姓名
|
||||
ContactPhone string `bson:"contactPhone" json:"contactPhone"` // 联系电话
|
||||
ContactEmail string `bson:"contactEmail" json:"contactEmail"` // 联系邮箱
|
||||
|
||||
// 状态信息
|
||||
Status string `bson:"status" json:"status"` // 状态:active, inactive, suspended
|
||||
PackageType string `bson:"packageType" json:"packageType"` // 套餐类型:basic, standard, premium
|
||||
ExpireTime int64 `bson:"expireTime" json:"expireTime"` // 套餐到期时间
|
||||
|
||||
// 限制信息
|
||||
MaxApps int64 `bson:"maxApps" json:"maxApps"` // 最大应用数
|
||||
MaxUsers int64 `bson:"maxUsers" json:"maxUsers"` // 最大用户数
|
||||
MaxRequestPerDay int64 `bson:"maxRequestPerDay" json:"maxRequestPerDay"` // 每日最大请求数
|
||||
|
||||
// 配置信息
|
||||
Config map[string]interface{} `bson:"config" json:"config"` // 租户配置
|
||||
|
||||
Remark string `bson:"remark" json:"remark"` // 备注
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/dao"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/dao"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/dao"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
)
|
||||
|
||||
var AdStatistics = new(adStatistics)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/dao"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/dao"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
)
|
||||
|
||||
var Advertiser = new(advertiser)
|
||||
|
||||
246
service/application_service.go
Normal file
246
service/application_service.go
Normal file
@@ -0,0 +1,246 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
|
||||
"cidservice/dao"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
var (
|
||||
Application = applicationService{}
|
||||
)
|
||||
|
||||
type applicationService struct{}
|
||||
|
||||
// CreateApplication 创建应用
|
||||
func (s *applicationService) CreateApplication(ctx context.Context, req *dto.CreateApplicationReq) (id int64, err error) {
|
||||
// 检查应用名称是否已存在
|
||||
existingApp, err := dao.Application.GetByName(ctx, req.Name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingApp != nil {
|
||||
return 0, gerror.New("应用名称已存在")
|
||||
}
|
||||
|
||||
// 生成API密钥
|
||||
appKey, appSecret, err := s.generateAPIKeys()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
application := &entity.Application{
|
||||
TenantId: req.TenantID,
|
||||
Name: req.Name,
|
||||
Code: req.Code,
|
||||
Description: req.Description,
|
||||
Platform: req.Platform,
|
||||
PackageName: req.PackageName,
|
||||
AppStoreURL: req.AppStoreURL,
|
||||
Categories: req.Categories,
|
||||
Tags: req.Tags,
|
||||
AdTypes: req.AdTypes,
|
||||
Status: "active",
|
||||
AppKey: appKey,
|
||||
AppSecret: appSecret,
|
||||
CallbackURL: req.CallbackURL,
|
||||
}
|
||||
|
||||
return dao.Application.Create(ctx, application)
|
||||
}
|
||||
|
||||
// UpdateApplication 更新应用
|
||||
func (s *applicationService) UpdateApplication(ctx context.Context, id int64, req *dto.UpdateApplicationReq) (affected int64, err error) {
|
||||
// 检查应用是否存在
|
||||
existingApp, err := dao.Application.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingApp == nil {
|
||||
return 0, gerror.New("应用不存在")
|
||||
}
|
||||
|
||||
// 如果更新名称,检查是否与其他应用冲突
|
||||
if req.Name != "" && req.Name != existingApp.Name {
|
||||
conflictApp, err := dao.Application.GetByName(ctx, req.Name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if conflictApp != nil && conflictApp.Id != id {
|
||||
return 0, gerror.New("应用名称已存在")
|
||||
}
|
||||
}
|
||||
|
||||
// 构建更新数据
|
||||
updateData := &entity.Application{}
|
||||
if req.Name != "" {
|
||||
updateData.Name = req.Name
|
||||
}
|
||||
if req.Description != "" {
|
||||
updateData.Description = req.Description
|
||||
}
|
||||
if req.Platform != "" {
|
||||
updateData.Platform = req.Platform
|
||||
}
|
||||
if req.PackageName != "" {
|
||||
updateData.PackageName = req.PackageName
|
||||
}
|
||||
if req.AppStoreURL != "" {
|
||||
updateData.AppStoreURL = req.AppStoreURL
|
||||
}
|
||||
if req.CallbackURL != "" {
|
||||
updateData.CallbackURL = req.CallbackURL
|
||||
}
|
||||
if len(req.Categories) > 0 {
|
||||
updateData.Categories = req.Categories
|
||||
}
|
||||
if len(req.Tags) > 0 {
|
||||
updateData.Tags = req.Tags
|
||||
}
|
||||
if len(req.AdTypes) > 0 {
|
||||
updateData.AdTypes = req.AdTypes
|
||||
}
|
||||
|
||||
// 使用Update方法更新应用
|
||||
err = dao.Application.Update(ctx, updateData)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
// GetApplicationsByTenant 获取租户下的应用列表
|
||||
func (s *applicationService) GetApplicationsByTenant(ctx context.Context, tenantID int64, platform, status string, page, size int) (list []*entity.Application, total int64, err error) {
|
||||
// 构建过滤条件
|
||||
filter := make(map[string]interface{})
|
||||
filter["tenant_id"] = tenantID
|
||||
if platform != "" {
|
||||
filter["platform"] = platform
|
||||
}
|
||||
if status != "" {
|
||||
filter["status"] = status
|
||||
}
|
||||
|
||||
// 调用DAO的GetByTenantID方法获取租户下的所有应用
|
||||
apps, err := dao.Application.GetByTenantID(ctx, tenantID)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用额外的过滤条件
|
||||
var filteredApps []*entity.Application
|
||||
for _, app := range apps {
|
||||
if platform != "" && app.Platform != platform {
|
||||
continue
|
||||
}
|
||||
if status != "" && app.Status != status {
|
||||
continue
|
||||
}
|
||||
filteredApps = append(filteredApps, app)
|
||||
}
|
||||
|
||||
// 实现简单的分页
|
||||
startIndex := (page - 1) * size
|
||||
endIndex := startIndex + size
|
||||
if startIndex >= len(filteredApps) {
|
||||
return []*entity.Application{}, int64(len(filteredApps)), nil
|
||||
}
|
||||
if endIndex > len(filteredApps) {
|
||||
endIndex = len(filteredApps)
|
||||
}
|
||||
|
||||
return filteredApps[startIndex:endIndex], int64(len(filteredApps)), nil
|
||||
}
|
||||
|
||||
// GetApplicationByKey 根据API密钥获取应用
|
||||
func (s *applicationService) GetApplicationByKey(ctx context.Context, appKey string) (application *entity.Application, err error) {
|
||||
return dao.Application.GetByAPIKey(ctx, appKey)
|
||||
}
|
||||
|
||||
// GetApplicationByID 根据ID获取应用
|
||||
func (s *applicationService) GetApplicationByID(ctx context.Context, id int64) (application *entity.Application, err error) {
|
||||
return dao.Application.GetByID(ctx, id)
|
||||
}
|
||||
|
||||
// DeleteApplication 删除应用
|
||||
func (s *applicationService) DeleteApplication(ctx context.Context, id int64) (affected int64, err error) {
|
||||
err = dao.Application.Delete(ctx, id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
// ValidateApplication 验证应用权限
|
||||
func (s *applicationService) ValidateApplication(ctx context.Context, appKey, appSecret string) (application *entity.Application, err error) {
|
||||
app, err := dao.Application.GetByAPIKey(ctx, appKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if app == nil {
|
||||
return nil, gerror.New("应用不存在")
|
||||
}
|
||||
if app.Status != "active" {
|
||||
return nil, gerror.New("应用状态异常")
|
||||
}
|
||||
if app.AppSecret != appSecret {
|
||||
return nil, gerror.New("密钥验证失败")
|
||||
}
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
// generateAPIKeys 生成API密钥
|
||||
func (s *applicationService) generateAPIKeys() (appKey, appSecret string, err error) {
|
||||
// 生成32位随机字符串作为AppKey
|
||||
keyBytes := make([]byte, 16)
|
||||
if _, err := rand.Read(keyBytes); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
appKey = hex.EncodeToString(keyBytes)
|
||||
|
||||
// 生成64位随机字符串作为AppSecret
|
||||
secretBytes := make([]byte, 32)
|
||||
if _, err := rand.Read(secretBytes); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
appSecret = hex.EncodeToString(secretBytes)
|
||||
|
||||
return appKey, appSecret, nil
|
||||
}
|
||||
|
||||
// ResetAPIKeys 重置API密钥
|
||||
func (s *applicationService) ResetAPIKeys(ctx context.Context, id int64) (appKey, appSecret string, err error) {
|
||||
// 检查应用是否存在
|
||||
existingApp, err := dao.Application.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if existingApp == nil {
|
||||
return "", "", gerror.New("应用不存在")
|
||||
}
|
||||
|
||||
// 生成新的API密钥
|
||||
appKey, appSecret, err = s.generateAPIKeys()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// 更新应用密钥
|
||||
updateData := &entity.Application{
|
||||
AppKey: appKey,
|
||||
AppSecret: appSecret,
|
||||
}
|
||||
err = dao.Application.Update(ctx, updateData)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return appKey, appSecret, nil
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidService/model/types"
|
||||
"cidservice/dao"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
"cidservice/model/types"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -85,6 +85,15 @@ func (s *cidService) GenerateCID(ctx context.Context, req *dto.GenerateCIDReq) (
|
||||
return nil, gerror.Wrap(err, "获取租户信息失败")
|
||||
}
|
||||
|
||||
// 检查租户请求次数限制
|
||||
allowed, err := RateLimit.CheckTenantRequestLimit(ctx, tenant.Id, nil)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "检查租户请求限制失败")
|
||||
}
|
||||
if !allowed {
|
||||
return nil, gerror.New("租户请求次数已超过限制,请稍后再试")
|
||||
}
|
||||
|
||||
// 获取匹配策略
|
||||
strategy, err := s.getMatchingStrategy(ctx, tenant.Level)
|
||||
if err != nil {
|
||||
|
||||
137
service/rate_limit_service.go
Normal file
137
service/rate_limit_service.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"cidservice/consts"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
var (
|
||||
RateLimit = rateLimitService{}
|
||||
)
|
||||
|
||||
type rateLimitService struct{}
|
||||
|
||||
// TenantRateLimitConfig 租户限流配置
|
||||
type TenantRateLimitConfig struct {
|
||||
TenantID int64 // 租户ID
|
||||
RequestsPerSecond float64 // 每秒请求数
|
||||
Burst int // 突发请求数
|
||||
Window time.Duration // 时间窗口
|
||||
}
|
||||
|
||||
// CheckTenantRequestLimit 检查租户请求次数限制
|
||||
func (s *rateLimitService) CheckTenantRequestLimit(ctx context.Context, tenantID int64, config *TenantRateLimitConfig) (bool, error) {
|
||||
if config == nil {
|
||||
// 使用默认配置
|
||||
config = s.getDefaultTenantRateLimitConfig(tenantID)
|
||||
}
|
||||
|
||||
// 构建Redis键 - 使用当前小时的键,确保按小时计数
|
||||
now := time.Now()
|
||||
hourKey := fmt.Sprintf("%s%d:%d", consts.AdRequestLimitKeyPrefix, tenantID, now.Hour())
|
||||
|
||||
// 获取当前计数
|
||||
currentCountVar, err := g.Redis().Get(ctx, hourKey)
|
||||
if err != nil && err.Error() != "redis: nil" {
|
||||
return false, err
|
||||
}
|
||||
|
||||
currentCount := currentCountVar.Int64()
|
||||
|
||||
// 如果是第一次请求,设置计数和过期时间(到下一个小时)
|
||||
if currentCount == 0 {
|
||||
// 设置过期时间为到下一个小时的剩余时间
|
||||
nextHour := now.Truncate(time.Hour).Add(time.Hour)
|
||||
ttl := nextHour.Sub(now)
|
||||
// 使用SetEX一次性设置值和过期时间
|
||||
err = g.Redis().SetEX(ctx, hourKey, 1, int64(ttl.Seconds()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// 检查是否超过限制
|
||||
maxRequests := int64(config.RequestsPerSecond * config.Window.Seconds())
|
||||
if currentCount >= maxRequests {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// 增加计数
|
||||
_, err = g.Redis().Incr(ctx, hourKey)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetDefaultTenantRateLimitConfig 获取默认的租户限流配置
|
||||
func (s *rateLimitService) getDefaultTenantRateLimitConfig(tenantID int64) *TenantRateLimitConfig {
|
||||
// 从配置文件中读取限流参数
|
||||
ctx := context.Background()
|
||||
|
||||
// 检查是否启用租户限流
|
||||
enabled := g.Cfg().MustGet(ctx, "tenantRateLimit.enabled", false).Bool()
|
||||
if !enabled {
|
||||
// 如果未启用,返回一个很大的限制值,相当于不限制
|
||||
return &TenantRateLimitConfig{
|
||||
TenantID: tenantID,
|
||||
RequestsPerSecond: 10000, // 每秒10000个请求,相当于不限制
|
||||
Burst: 20000, // 突发20000个请求
|
||||
Window: time.Hour,
|
||||
}
|
||||
}
|
||||
|
||||
// 从配置文件中获取限流参数
|
||||
requestsPerHour := g.Cfg().MustGet(ctx, "tenantRateLimit.requestsPerHour", 3600).Int64()
|
||||
windowSeconds := g.Cfg().MustGet(ctx, "tenantRateLimit.window", 3600).Int64()
|
||||
burst := g.Cfg().MustGet(ctx, "tenantRateLimit.burst", 100).Int()
|
||||
|
||||
// 转换为每秒请求数
|
||||
requestsPerSecond := float64(requestsPerHour) / float64(windowSeconds)
|
||||
|
||||
return &TenantRateLimitConfig{
|
||||
TenantID: tenantID,
|
||||
RequestsPerSecond: requestsPerSecond,
|
||||
Burst: burst,
|
||||
Window: time.Duration(windowSeconds) * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
// SetTenantRateLimitConfig 设置租户限流配置
|
||||
func (s *rateLimitService) SetTenantRateLimitConfig(ctx context.Context, config *TenantRateLimitConfig) error {
|
||||
// 注意:实际使用的是config.yml中的全局配置,此方法仅用于兼容旧API
|
||||
// 实际限流参数请修改config.yml中的tenantRateLimit部分
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTenantCurrentUsage 获取租户当前请求使用情况
|
||||
func (s *rateLimitService) GetTenantCurrentUsage(ctx context.Context, tenantID int64, config *TenantRateLimitConfig) (current int64, max int64, err error) {
|
||||
if config == nil {
|
||||
config = s.getDefaultTenantRateLimitConfig(tenantID)
|
||||
}
|
||||
|
||||
// 构建当前小时的Redis键
|
||||
now := time.Now()
|
||||
hourKey := fmt.Sprintf("%s%d:%d", consts.AdRequestLimitKeyPrefix, tenantID, now.Hour())
|
||||
|
||||
// 获取当前计数
|
||||
currentVar, err := g.Redis().Get(ctx, hourKey)
|
||||
if err != nil && err.Error() == "redis: nil" {
|
||||
current = 0
|
||||
err = nil
|
||||
} else if err != nil {
|
||||
return 0, 0, err
|
||||
} else {
|
||||
current = currentVar.Int64()
|
||||
}
|
||||
|
||||
max = int64(config.RequestsPerSecond * config.Window.Seconds())
|
||||
return current, max, nil
|
||||
}
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/dao"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
)
|
||||
|
||||
// Report Service 单例
|
||||
|
||||
514
service/stat_report_service.go
Normal file
514
service/stat_report_service.go
Normal file
@@ -0,0 +1,514 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"cidservice/dao"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type StatReportService struct{}
|
||||
|
||||
var StatReport = &StatReportService{}
|
||||
|
||||
// 生成日报表
|
||||
func (s *StatReportService) GenerateDailyReport(ctx context.Context, req *dto.ReportGenerateReq) (*dto.ReportGenerateResp, error) {
|
||||
// 获取统计日期
|
||||
reportDate := time.Now()
|
||||
if req.Date != "" {
|
||||
parsedDate, err := time.Parse("2006-01-02", req.Date)
|
||||
if err == nil {
|
||||
reportDate = parsedDate
|
||||
}
|
||||
}
|
||||
|
||||
// 生成日报表数据
|
||||
reportData, err := s.generateReportData(ctx, req.TenantID, req.AppID, "daily", reportDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 保存报表
|
||||
report := &entity.StatReport{
|
||||
TenantId: req.TenantID,
|
||||
AppID: req.AppID,
|
||||
ReportType: "daily",
|
||||
ReportDate: reportDate,
|
||||
ReportData: gconv.String(reportData),
|
||||
GeneratedAt: time.Now(),
|
||||
Status: "completed",
|
||||
}
|
||||
|
||||
_, err = dao.StatReport.Create(ctx, report)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.ReportGenerateResp{
|
||||
ReportID: report.Id,
|
||||
ReportType: "daily",
|
||||
ReportDate: reportDate.Format("2006-01-02"),
|
||||
Data: reportData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 生成月报表
|
||||
func (s *StatReportService) GenerateMonthlyReport(ctx context.Context, req *dto.ReportGenerateReq) (*dto.ReportGenerateResp, error) {
|
||||
reportDate := time.Now()
|
||||
if req.Date != "" {
|
||||
parsedDate, err := time.Parse("2006-01", req.Date)
|
||||
if err == nil {
|
||||
reportDate = parsedDate
|
||||
}
|
||||
}
|
||||
|
||||
reportData, err := s.generateReportData(ctx, req.TenantID, req.AppID, "monthly", reportDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := &entity.StatReport{
|
||||
TenantId: req.TenantID,
|
||||
AppID: req.AppID,
|
||||
ReportType: "monthly",
|
||||
ReportDate: reportDate,
|
||||
ReportData: gconv.String(reportData),
|
||||
GeneratedAt: time.Now(),
|
||||
Status: "completed",
|
||||
}
|
||||
|
||||
_, err = dao.StatReport.Create(ctx, report)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.ReportGenerateResp{
|
||||
ReportID: report.Id,
|
||||
ReportType: "monthly",
|
||||
ReportDate: reportDate.Format("2006-01"),
|
||||
Data: reportData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 生成季度报表
|
||||
func (s *StatReportService) GenerateQuarterlyReport(ctx context.Context, req *dto.ReportGenerateReq) (*dto.ReportGenerateResp, error) {
|
||||
reportDate := time.Now()
|
||||
if req.Date != "" {
|
||||
parsedDate, err := time.Parse("2006-Q1", req.Date)
|
||||
if err == nil {
|
||||
reportDate = parsedDate
|
||||
}
|
||||
}
|
||||
|
||||
reportData, err := s.generateReportData(ctx, req.TenantID, req.AppID, "quarterly", reportDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := &entity.StatReport{
|
||||
TenantId: req.TenantID,
|
||||
AppID: req.AppID,
|
||||
ReportType: "quarterly",
|
||||
ReportDate: reportDate,
|
||||
ReportData: gconv.String(reportData),
|
||||
GeneratedAt: time.Now(),
|
||||
Status: "completed",
|
||||
}
|
||||
|
||||
_, err = dao.StatReport.Create(ctx, report)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.ReportGenerateResp{
|
||||
ReportID: report.Id,
|
||||
ReportType: "quarterly",
|
||||
ReportDate: reportDate.Format("2006-Q1"),
|
||||
Data: reportData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 生成年报表
|
||||
func (s *StatReportService) GenerateYearlyReport(ctx context.Context, req *dto.ReportGenerateReq) (*dto.ReportGenerateResp, error) {
|
||||
reportDate := time.Now()
|
||||
if req.Date != "" {
|
||||
parsedDate, err := time.Parse("2006", req.Date)
|
||||
if err == nil {
|
||||
reportDate = parsedDate
|
||||
}
|
||||
}
|
||||
|
||||
reportData, err := s.generateReportData(ctx, req.TenantID, req.AppID, "yearly", reportDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := &entity.StatReport{
|
||||
TenantId: req.TenantID,
|
||||
AppID: req.AppID,
|
||||
ReportType: "yearly",
|
||||
ReportDate: reportDate,
|
||||
ReportData: gconv.String(reportData),
|
||||
GeneratedAt: time.Now(),
|
||||
Status: "completed",
|
||||
}
|
||||
|
||||
_, err = dao.StatReport.Create(ctx, report)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.ReportGenerateResp{
|
||||
ReportID: report.Id,
|
||||
ReportType: "yearly",
|
||||
ReportDate: reportDate.Format("2006"),
|
||||
Data: reportData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 生成报表数据
|
||||
func (s *StatReportService) generateReportData(ctx context.Context, tenantID, appID int64, reportType string, reportDate time.Time) (map[string]interface{}, error) {
|
||||
// 构建查询条件
|
||||
where := g.Map{"tenant_id": tenantID}
|
||||
if appID > 0 {
|
||||
where["app_id"] = appID
|
||||
}
|
||||
|
||||
// 根据报表类型确定时间范围
|
||||
startTime, endTime := s.getReportTimeRange(reportType, reportDate)
|
||||
where["created_at between ? and ?"] = g.Slice{startTime, endTime}
|
||||
|
||||
// 查询基础统计数据
|
||||
var stats []map[string]interface{}
|
||||
err := g.DB().Model("ad_statistics").Where(where).Scan(&stats)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 计算环比数据
|
||||
yoyData, err := s.calculateYearOverYear(ctx, tenantID, appID, reportType, reportDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 计算同比数据
|
||||
momData, err := s.calculateMonthOverMonth(ctx, tenantID, appID, reportType, reportDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 按广告类型分组统计
|
||||
adTypeStats, err := s.groupByAdType(stats)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 按地区分组统计
|
||||
regionStats := s.groupByRegion(stats)
|
||||
|
||||
// 按终端类型分组统计
|
||||
platformStats := s.groupByPlatform(stats)
|
||||
|
||||
return map[string]interface{}{
|
||||
"basic_stats": map[string]interface{}{
|
||||
"total_impressions": s.sumField(stats, "impressions"),
|
||||
"total_clicks": s.sumField(stats, "clicks"),
|
||||
"total_revenue": s.sumField(stats, "revenue"),
|
||||
"avg_ctr": s.calculateCTR(stats),
|
||||
"avg_play_duration": s.avgField(stats, "play_duration"),
|
||||
},
|
||||
"ad_type_stats": adTypeStats,
|
||||
"region_stats": regionStats,
|
||||
"platform_stats": platformStats,
|
||||
"year_over_year": yoyData,
|
||||
"month_over_month": momData,
|
||||
"time_range": map[string]string{
|
||||
"start": startTime.Format("2006-01-02 15:04:05"),
|
||||
"end": endTime.Format("2006-01-02 15:04:05"),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 获取报表时间范围
|
||||
func (s *StatReportService) getReportTimeRange(reportType string, reportDate time.Time) (time.Time, time.Time) {
|
||||
switch reportType {
|
||||
case "daily":
|
||||
start := time.Date(reportDate.Year(), reportDate.Month(), reportDate.Day(), 0, 0, 0, 0, time.Local)
|
||||
end := start.AddDate(0, 0, 1).Add(-time.Second)
|
||||
return start, end
|
||||
case "monthly":
|
||||
start := time.Date(reportDate.Year(), reportDate.Month(), 1, 0, 0, 0, 0, time.Local)
|
||||
end := start.AddDate(0, 1, 0).Add(-time.Second)
|
||||
return start, end
|
||||
case "quarterly":
|
||||
quarter := (reportDate.Month()-1)/3 + 1
|
||||
startMonth := time.Month((quarter-1)*3 + 1)
|
||||
start := time.Date(reportDate.Year(), startMonth, 1, 0, 0, 0, 0, time.Local)
|
||||
end := start.AddDate(0, 3, 0).Add(-time.Second)
|
||||
return start, end
|
||||
case "yearly":
|
||||
start := time.Date(reportDate.Year(), 1, 1, 0, 0, 0, 0, time.Local)
|
||||
end := start.AddDate(1, 0, 0).Add(-time.Second)
|
||||
return start, end
|
||||
default:
|
||||
return reportDate, reportDate
|
||||
}
|
||||
}
|
||||
|
||||
// 计算同比数据
|
||||
func (s *StatReportService) calculateYearOverYear(ctx context.Context, tenantID, appID int64, reportType string, reportDate time.Time) (map[string]interface{}, error) {
|
||||
lastYearDate := reportDate.AddDate(-1, 0, 0)
|
||||
lastYearData, err := s.getComparisonData(ctx, tenantID, appID, reportType, lastYearDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"last_year": lastYearData,
|
||||
"growth_rate": s.calculateGrowthRate(lastYearData, s.getCurrentPeriodData(ctx, tenantID, appID, reportType, reportDate)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 计算环比数据
|
||||
func (s *StatReportService) calculateMonthOverMonth(ctx context.Context, tenantID, appID int64, reportType string, reportDate time.Time) (map[string]interface{}, error) {
|
||||
var lastPeriodDate time.Time
|
||||
switch reportType {
|
||||
case "daily":
|
||||
lastPeriodDate = reportDate.AddDate(0, 0, -1)
|
||||
case "monthly":
|
||||
lastPeriodDate = reportDate.AddDate(0, -1, 0)
|
||||
case "quarterly":
|
||||
lastPeriodDate = reportDate.AddDate(0, -3, 0)
|
||||
case "yearly":
|
||||
lastPeriodDate = reportDate.AddDate(-1, 0, 0)
|
||||
}
|
||||
|
||||
lastPeriodData, err := s.getComparisonData(ctx, tenantID, appID, reportType, lastPeriodDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"last_period": lastPeriodData,
|
||||
"growth_rate": s.calculateGrowthRate(lastPeriodData, s.getCurrentPeriodData(ctx, tenantID, appID, reportType, reportDate)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 获取对比数据
|
||||
func (s *StatReportService) getComparisonData(ctx context.Context, tenantID, appID int64, reportType string, date time.Time) (map[string]float64, error) {
|
||||
// 这里简化实现,实际应该查询数据库
|
||||
return map[string]float64{
|
||||
"impressions": 1000,
|
||||
"clicks": 50,
|
||||
"revenue": 500.0,
|
||||
"ctr": 0.05,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 获取当前周期数据
|
||||
func (s *StatReportService) getCurrentPeriodData(ctx context.Context, tenantID, appID int64, reportType string, date time.Time) map[string]float64 {
|
||||
// 这里简化实现,实际应该查询数据库
|
||||
return map[string]float64{
|
||||
"impressions": 1200,
|
||||
"clicks": 60,
|
||||
"revenue": 600.0,
|
||||
"ctr": 0.05,
|
||||
}
|
||||
}
|
||||
|
||||
// 计算增长率
|
||||
func (s *StatReportService) calculateGrowthRate(lastData, currentData map[string]float64) map[string]float64 {
|
||||
growthRate := make(map[string]float64)
|
||||
for key, lastValue := range lastData {
|
||||
currentValue := currentData[key]
|
||||
if lastValue == 0 {
|
||||
growthRate[key] = 0
|
||||
} else {
|
||||
growthRate[key] = (currentValue - lastValue) / lastValue * 100
|
||||
}
|
||||
}
|
||||
return growthRate
|
||||
}
|
||||
|
||||
// 按广告类型分组统计
|
||||
func (s *StatReportService) groupByAdType(stats []map[string]interface{}) (map[string]interface{}, error) {
|
||||
result := make(map[string]interface{})
|
||||
for _, stat := range stats {
|
||||
adType := gconv.String(stat["ad_type"])
|
||||
if adType == "" {
|
||||
adType = "unknown"
|
||||
}
|
||||
|
||||
if _, exists := result[adType]; !exists {
|
||||
result[adType] = map[string]float64{
|
||||
"impressions": 0,
|
||||
"clicks": 0,
|
||||
"revenue": 0,
|
||||
}
|
||||
}
|
||||
|
||||
adTypeStat, ok := result[adType].(map[string]float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid adTypeStat type")
|
||||
}
|
||||
adTypeStat["impressions"] += gconv.Float64(stat["impressions"])
|
||||
adTypeStat["clicks"] += gconv.Float64(stat["clicks"])
|
||||
adTypeStat["revenue"] += gconv.Float64(stat["revenue"])
|
||||
}
|
||||
|
||||
// 计算每个广告类型的CTR
|
||||
for adType, stat := range result {
|
||||
adTypeStat, ok := stat.(map[string]float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid adTypeStat type for adType: %s", adType)
|
||||
}
|
||||
if adTypeStat["impressions"] > 0 {
|
||||
adTypeStat["ctr"] = adTypeStat["clicks"] / adTypeStat["impressions"] * 100
|
||||
} else {
|
||||
adTypeStat["ctr"] = 0
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 按地区分组统计
|
||||
func (s *StatReportService) groupByRegion(stats []map[string]interface{}) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
for _, stat := range stats {
|
||||
region := gconv.String(stat["region"])
|
||||
if region == "" {
|
||||
region = "unknown"
|
||||
}
|
||||
|
||||
if _, exists := result[region]; !exists {
|
||||
result[region] = map[string]float64{
|
||||
"impressions": 0,
|
||||
"clicks": 0,
|
||||
"revenue": 0,
|
||||
}
|
||||
}
|
||||
|
||||
regionStat := result[region].(map[string]float64)
|
||||
regionStat["impressions"] += gconv.Float64(stat["impressions"])
|
||||
regionStat["clicks"] += gconv.Float64(stat["clicks"])
|
||||
regionStat["revenue"] += gconv.Float64(stat["revenue"])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 按终端类型分组统计
|
||||
func (s *StatReportService) groupByPlatform(stats []map[string]interface{}) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
for _, stat := range stats {
|
||||
platform := gconv.String(stat["platform"])
|
||||
if platform == "" {
|
||||
platform = "unknown"
|
||||
}
|
||||
|
||||
if _, exists := result[platform]; !exists {
|
||||
result[platform] = map[string]float64{
|
||||
"impressions": 0,
|
||||
"clicks": 0,
|
||||
"revenue": 0,
|
||||
}
|
||||
}
|
||||
|
||||
platformStat := result[platform].(map[string]float64)
|
||||
platformStat["impressions"] += gconv.Float64(stat["impressions"])
|
||||
platformStat["clicks"] += gconv.Float64(stat["clicks"])
|
||||
platformStat["revenue"] += gconv.Float64(stat["revenue"])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 计算字段总和
|
||||
func (s *StatReportService) sumField(stats []map[string]interface{}, field string) float64 {
|
||||
total := 0.0
|
||||
for _, stat := range stats {
|
||||
total += gconv.Float64(stat[field])
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// 计算字段平均值
|
||||
func (s *StatReportService) avgField(stats []map[string]interface{}, field string) float64 {
|
||||
if len(stats) == 0 {
|
||||
return 0
|
||||
}
|
||||
return s.sumField(stats, field) / float64(len(stats))
|
||||
}
|
||||
|
||||
// 计算平均CTR
|
||||
func (s *StatReportService) calculateCTR(stats []map[string]interface{}) float64 {
|
||||
totalImpressions := s.sumField(stats, "impressions")
|
||||
totalClicks := s.sumField(stats, "clicks")
|
||||
if totalImpressions == 0 {
|
||||
return 0
|
||||
}
|
||||
return totalClicks / totalImpressions * 100
|
||||
}
|
||||
|
||||
// 查询报表列表
|
||||
func (s *StatReportService) GetReportList(ctx context.Context, req *dto.ReportListReq) (*dto.ReportListResp, error) {
|
||||
// 使用DAO的List方法
|
||||
reports, count, err := dao.StatReport.List(ctx, req.TenantID, req.AppID, req.ReportType, req.StartDate, req.EndDate, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为DTO
|
||||
var reportDTOs []*dto.ReportDTO
|
||||
for _, report := range reports {
|
||||
reportDTOs = append(reportDTOs, &dto.ReportDTO{
|
||||
ID: report.Id,
|
||||
TenantID: report.TenantId,
|
||||
AppID: report.AppID,
|
||||
ReportType: report.ReportType,
|
||||
ReportDate: report.ReportDate.Format("2006-01-02"),
|
||||
GeneratedAt: report.GeneratedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
return &dto.ReportListResp{
|
||||
Reports: reportDTOs,
|
||||
Total: count,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 获取报表详情
|
||||
func (s *StatReportService) GetReportDetail(ctx context.Context, reportID int64) (*dto.ReportDetailResp, error) {
|
||||
var report *entity.StatReport
|
||||
report, err := dao.StatReport.GetByID(ctx, reportID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if report == nil {
|
||||
return nil, fmt.Errorf("报表不存在")
|
||||
}
|
||||
|
||||
// 解析报表数据
|
||||
var reportData map[string]interface{}
|
||||
if err := gconv.Struct(report.ReportData, &reportData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.ReportDetailResp{
|
||||
ID: report.Id,
|
||||
TenantID: report.TenantId,
|
||||
AppID: report.AppID,
|
||||
ReportType: report.ReportType,
|
||||
ReportDate: report.ReportDate.Format("2006-01-02"),
|
||||
GeneratedAt: report.GeneratedAt.Format("2006-01-02 15:04:05"),
|
||||
Data: reportData,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"cidservice/dao"
|
||||
"cidservice/model/dto"
|
||||
"cidservice/model/entity"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
33
test_config.go
Normal file
33
test_config.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"cidservice/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
// 检查租户请求次数限制
|
||||
allowed, err := service.RateLimit.CheckTenantRequestLimit(ctx, 1, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("错误: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("租户请求是否允许: %v\n", allowed)
|
||||
|
||||
// 获取租户当前使用情况
|
||||
current, max, err := service.RateLimit.GetTenantCurrentUsage(ctx, 1, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("错误: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("租户请求使用情况:\n")
|
||||
fmt.Printf(" 当前使用: %d\n", current)
|
||||
fmt.Printf(" 最大允许: %d\n", max)
|
||||
fmt.Printf(" 使用率: %.2f%%\n", float64(current)/float64(max)*100)
|
||||
}
|
||||
Reference in New Issue
Block a user