Dockerfile
This commit is contained in:
+26
-5
@@ -1,14 +1,35 @@
|
||||
server:
|
||||
address : ":3001"
|
||||
name: "cid"
|
||||
workerId: 1
|
||||
logPath: "resource/log/server"
|
||||
logStdout: true
|
||||
errorStack: true
|
||||
rate:
|
||||
limit: 200
|
||||
burst: 300
|
||||
mongo:
|
||||
logger:
|
||||
level: "all"
|
||||
stdout: true
|
||||
address: "mongodb://116.204.74.41:27017/cid_service?retryWrites=true"
|
||||
|
||||
# Database.
|
||||
database:
|
||||
default:
|
||||
- type: "pgsql"
|
||||
host: "localhost"
|
||||
port: "5432"
|
||||
user: "postgres"
|
||||
pass: "123456"
|
||||
name: "cid"
|
||||
role: "master"
|
||||
maxIdle: "5"
|
||||
maxOpen: "20"
|
||||
maxLifetime: "60s"
|
||||
charset: "utf8mb4"
|
||||
debug: true
|
||||
dryRun: false
|
||||
createdAt: "created_at"
|
||||
updatedAt: "updated_at"
|
||||
deletedAt: "deleted_at"
|
||||
timeMaintainDisabled: false
|
||||
|
||||
redis:
|
||||
# 集群模式配置方法
|
||||
default:
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package consts
|
||||
|
||||
// AdFormatType 广告格式类型枚举
|
||||
type AdFormatType string
|
||||
|
||||
const (
|
||||
AdFormatTypeBanner AdFormatType = "banner" // 横幅广告
|
||||
AdFormatTypeVideo AdFormatType = "video" // 视频广告
|
||||
AdFormatTypeNative AdFormatType = "native" // 原生广告
|
||||
AdFormatTypeInterstitial AdFormatType = "interstitial" // 插屏广告
|
||||
)
|
||||
|
||||
// GetAllAdFormatTypes 获取所有广告格式类型
|
||||
func GetAllAdFormatTypes() []AdFormatType {
|
||||
return []AdFormatType{
|
||||
AdFormatTypeBanner,
|
||||
AdFormatTypeVideo,
|
||||
AdFormatTypeNative,
|
||||
AdFormatTypeInterstitial,
|
||||
}
|
||||
}
|
||||
|
||||
type AdFormatTypeKeyValue struct {
|
||||
Key AdFormatType
|
||||
Value string
|
||||
}
|
||||
|
||||
var (
|
||||
AdFormatTypeBannerKeyValue = AdFormatTypeKeyValue{Key: AdFormatTypeBanner, Value: "横幅广告"}
|
||||
AdFormatTypeVideoKeyValue = AdFormatTypeKeyValue{Key: AdFormatTypeVideo, Value: "视频广告"}
|
||||
AdFormatTypeNativeKeyValue = AdFormatTypeKeyValue{Key: AdFormatTypeNative, Value: "原生广告"}
|
||||
AdFormatTypeInterstitialKeyValue = AdFormatTypeKeyValue{Key: AdFormatTypeInterstitial, Value: "插屏广告"}
|
||||
)
|
||||
|
||||
func GetAllAdFormatTypeKeyValue() []AdFormatTypeKeyValue {
|
||||
return []AdFormatTypeKeyValue{
|
||||
AdFormatTypeBannerKeyValue,
|
||||
AdFormatTypeVideoKeyValue,
|
||||
AdFormatTypeNativeKeyValue,
|
||||
AdFormatTypeInterstitialKeyValue,
|
||||
}
|
||||
}
|
||||
|
||||
var adFormatTypeValueMap = map[AdFormatType]string{
|
||||
AdFormatTypeBanner: AdFormatTypeBannerKeyValue.Value,
|
||||
AdFormatTypeVideo: AdFormatTypeVideoKeyValue.Value,
|
||||
AdFormatTypeNative: AdFormatTypeNativeKeyValue.Value,
|
||||
AdFormatTypeInterstitial: AdFormatTypeInterstitialKeyValue.Value,
|
||||
}
|
||||
|
||||
func GetAdFormatTypeValueByKey(key AdFormatType) (value string) {
|
||||
value, exists := adFormatTypeValueMap[key]
|
||||
if !exists {
|
||||
value = "未知广告格式"
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package consts
|
||||
|
||||
// AdSourceHealth 广告源健康状态枚举
|
||||
type AdSourceHealth string
|
||||
|
||||
const (
|
||||
AdSourceHealthHealthy AdSourceHealth = "healthy" // 健康
|
||||
AdSourceHealthDegraded AdSourceHealth = "degraded" // 降级
|
||||
AdSourceHealthUnhealthy AdSourceHealth = "unhealthy" // 不健康
|
||||
)
|
||||
|
||||
// GetAllAdSourceHealths 获取所有广告源健康状态
|
||||
func GetAllAdSourceHealths() []AdSourceHealth {
|
||||
return []AdSourceHealth{
|
||||
AdSourceHealthHealthy,
|
||||
AdSourceHealthDegraded,
|
||||
AdSourceHealthUnhealthy,
|
||||
}
|
||||
}
|
||||
|
||||
type AdSourceHealthKeyValue struct {
|
||||
Key AdSourceHealth
|
||||
Value string
|
||||
}
|
||||
|
||||
var (
|
||||
AdSourceHealthHealthyKeyValue = AdSourceHealthKeyValue{Key: AdSourceHealthHealthy, Value: "健康"}
|
||||
AdSourceHealthDegradedKeyValue = AdSourceHealthKeyValue{Key: AdSourceHealthDegraded, Value: "降级"}
|
||||
AdSourceHealthUnhealthyKeyValue = AdSourceHealthKeyValue{Key: AdSourceHealthUnhealthy, Value: "不健康"}
|
||||
)
|
||||
|
||||
func GetAllAdSourceHealthKeyValue() []AdSourceHealthKeyValue {
|
||||
return []AdSourceHealthKeyValue{
|
||||
AdSourceHealthHealthyKeyValue,
|
||||
AdSourceHealthDegradedKeyValue,
|
||||
AdSourceHealthUnhealthyKeyValue,
|
||||
}
|
||||
}
|
||||
|
||||
var adSourceHealthValueMap = map[AdSourceHealth]string{
|
||||
AdSourceHealthHealthy: AdSourceHealthHealthyKeyValue.Value,
|
||||
AdSourceHealthDegraded: AdSourceHealthDegradedKeyValue.Value,
|
||||
AdSourceHealthUnhealthy: AdSourceHealthUnhealthyKeyValue.Value,
|
||||
}
|
||||
|
||||
func GetAdSourceHealthValueByKey(key AdSourceHealth) (value string) {
|
||||
value, exists := adSourceHealthValueMap[key]
|
||||
if !exists {
|
||||
value = "未知健康状态"
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package consts
|
||||
|
||||
// AdSourceProvider 广告源提供商枚举
|
||||
type AdSourceProvider string
|
||||
|
||||
const (
|
||||
AdSourceProviderGoogle AdSourceProvider = "google" // Google
|
||||
AdSourceProviderBaidu AdSourceProvider = "baidu" // 百度
|
||||
AdSourceProviderTencent AdSourceProvider = "tencent" // 腾讯
|
||||
AdSourceProviderSelf AdSourceProvider = "self" // 自营
|
||||
)
|
||||
|
||||
// GetAllAdSourceProviders 获取所有广告源提供商
|
||||
func GetAllAdSourceProviders() []AdSourceProvider {
|
||||
return []AdSourceProvider{
|
||||
AdSourceProviderGoogle,
|
||||
AdSourceProviderBaidu,
|
||||
AdSourceProviderTencent,
|
||||
AdSourceProviderSelf,
|
||||
}
|
||||
}
|
||||
|
||||
type AdSourceProviderKeyValue struct {
|
||||
Key AdSourceProvider
|
||||
Value string
|
||||
}
|
||||
|
||||
var (
|
||||
AdSourceProviderGoogleKeyValue = AdSourceProviderKeyValue{Key: AdSourceProviderGoogle, Value: "Google"}
|
||||
AdSourceProviderBaiduKeyValue = AdSourceProviderKeyValue{Key: AdSourceProviderBaidu, Value: "百度"}
|
||||
AdSourceProviderTencentKeyValue = AdSourceProviderKeyValue{Key: AdSourceProviderTencent, Value: "腾讯"}
|
||||
AdSourceProviderSelfKeyValue = AdSourceProviderKeyValue{Key: AdSourceProviderSelf, Value: "自营"}
|
||||
)
|
||||
|
||||
func GetAllAdSourceProviderKeyValue() []AdSourceProviderKeyValue {
|
||||
return []AdSourceProviderKeyValue{
|
||||
AdSourceProviderGoogleKeyValue,
|
||||
AdSourceProviderBaiduKeyValue,
|
||||
AdSourceProviderTencentKeyValue,
|
||||
AdSourceProviderSelfKeyValue,
|
||||
}
|
||||
}
|
||||
|
||||
var adSourceProviderValueMap = map[AdSourceProvider]string{
|
||||
AdSourceProviderGoogle: AdSourceProviderGoogleKeyValue.Value,
|
||||
AdSourceProviderBaidu: AdSourceProviderBaiduKeyValue.Value,
|
||||
AdSourceProviderTencent: AdSourceProviderTencentKeyValue.Value,
|
||||
AdSourceProviderSelf: AdSourceProviderSelfKeyValue.Value,
|
||||
}
|
||||
|
||||
func GetAdSourceProviderValueByKey(key AdSourceProvider) (value string) {
|
||||
value, exists := adSourceProviderValueMap[key]
|
||||
if !exists {
|
||||
value = "未知提供商"
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package consts
|
||||
|
||||
// AdSourceStatus 广告源状态枚举
|
||||
type AdSourceStatus string
|
||||
|
||||
const (
|
||||
AdSourceStatusActive AdSourceStatus = "active" // 活跃
|
||||
AdSourceStatusInactive AdSourceStatus = "inactive" // 非活跃
|
||||
AdSourceStatusMaintenance AdSourceStatus = "maintenance" // 维护中
|
||||
)
|
||||
|
||||
// GetAllAdSourceStatuses 获取所有广告源状态
|
||||
func GetAllAdSourceStatuses() []AdSourceStatus {
|
||||
return []AdSourceStatus{
|
||||
AdSourceStatusActive,
|
||||
AdSourceStatusInactive,
|
||||
AdSourceStatusMaintenance,
|
||||
}
|
||||
}
|
||||
|
||||
type AdSourceStatusKeyValue struct {
|
||||
Key AdSourceStatus
|
||||
Value string
|
||||
}
|
||||
|
||||
var (
|
||||
AdSourceStatusActiveKeyValue = AdSourceStatusKeyValue{Key: AdSourceStatusActive, Value: "活跃"}
|
||||
AdSourceStatusInactiveKeyValue = AdSourceStatusKeyValue{Key: AdSourceStatusInactive, Value: "非活跃"}
|
||||
AdSourceStatusMaintenanceKeyValue = AdSourceStatusKeyValue{Key: AdSourceStatusMaintenance, Value: "维护中"}
|
||||
)
|
||||
|
||||
func GetAllAdSourceStatusKeyValue() []AdSourceStatusKeyValue {
|
||||
return []AdSourceStatusKeyValue{
|
||||
AdSourceStatusActiveKeyValue,
|
||||
AdSourceStatusInactiveKeyValue,
|
||||
AdSourceStatusMaintenanceKeyValue,
|
||||
}
|
||||
}
|
||||
|
||||
var adSourceStatusValueMap = map[AdSourceStatus]string{
|
||||
AdSourceStatusActive: AdSourceStatusActiveKeyValue.Value,
|
||||
AdSourceStatusInactive: AdSourceStatusInactiveKeyValue.Value,
|
||||
AdSourceStatusMaintenance: AdSourceStatusMaintenanceKeyValue.Value,
|
||||
}
|
||||
|
||||
func GetAdSourceStatusValueByKey(key AdSourceStatus) (value string) {
|
||||
value, exists := adSourceStatusValueMap[key]
|
||||
if !exists {
|
||||
value = "未知状态"
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package consts
|
||||
|
||||
// AdSourceType 广告源类型枚举
|
||||
type AdSourceType string
|
||||
|
||||
const (
|
||||
AdSourceTypeSelf AdSourceType = "self" // 自营
|
||||
AdSourceTypeThirdParty AdSourceType = "third_party" // 第三方
|
||||
AdSourceTypeExchange AdSourceType = "exchange" // 广告交易平台
|
||||
)
|
||||
|
||||
// GetAllAdSourceTypes 获取所有广告源类型
|
||||
func GetAllAdSourceTypes() []AdSourceType {
|
||||
return []AdSourceType{
|
||||
AdSourceTypeSelf,
|
||||
AdSourceTypeThirdParty,
|
||||
AdSourceTypeExchange,
|
||||
}
|
||||
}
|
||||
|
||||
type AdSourceTypeKeyValue struct {
|
||||
Key AdSourceType
|
||||
Value string
|
||||
}
|
||||
|
||||
var (
|
||||
AdSourceTypeSelfKeyValue = AdSourceTypeKeyValue{Key: AdSourceTypeSelf, Value: "自营"}
|
||||
AdSourceTypeThirdPartyKeyValue = AdSourceTypeKeyValue{Key: AdSourceTypeThirdParty, Value: "第三方"}
|
||||
AdSourceTypeExchangeKeyValue = AdSourceTypeKeyValue{Key: AdSourceTypeExchange, Value: "广告交易平台"}
|
||||
)
|
||||
|
||||
func GetAllAdSourceTypeKeyValue() []AdSourceTypeKeyValue {
|
||||
return []AdSourceTypeKeyValue{
|
||||
AdSourceTypeSelfKeyValue,
|
||||
AdSourceTypeThirdPartyKeyValue,
|
||||
AdSourceTypeExchangeKeyValue,
|
||||
}
|
||||
}
|
||||
|
||||
var adSourceTypeValueMap = map[AdSourceType]string{
|
||||
AdSourceTypeSelf: AdSourceTypeSelfKeyValue.Value,
|
||||
AdSourceTypeThirdParty: AdSourceTypeThirdPartyKeyValue.Value,
|
||||
AdSourceTypeExchange: AdSourceTypeExchangeKeyValue.Value,
|
||||
}
|
||||
|
||||
func GetAdSourceTypeValueByKey(key AdSourceType) (value string) {
|
||||
value, exists := adSourceTypeValueMap[key]
|
||||
if !exists {
|
||||
value = "未知类型"
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package app
|
||||
|
||||
// AppStatus 应用状态
|
||||
type AppStatus string
|
||||
|
||||
const (
|
||||
AppStatusActive AppStatus = "active" // 启用
|
||||
AppStatusInactive AppStatus = "inactive" // 停用
|
||||
)
|
||||
|
||||
func (s AppStatus) String() string {
|
||||
return string(s)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package app
|
||||
|
||||
// AppType 应用类型
|
||||
type AppType string
|
||||
|
||||
const (
|
||||
AppTypeWeb AppType = "web" // Web应用
|
||||
AppTypeMobile AppType = "mobile" // 移动应用
|
||||
AppTypeMiniApp AppType = "mini_app" // 小程序
|
||||
AppTypeH5 AppType = "h5" // H5应用
|
||||
AppTypeDesktop AppType = "desktop" // 桌面应用
|
||||
AppTypeThirdParty AppType = "third_party" // 第三方应用
|
||||
)
|
||||
|
||||
func (s AppType) String() string {
|
||||
return string(s)
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package consts
|
||||
|
||||
// AuthType 认证类型枚举
|
||||
type AuthType string
|
||||
|
||||
const (
|
||||
AuthTypeAPIKey AuthType = "api_key" // API密钥
|
||||
AuthTypeOAuth AuthType = "oauth" // OAuth
|
||||
AuthTypeBasic AuthType = "basic" // Basic认证
|
||||
)
|
||||
|
||||
// GetAllAuthTypes 获取所有认证类型
|
||||
func GetAllAuthTypes() []AuthType {
|
||||
return []AuthType{
|
||||
AuthTypeAPIKey,
|
||||
AuthTypeOAuth,
|
||||
AuthTypeBasic,
|
||||
}
|
||||
}
|
||||
|
||||
type AuthTypeKeyValue struct {
|
||||
Key AuthType
|
||||
Value string
|
||||
}
|
||||
|
||||
var (
|
||||
AuthTypeAPIKeyKeyValue = AuthTypeKeyValue{Key: AuthTypeAPIKey, Value: "API密钥"}
|
||||
AuthTypeOAuthKeyValue = AuthTypeKeyValue{Key: AuthTypeOAuth, Value: "OAuth"}
|
||||
AuthTypeBasicKeyValue = AuthTypeKeyValue{Key: AuthTypeBasic, Value: "Basic认证"}
|
||||
)
|
||||
|
||||
func GetAllAuthTypeKeyValue() []AuthTypeKeyValue {
|
||||
return []AuthTypeKeyValue{
|
||||
AuthTypeAPIKeyKeyValue,
|
||||
AuthTypeOAuthKeyValue,
|
||||
AuthTypeBasicKeyValue,
|
||||
}
|
||||
}
|
||||
|
||||
var authTypeValueMap = map[AuthType]string{
|
||||
AuthTypeAPIKey: AuthTypeAPIKeyKeyValue.Value,
|
||||
AuthTypeOAuth: AuthTypeOAuthKeyValue.Value,
|
||||
AuthTypeBasic: AuthTypeBasicKeyValue.Value,
|
||||
}
|
||||
|
||||
func GetAuthTypeValueByKey(key AuthType) (value string) {
|
||||
value, exists := authTypeValueMap[key]
|
||||
if !exists {
|
||||
value = "未知认证类型"
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package consts
|
||||
|
||||
// BiddingType 竞价类型枚举
|
||||
type BiddingType string
|
||||
|
||||
const (
|
||||
BiddingTypeCPM BiddingType = "cpm" // 千次展示成本
|
||||
BiddingTypeCPC BiddingType = "cpc" // 每次点击成本
|
||||
BiddingTypeCPA BiddingType = "cpa" // 每次行动成本
|
||||
BiddingTypeRTB BiddingType = "rtb" // 实时竞价
|
||||
)
|
||||
|
||||
// GetAllBiddingTypes 获取所有竞价类型
|
||||
func GetAllBiddingTypes() []BiddingType {
|
||||
return []BiddingType{
|
||||
BiddingTypeCPM,
|
||||
BiddingTypeCPC,
|
||||
BiddingTypeCPA,
|
||||
BiddingTypeRTB,
|
||||
}
|
||||
}
|
||||
|
||||
type BiddingTypeKeyValue struct {
|
||||
Key BiddingType
|
||||
Value string
|
||||
}
|
||||
|
||||
var (
|
||||
BiddingTypeCPMKeyValue = BiddingTypeKeyValue{Key: BiddingTypeCPM, Value: "千次展示成本"}
|
||||
BiddingTypeCPCKeypValue = BiddingTypeKeyValue{Key: BiddingTypeCPC, Value: "每次点击成本"}
|
||||
BiddingTypeCPAKeyValue = BiddingTypeKeyValue{Key: BiddingTypeCPA, Value: "每次行动成本"}
|
||||
BiddingTypeRTBKeyValue = BiddingTypeKeyValue{Key: BiddingTypeRTB, Value: "实时竞价"}
|
||||
)
|
||||
|
||||
func GetAllBiddingTypeKeyValue() []BiddingTypeKeyValue {
|
||||
return []BiddingTypeKeyValue{
|
||||
BiddingTypeCPMKeyValue,
|
||||
BiddingTypeCPCKeypValue,
|
||||
BiddingTypeCPAKeyValue,
|
||||
BiddingTypeRTBKeyValue,
|
||||
}
|
||||
}
|
||||
|
||||
var biddingTypeValueMap = map[BiddingType]string{
|
||||
BiddingTypeCPM: BiddingTypeCPMKeyValue.Value,
|
||||
BiddingTypeCPC: BiddingTypeCPCKeypValue.Value,
|
||||
BiddingTypeCPA: BiddingTypeCPAKeyValue.Value,
|
||||
BiddingTypeRTB: BiddingTypeRTBKeyValue.Value,
|
||||
}
|
||||
|
||||
func GetBiddingTypeValueByKey(key BiddingType) (value string) {
|
||||
value, exists := biddingTypeValueMap[key]
|
||||
if !exists {
|
||||
value = "未知竞价类型"
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package consts
|
||||
|
||||
// BillingModel 计费模式枚举
|
||||
type BillingModel string
|
||||
|
||||
const (
|
||||
BillingModelCPM BillingModel = "cpm" // 千次展示成本
|
||||
BillingModelCPC BillingModel = "cpc" // 每次点击成本
|
||||
BillingModelCPA BillingModel = "cpa" // 每次行动成本
|
||||
BillingModelRevShare BillingModel = "rev_share" // 收入分成
|
||||
)
|
||||
|
||||
// GetAllBillingModels 获取所有计费模式
|
||||
func GetAllBillingModels() []BillingModel {
|
||||
return []BillingModel{
|
||||
BillingModelCPM,
|
||||
BillingModelCPC,
|
||||
BillingModelCPA,
|
||||
BillingModelRevShare,
|
||||
}
|
||||
}
|
||||
|
||||
type BillingModelKeyValue struct {
|
||||
Key BillingModel
|
||||
Value string
|
||||
}
|
||||
|
||||
var (
|
||||
BillingModelCPMKeyValue = BillingModelKeyValue{Key: BillingModelCPM, Value: "千次展示成本"}
|
||||
BillingModelCPCKeypValue = BillingModelKeyValue{Key: BillingModelCPC, Value: "每次点击成本"}
|
||||
BillingModelCPAKeyValue = BillingModelKeyValue{Key: BillingModelCPA, Value: "每次行动成本"}
|
||||
BillingModelRevShareKeyValue = BillingModelKeyValue{Key: BillingModelRevShare, Value: "收入分成"}
|
||||
)
|
||||
|
||||
func GetAllBillingModelKeyValue() []BillingModelKeyValue {
|
||||
return []BillingModelKeyValue{
|
||||
BillingModelCPMKeyValue,
|
||||
BillingModelCPCKeypValue,
|
||||
BillingModelCPAKeyValue,
|
||||
BillingModelRevShareKeyValue,
|
||||
}
|
||||
}
|
||||
|
||||
var billingModelValueMap = map[BillingModel]string{
|
||||
BillingModelCPM: BillingModelCPMKeyValue.Value,
|
||||
BillingModelCPC: BillingModelCPCKeypValue.Value,
|
||||
BillingModelCPA: BillingModelCPAKeyValue.Value,
|
||||
BillingModelRevShare: BillingModelRevShareKeyValue.Value,
|
||||
}
|
||||
|
||||
func GetBillingModelValueByKey(key BillingModel) (value string) {
|
||||
value, exists := billingModelValueMap[key]
|
||||
if !exists {
|
||||
value = "未知计费模式"
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package consts
|
||||
|
||||
// MongoDB集合名称常量
|
||||
const (
|
||||
AdPositionCollection = "ad_position" // 广告位集合
|
||||
AdSourceCollection = "ad_source" // 广告源集合
|
||||
AdvertisementCollection = "advertisement" // 广告集合
|
||||
AdvertiserCollection = "advertiser" // 广告主集合
|
||||
ApplicationCollection = "application" // 应用集合
|
||||
CidRequestCollection = "cid_request" // CID请求集合
|
||||
StrategyCollection = "strategy" // 策略集合
|
||||
AdCreativeCollection = "ad_creative" // 广告创意集合
|
||||
AdPlatformCollection = "ad_platform" // 广告平台集合
|
||||
AdTypeCollection = "ad_type" // 广告类型集合
|
||||
AppPlatformConfigCollection = "app_platform_config" // 应用平台配置集合
|
||||
PlatformDeliveryRuleCollection = "platform_delivery_rule" // 平台投放规则集合
|
||||
TargetingCollection = "targeting" // 定向规则集合
|
||||
)
|
||||
@@ -1,19 +0,0 @@
|
||||
package consts
|
||||
|
||||
// 默认配置值
|
||||
const (
|
||||
DefaultTimeout = 5000 // 默认超时时间(毫秒)
|
||||
DefaultRetryCount = 3 // 默认重试次数
|
||||
DefaultPriority = 1 // 默认优先级
|
||||
)
|
||||
|
||||
// 错误消息
|
||||
const (
|
||||
ErrAdSourceNotFound = "广告源不存在"
|
||||
ErrAdSourceNameExists = "广告源名称已存在"
|
||||
ErrAdSourceCodeExists = "广告源编码已存在"
|
||||
ErrAdSourceInactive = "广告源非活跃状态"
|
||||
ErrAdSourceUnhealthy = "广告源健康状态异常"
|
||||
ErrRateLimitExceeded = "请求频率超限"
|
||||
ErrInvalidConfiguration = "配置参数无效"
|
||||
)
|
||||
@@ -1,16 +0,0 @@
|
||||
package consts
|
||||
|
||||
// 注意:以下枚举常量已迁移到单独的枚举文件中,请使用新的枚举类型:
|
||||
// - AdSourceStatus -> consts.AdSourceStatus (ad_source_status.go)
|
||||
// - AdSourceHealth -> consts.AdSourceHealth (ad_source_health.go)
|
||||
// - AdSourceType -> consts.AdSourceType (ad_source_type.go)
|
||||
// - AdSourceProvider -> consts.AdSourceProvider (ad_source_provider.go)
|
||||
// - AuthType -> consts.AuthType (auth_type.go)
|
||||
// - BiddingType -> consts.BiddingType (bidding_type.go)
|
||||
// - AdFormatType -> consts.AdFormatType (ad_format_type.go)
|
||||
// - BillingModel -> consts.BillingModel (billing_model.go)
|
||||
// - PaymentTerms -> consts.PaymentTerms (payment_terms.go)
|
||||
|
||||
// 配置值常量已迁移到 config.go 文件中
|
||||
// 错误消息常量已迁移到 config.go 文件中
|
||||
// MongoDB集合名称常量已迁移到 collections.go 文件中
|
||||
@@ -0,0 +1,18 @@
|
||||
package data
|
||||
|
||||
// ApiMethod 接口请求方法
|
||||
type ApiMethod string
|
||||
|
||||
const (
|
||||
ApiMethodGet ApiMethod = "GET" // GET请求
|
||||
ApiMethodPost ApiMethod = "POST" // POST请求
|
||||
ApiMethodPut ApiMethod = "PUT" // PUT请求
|
||||
ApiMethodDelete ApiMethod = "DELETE" // DELETE请求
|
||||
ApiMethodPatch ApiMethod = "PATCH" // PATCH请求
|
||||
ApiMethodHead ApiMethod = "HEAD" // HEAD请求
|
||||
ApiMethodOptions ApiMethod = "OPTIONS" // OPTIONS请求
|
||||
)
|
||||
|
||||
func (m ApiMethod) String() string {
|
||||
return string(m)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package data
|
||||
|
||||
// FetchStatus 数据获取状态
|
||||
type FetchStatus string
|
||||
|
||||
const (
|
||||
FetchStatusPending FetchStatus = "pending" // 待执行
|
||||
FetchStatusRunning FetchStatus = "running" // 执行中
|
||||
FetchStatusSuccess FetchStatus = "success" // 成功
|
||||
FetchStatusFailed FetchStatus = "failed" // 失败
|
||||
FetchStatusRateLimit FetchStatus = "rate_limit" // 触发限流
|
||||
)
|
||||
|
||||
func (f FetchStatus) String() string {
|
||||
return string(f)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package data
|
||||
|
||||
// LimitType 限流类型
|
||||
type LimitType string
|
||||
|
||||
const (
|
||||
LimitTypeApp LimitType = "app" // 应用维度限流
|
||||
LimitTypeTenant LimitType = "tenant" // 租户维度限流
|
||||
LimitTypeApi LimitType = "api" // 接口维度限流
|
||||
)
|
||||
|
||||
func (l LimitType) String() string {
|
||||
return string(l)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package data
|
||||
|
||||
// PlatformStatus 平台状态
|
||||
type PlatformStatus string
|
||||
|
||||
const (
|
||||
PlatformStatusActive PlatformStatus = "active" // 启用
|
||||
PlatformStatusInactive PlatformStatus = "inactive" // 停用
|
||||
)
|
||||
|
||||
func (s PlatformStatus) String() string {
|
||||
return string(s)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package data
|
||||
|
||||
// SyncPlatform 同步平台类型
|
||||
type SyncPlatform string
|
||||
|
||||
const (
|
||||
PlatformTaobao SyncPlatform = "taobao" // 淘宝
|
||||
PlatformJD SyncPlatform = "jd" // 京东
|
||||
PlatformKuaishou SyncPlatform = "kuaishou" // 快手
|
||||
PlatformDouyin SyncPlatform = "douyin" // 抖音
|
||||
PlatformXhs SyncPlatform = "xhs" // 小红书
|
||||
PlatformPdd SyncPlatform = "pdd" // 拼多多
|
||||
PlatformXianyu SyncPlatform = "xianyu" // 闲鱼
|
||||
PlatformTmall SyncPlatform = "tmall" // 天猫
|
||||
PlatformWechat SyncPlatform = "wechat" // 微信
|
||||
PlatformCustom SyncPlatform = "custom" // 自定义平台
|
||||
)
|
||||
|
||||
func (s SyncPlatform) String() string {
|
||||
return string(s)
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package consts
|
||||
|
||||
import "errors"
|
||||
|
||||
// 广告管理错误码
|
||||
const (
|
||||
ErrAdNotFound = 1001 // 广告不存在
|
||||
ErrAdStatusInvalid = 1002 // 广告状态无效
|
||||
ErrAdAuditedRejected = 1003 // 广告审核被拒绝
|
||||
ErrAdBudgetInsufficient = 1004 // 广告预算不足
|
||||
)
|
||||
|
||||
// 广告主管理错误码
|
||||
const (
|
||||
ErrAdvertiserNotFound = 2001 // 广告主不存在
|
||||
ErrAdvertiserStatusInvalid = 2002 // 广告主状态无效
|
||||
ErrAdvertiserAuditedRejected = 2003 // 广告主审核被拒绝
|
||||
ErrAdvertiserBalanceLow = 2004 // 广告主余额不足
|
||||
ErrCreditLimitInvalid = 2005 // 授信额度无效
|
||||
)
|
||||
|
||||
// 广告位管理错误码
|
||||
const (
|
||||
ErrAdPositionNotFound = 3001 // 广告位不存在
|
||||
ErrAdPositionStatusInvalid = 3002 // 广告位状态无效
|
||||
ErrAdPositionCodeExists = 3003 // 广告位编码已存在
|
||||
ErrAdNotMatched = 3004 // 无匹配广告
|
||||
)
|
||||
|
||||
// 报表管理错误码
|
||||
const (
|
||||
ErrReportNotFound = 4001 // 报表不存在
|
||||
ErrReportNotGenerated = 4002 // 报表未生成
|
||||
ErrReportExpired = 4003 // 报表已过期
|
||||
ErrReportInvalidFormat = 4004 // 报表格式无效
|
||||
)
|
||||
|
||||
// 配置验证错误
|
||||
var (
|
||||
ErrInvalidPriority = errors.New("优先级必须为非负数")
|
||||
ErrInvalidWeight = errors.New("权重必须在0到1之间")
|
||||
ErrInvalidBidAmount = errors.New("出价金额必须为非负数")
|
||||
ErrInvalidBidRange = errors.New("最小出价不能大于最大出价")
|
||||
ErrInvalidROAS = errors.New("ROAS必须为非负数")
|
||||
ErrInvalidBudget = errors.New("预算金额必须为非负数")
|
||||
ErrInvalidTimeRange = errors.New("开始时间不能大于结束时间")
|
||||
ErrInvalidTimeout = errors.New("超时时间必须为正数")
|
||||
ErrInvalidRetryCount = errors.New("重试次数必须为非负数")
|
||||
ErrInvalidFileSize = errors.New("文件大小必须为正数")
|
||||
ErrInvalidDuration = errors.New("时长必须为正数")
|
||||
ErrInvalidRateLimit = errors.New("速率限制必须为正数")
|
||||
ErrInvalidCommission = errors.New("佣金比例必须在0到1之间")
|
||||
ErrInvalidRevShare = errors.New("收入分成比例必须在0到1之间")
|
||||
ErrInvalidAge = errors.New("年龄必须为正数且最小年龄不能大于最大年龄")
|
||||
ErrInvalidFrequency = errors.New("频次限制必须为非负数")
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package mapping
|
||||
|
||||
// MappingStatus 映射状态
|
||||
type MappingStatus string
|
||||
|
||||
const (
|
||||
MappingStatusActive MappingStatus = "active" // 启用
|
||||
MappingStatusInactive MappingStatus = "inactive" // 停用
|
||||
)
|
||||
|
||||
func (s MappingStatus) String() string {
|
||||
return string(s)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package mapping
|
||||
|
||||
// TransformType 转换类型
|
||||
type TransformType string
|
||||
|
||||
const (
|
||||
TransformTypeFixed TransformType = "fixed" // 固定值
|
||||
TransformTypeMapping TransformType = "mapping" // 值映射
|
||||
TransformTypeRegex TransformType = "regex" // 正则转换
|
||||
TransformTypeFunction TransformType = "function" // 函数转换
|
||||
TransformTypeScript TransformType = "script" // 脚本转换
|
||||
)
|
||||
|
||||
func (t TransformType) String() string {
|
||||
return string(t)
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package consts
|
||||
|
||||
// PaymentTerms 支付条款枚举
|
||||
type PaymentTerms string
|
||||
|
||||
const (
|
||||
PaymentTermsNet30 PaymentTerms = "net_30" // 30天
|
||||
PaymentTermsNet60 PaymentTerms = "net_60" // 60天
|
||||
PaymentTermsNet90 PaymentTerms = "net_90" // 90天
|
||||
)
|
||||
|
||||
// GetAllPaymentTerms 获取所有支付条款
|
||||
func GetAllPaymentTerms() []PaymentTerms {
|
||||
return []PaymentTerms{
|
||||
PaymentTermsNet30,
|
||||
PaymentTermsNet60,
|
||||
PaymentTermsNet90,
|
||||
}
|
||||
}
|
||||
|
||||
type PaymentTermsKeyValue struct {
|
||||
Key PaymentTerms
|
||||
Value string
|
||||
}
|
||||
|
||||
var (
|
||||
PaymentTermsNet30KeyValue = PaymentTermsKeyValue{Key: PaymentTermsNet30, Value: "30天"}
|
||||
PaymentTermsNet60KeyValue = PaymentTermsKeyValue{Key: PaymentTermsNet60, Value: "60天"}
|
||||
PaymentTermsNet90KeyValue = PaymentTermsKeyValue{Key: PaymentTermsNet90, Value: "90天"}
|
||||
)
|
||||
|
||||
func GetAllPaymentTermsKeyValue() []PaymentTermsKeyValue {
|
||||
return []PaymentTermsKeyValue{
|
||||
PaymentTermsNet30KeyValue,
|
||||
PaymentTermsNet60KeyValue,
|
||||
PaymentTermsNet90KeyValue,
|
||||
}
|
||||
}
|
||||
|
||||
var paymentTermsValueMap = map[PaymentTerms]string{
|
||||
PaymentTermsNet30: PaymentTermsNet30KeyValue.Value,
|
||||
PaymentTermsNet60: PaymentTermsNet60KeyValue.Value,
|
||||
PaymentTermsNet90: PaymentTermsNet90KeyValue.Value,
|
||||
}
|
||||
|
||||
func GetPaymentTermsValueByKey(key PaymentTerms) (value string) {
|
||||
value, exists := paymentTermsValueMap[key]
|
||||
if !exists {
|
||||
value = "未知支付条款"
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package public
|
||||
|
||||
// PostgreSQL表名常量
|
||||
const (
|
||||
PlatformTable = "cid_platform" // 平台管理表
|
||||
ApiInterfaceTable = "cid_api_interface" // 接口管理表
|
||||
DataFetchLogTable = "cid_data_fetch_log" // 数据获取日志表
|
||||
DataMappingTable = "cid_data_mapping" // 数据映射表
|
||||
ApplicationTable = "cid_application" // 应用管理表
|
||||
)
|
||||
@@ -1,31 +0,0 @@
|
||||
package consts
|
||||
|
||||
const (
|
||||
AdRequestLimitKeyPrefix = "ad_request_limit:" // 广告请求限流键前缀
|
||||
RateLimitKeyPrefix = "rate_limit:" // 通用限流键前缀
|
||||
SessionCacheKeyPrefix = "session_cache:" // 会话缓存键前缀
|
||||
)
|
||||
|
||||
// 广告缓存键
|
||||
const (
|
||||
AdCacheKeyPrefix = "cid:ad:" // 广告缓存前缀
|
||||
AdPositionCacheKeyPrefix = "cid:pos:" // 广告位缓存前缀
|
||||
AdvertiserCacheKeyPrefix = "cid:adv:" // 广告主缓存前缀
|
||||
)
|
||||
|
||||
// 广告匹配键
|
||||
const (
|
||||
AdMatchingKeyPrefix = "cid:match:" // 广告匹配键前缀
|
||||
UserProfileKeyPrefix = "cid:user:" // 用户画像键前缀
|
||||
)
|
||||
|
||||
// 限流键
|
||||
const (
|
||||
ApiRequestLimitKeyPrefix = "cid:limit:api:" // API请求限流键前缀
|
||||
)
|
||||
|
||||
// Stream键
|
||||
const (
|
||||
AdEventStreamKey = "cid:stream:ad_event" // 广告事件流
|
||||
UserBehaviorStreamKey = "cid:stream:user_behavior" // 用户行为流
|
||||
)
|
||||
@@ -1,65 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cid/model/dto"
|
||||
"cid/service"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
type adPosition struct{}
|
||||
|
||||
var AdPosition = new(adPosition)
|
||||
|
||||
// Add 添加广告位
|
||||
func (c *adPosition) Add(ctx context.Context, req *dto.AddAdPositionReq) (res *dto.AddAdPositionRes, err error) {
|
||||
return service.AdPosition.Add(ctx, req)
|
||||
}
|
||||
|
||||
// Update 更新广告位
|
||||
func (c *adPosition) Update(ctx context.Context, req *dto.UpdateAdPositionReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.AdPosition.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告位状态
|
||||
func (c *adPosition) UpdateStatus(ctx context.Context, req *dto.UpdateAdPositionStatusReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.AdPosition.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取广告位详情
|
||||
func (c *adPosition) GetOne(ctx context.Context, req *dto.GetAdPositionReq) (res *dto.GetAdPositionRes, err error) {
|
||||
return service.AdPosition.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// List 获取广告位列表
|
||||
func (c *adPosition) List(ctx context.Context, req *dto.ListAdPositionReq) (res *dto.ListAdPositionRes, err error) {
|
||||
return service.AdPosition.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetAvailableAdPositions 获取可用的广告位列表
|
||||
func (c *adPosition) GetAvailableAdPositions(ctx context.Context, _ *dto.GetAvailableAdPositionsReq) (res *dto.GetAvailableAdPositionsRes, err error) {
|
||||
list, err := service.AdPosition.GetAvailableAdPositions(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.GetAvailableAdPositionsRes{
|
||||
List: list,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MatchAd 匹配广告
|
||||
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
|
||||
}
|
||||
|
||||
return &dto.MatchAdRes{
|
||||
Advertisement: ad,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cid/model/dto"
|
||||
"cid/service"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
var AdSource = new(adSource)
|
||||
|
||||
type adSource struct{}
|
||||
|
||||
// Create 创建广告源
|
||||
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
|
||||
}
|
||||
|
||||
adSource, err := service.AdSource.GetAdSourceByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.GetAdSourceRes{
|
||||
AdSource: adSource,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Update 更新广告源
|
||||
func (c *adSource) Update(ctx context.Context, req *dto.UpdateAdSourceReq) (res *dto.GetAdSourceRes, err error) {
|
||||
affected, err := service.AdSource.UpdateAdSource(ctx, req.Id, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if affected == 0 {
|
||||
return nil, gerror.New("广告源更新失败")
|
||||
}
|
||||
|
||||
adSource, err := service.AdSource.GetAdSourceByID(ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.GetAdSourceRes{
|
||||
AdSource: adSource,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Delete 删除广告源
|
||||
func (c *adSource) Delete(ctx context.Context, req *dto.DeleteAdSourceReq) (res *dto.DeleteAdSourceRes, err error) {
|
||||
affected, err := service.AdSource.DeleteAdSource(ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if affected == 0 {
|
||||
return nil, gerror.New("广告源删除失败")
|
||||
}
|
||||
|
||||
return &dto.DeleteAdSourceRes{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取广告源
|
||||
func (c *adSource) GetByID(ctx context.Context, req *dto.GetAdSourceReq) (res *dto.GetAdSourceRes, err error) {
|
||||
adSource, err := service.AdSource.GetAdSourceByID(ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if adSource == nil {
|
||||
return nil, gerror.New("广告源不存在")
|
||||
}
|
||||
|
||||
return &dto.GetAdSourceRes{
|
||||
AdSource: adSource,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// List 获取广告源列表
|
||||
func (c *adSource) List(ctx context.Context, req *dto.ListAdSourceReq) (res *dto.ListAdSourceRes, err error) {
|
||||
adSources, err := service.AdSource.GetAvailableSources(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.ListAdSourceRes{
|
||||
List: adSources,
|
||||
Total: len(adSources),
|
||||
}, nil
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"cid/model/dto"
|
||||
"cid/service"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
type advertisement struct{}
|
||||
|
||||
var Advertisement = new(advertisement)
|
||||
|
||||
// Add 添加广告
|
||||
func (c *advertisement) Add(ctx context.Context, req *dto.AddAdvertisementReq) (res *dto.AddAdvertisementRes, err error) {
|
||||
return service.Advertisement.Add(ctx, req)
|
||||
}
|
||||
|
||||
// Update 更新广告
|
||||
func (c *advertisement) Update(ctx context.Context, req *dto.UpdateAdvertisementReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Advertisement.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告状态
|
||||
func (c *advertisement) UpdateStatus(ctx context.Context, req *dto.UpdateAdStatusReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Advertisement.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// Audit 审核广告
|
||||
func (c *advertisement) Audit(ctx context.Context, req *dto.AuditAdvertisementReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Advertisement.Audit(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取广告详情
|
||||
func (c *advertisement) GetOne(ctx context.Context, req *dto.GetAdvertisementReq) (res *dto.GetAdvertisementRes, err error) {
|
||||
return service.Advertisement.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// List 获取广告列表
|
||||
func (c *advertisement) List(ctx context.Context, req *dto.ListAdvertisementReq) (res *dto.ListAdvertisementRes, err error) {
|
||||
return service.Advertisement.List(ctx, req)
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"cid/model/dto"
|
||||
"cid/service"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
type advertiser struct{}
|
||||
|
||||
var Advertiser = new(advertiser)
|
||||
|
||||
// Add 添加广告主
|
||||
func (c *advertiser) Add(ctx context.Context, req *dto.AddAdvertiserReq) (res *dto.AddAdvertiserRes, err error) {
|
||||
return service.Advertiser.Add(ctx, req)
|
||||
}
|
||||
|
||||
// Update 更新广告主
|
||||
func (c *advertiser) Update(ctx context.Context, req *dto.UpdateAdvertiserReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Advertiser.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告主状态
|
||||
func (c *advertiser) UpdateStatus(ctx context.Context, req *dto.UpdateAdvertiserStatusReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Advertiser.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// Audit 审核广告主
|
||||
func (c *advertiser) Audit(ctx context.Context, req *dto.AuditAdvertiserReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Advertiser.Audit(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// Recharge 充值
|
||||
func (c *advertiser) Recharge(ctx context.Context, req *dto.RechargeAdvertiserReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Advertiser.Recharge(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateCreditLimit 更新授信额度
|
||||
func (c *advertiser) UpdateCreditLimit(ctx context.Context, req *dto.UpdateCreditLimitReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Advertiser.UpdateCreditLimit(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取广告主详情
|
||||
func (c *advertiser) GetOne(ctx context.Context, req *dto.GetAdvertiserReq) (res *dto.GetAdvertiserRes, err error) {
|
||||
return service.Advertiser.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// List 获取广告主列表
|
||||
func (c *advertiser) List(ctx context.Context, req *dto.ListAdvertiserReq) (res *dto.ListAdvertiserRes, err error) {
|
||||
return service.Advertiser.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetBalance 获取广告主余额
|
||||
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
|
||||
}
|
||||
|
||||
return &dto.GetAdvertiserBalanceRes{
|
||||
Balance: balance,
|
||||
CreditLimit: creditLimit,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
dto "cid/model/dto/app"
|
||||
service "cid/service/app"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
type applicationController struct{}
|
||||
|
||||
// Application 应用控制器
|
||||
var Application = new(applicationController)
|
||||
|
||||
// CreateApplication 创建应用
|
||||
func (c *applicationController) CreateApplication(ctx context.Context, req *dto.CreateApplicationReq) (res *dto.CreateApplicationRes, err error) {
|
||||
return service.Application.Create(ctx, req)
|
||||
}
|
||||
|
||||
// ListApplication 获取应用列表
|
||||
func (c *applicationController) ListApplication(ctx context.Context, req *dto.ListApplicationReq) (res *dto.ListApplicationRes, err error) {
|
||||
return service.Application.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetApplication 获取应用详情
|
||||
func (c *applicationController) GetApplication(ctx context.Context, req *dto.GetApplicationReq) (res *dto.GetApplicationRes, err error) {
|
||||
return service.Application.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// UpdateApplication 更新应用
|
||||
func (c *applicationController) UpdateApplication(ctx context.Context, req *dto.UpdateApplicationReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Application.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateApplicationStatus 更新应用状态
|
||||
func (c *applicationController) UpdateApplicationStatus(ctx context.Context, req *dto.UpdateApplicationStatusReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Application.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteApplication 删除应用
|
||||
func (c *applicationController) DeleteApplication(ctx context.Context, req *dto.DeleteApplicationReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Application.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"cid/model/dto"
|
||||
"cid/service"
|
||||
)
|
||||
|
||||
var Application = new(application)
|
||||
|
||||
type application struct{}
|
||||
|
||||
// CreateApplication 创建应用
|
||||
func (c *application) CreateApplication(ctx context.Context, req *dto.CreateApplicationReq) (res *dto.CreateApplicationRes, err error) {
|
||||
idStr, err := service.Application.CreateApplication(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 将字符串ID转换为int64
|
||||
id, _ := strconv.ParseInt(idStr, 10, 64)
|
||||
|
||||
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, strconv.FormatInt(req.ID, 10), 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, strconv.FormatInt(req.ID, 10))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 将ObjectId的十六进制字符串转换为int64,如果失败则使用0
|
||||
id, _ := strconv.ParseInt(app.Id.Hex(), 16, 64)
|
||||
// Application实体中没有TenantId字段,暂时设为0
|
||||
tenantID := int64(0)
|
||||
|
||||
return &dto.GetApplicationRes{
|
||||
ID: id,
|
||||
TenantID: 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, strconv.FormatInt(req.TenantID, 10), 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 {
|
||||
id, _ := strconv.ParseInt(app.Id.Hex(), 16, 64)
|
||||
appItems[i] = dto.ApplicationItem{
|
||||
ID: 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, strconv.FormatInt(req.ID, 10))
|
||||
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
|
||||
}
|
||||
|
||||
// 将ObjectId的十六进制字符串转换为int64,如果失败则使用0
|
||||
appID, _ := strconv.ParseInt(app.Id.Hex(), 16, 64)
|
||||
// Application实体中没有TenantId字段,暂时设为0
|
||||
tenantID := int64(0)
|
||||
tentantName := ""
|
||||
|
||||
return &dto.ValidateApplicationRes{
|
||||
Valid: true,
|
||||
AppID: appID,
|
||||
AppName: app.Name,
|
||||
TenantID: 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, strconv.FormatInt(req.ID, 10))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.DeleteApplicationRes{
|
||||
Success: affected > 0,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cid/model/dto"
|
||||
"cid/service"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
var CID = new(cid)
|
||||
|
||||
type cid struct{}
|
||||
|
||||
// GenerateCID 生成CID广告
|
||||
func (c *cid) GenerateCID(ctx context.Context, req *dto.GenerateCIDReq) (res *dto.GenerateCIDRes, err error) {
|
||||
if req == nil {
|
||||
return nil, gerror.New("请求参数不能为空")
|
||||
}
|
||||
|
||||
if req.RequestType == "" {
|
||||
req.RequestType = "default" // 默认请求类型
|
||||
}
|
||||
|
||||
result, err := service.CID.GenerateCID(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetCIDHistory 获取CID历史记录
|
||||
func (c *cid) GetCIDHistory(ctx context.Context, req *dto.GetCIDHistoryReq) (res *dto.GetCIDHistoryRes, err error) {
|
||||
if req == nil {
|
||||
return nil, gerror.New("请求参数不能为空")
|
||||
}
|
||||
|
||||
// 查询历史记录
|
||||
history, err := service.CID.GetCIDHistory(ctx, 1, req.Page, req.Size) // 临时使用固定用户ID
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return history, nil
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
dto "cid/model/dto/data"
|
||||
service "cid/service/data"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
type apiInterfaceController struct{}
|
||||
|
||||
// ApiInterface 接口控制器
|
||||
var ApiInterface = new(apiInterfaceController)
|
||||
|
||||
// CreateApiInterface 创建接口
|
||||
func (c *apiInterfaceController) CreateApiInterface(ctx context.Context, req *dto.CreateApiInterfaceReq) (res *dto.CreateApiInterfaceRes, err error) {
|
||||
return service.ApiInterface.Create(ctx, req)
|
||||
}
|
||||
|
||||
// ListApiInterface 获取接口列表
|
||||
func (c *apiInterfaceController) ListApiInterface(ctx context.Context, req *dto.ListApiInterfaceReq) (res *dto.ListApiInterfaceRes, err error) {
|
||||
return service.ApiInterface.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetApiInterface 获取接口详情
|
||||
func (c *apiInterfaceController) GetApiInterface(ctx context.Context, req *dto.GetApiInterfaceReq) (res *dto.GetApiInterfaceRes, err error) {
|
||||
return service.ApiInterface.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// UpdateApiInterface 更新接口
|
||||
func (c *apiInterfaceController) UpdateApiInterface(ctx context.Context, req *dto.UpdateApiInterfaceReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.ApiInterface.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateApiInterfaceStatus 更新接口状态
|
||||
func (c *apiInterfaceController) UpdateApiInterfaceStatus(ctx context.Context, req *dto.UpdateApiInterfaceStatusReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.ApiInterface.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteApiInterface 删除接口
|
||||
func (c *apiInterfaceController) DeleteApiInterface(ctx context.Context, req *dto.DeleteApiInterfaceReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.ApiInterface.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
dto "cid/model/dto/data"
|
||||
service "cid/service/data"
|
||||
"context"
|
||||
)
|
||||
|
||||
type dataFetchController struct{}
|
||||
|
||||
// DataFetch 数据获取控制器
|
||||
var DataFetch = new(dataFetchController)
|
||||
|
||||
// ExecuteDataFetch 执行数据获取
|
||||
func (c *dataFetchController) ExecuteDataFetch(ctx context.Context, req *dto.ExecuteDataFetchReq) (res *dto.ExecuteDataFetchRes, err error) {
|
||||
return service.DataFetch.Execute(ctx, req)
|
||||
}
|
||||
|
||||
// BatchExecuteDataFetch 批量执行数据获取
|
||||
func (c *dataFetchController) BatchExecuteDataFetch(ctx context.Context, req *dto.BatchExecuteDataFetchReq) (res *dto.BatchExecuteDataFetchRes, err error) {
|
||||
return service.DataFetch.BatchExecute(ctx, req)
|
||||
}
|
||||
|
||||
// ListDataFetchLog 获取数据获取日志列表
|
||||
func (c *dataFetchController) ListDataFetchLog(ctx context.Context, req *dto.ListDataFetchLogReq) (res *dto.ListDataFetchLogRes, err error) {
|
||||
return service.DataFetch.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetDataFetchLog 获取数据获取日志详情
|
||||
func (c *dataFetchController) GetDataFetchLog(ctx context.Context, req *dto.GetDataFetchLogReq) (res *dto.GetDataFetchLogRes, err error) {
|
||||
return service.DataFetch.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// ReExecuteDataFetch 重新执行数据获取
|
||||
func (c *dataFetchController) ReExecuteDataFetch(ctx context.Context, req *dto.ReExecuteDataFetchReq) (res *dto.ReExecuteDataFetchRes, err error) {
|
||||
return service.DataFetch.ReExecute(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
dto "cid/model/dto/data"
|
||||
service "cid/service/data"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
type platformController struct{}
|
||||
|
||||
// Platform 平台控制器
|
||||
var Platform = new(platformController)
|
||||
|
||||
// CreatePlatform 创建平台
|
||||
func (c *platformController) CreatePlatform(ctx context.Context, req *dto.CreatePlatformReq) (res *dto.CreatePlatformRes, err error) {
|
||||
return service.Platform.Create(ctx, req)
|
||||
}
|
||||
|
||||
// ListPlatform 获取平台列表
|
||||
func (c *platformController) ListPlatform(ctx context.Context, req *dto.ListPlatformReq) (res *dto.ListPlatformRes, err error) {
|
||||
return service.Platform.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetPlatform 获取平台详情
|
||||
func (c *platformController) GetPlatform(ctx context.Context, req *dto.GetPlatformReq) (res *dto.GetPlatformRes, err error) {
|
||||
return service.Platform.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// UpdatePlatform 更新平台
|
||||
func (c *platformController) UpdatePlatform(ctx context.Context, req *dto.UpdatePlatformReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Platform.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdatePlatformStatus 更新平台状态
|
||||
func (c *platformController) UpdatePlatformStatus(ctx context.Context, req *dto.UpdatePlatformStatusReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Platform.UpdateStatus(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// DeletePlatform 删除平台
|
||||
func (c *platformController) DeletePlatform(ctx context.Context, req *dto.DeletePlatformReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.Platform.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package mapping
|
||||
|
||||
import (
|
||||
dto "cid/model/dto/mapping"
|
||||
service "cid/service/mapping"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
type dataMappingController struct{}
|
||||
|
||||
// DataMapping 数据映射控制器
|
||||
var DataMapping = new(dataMappingController)
|
||||
|
||||
// CreateDataMapping 创建数据映射
|
||||
func (c *dataMappingController) CreateDataMapping(ctx context.Context, req *dto.CreateDataMappingReq) (res *dto.CreateDataMappingRes, err error) {
|
||||
return service.DataMapping.Create(ctx, req)
|
||||
}
|
||||
|
||||
// BatchCreateDataMappings 批量创建数据映射
|
||||
func (c *dataMappingController) BatchCreateDataMappings(ctx context.Context, req *dto.BatchCreateDataMappingReq) (res *dto.BatchCreateDataMappingRes, err error) {
|
||||
return service.DataMapping.BatchCreate(ctx, req)
|
||||
}
|
||||
|
||||
// ListDataMapping 获取数据映射列表
|
||||
func (c *dataMappingController) ListDataMapping(ctx context.Context, req *dto.ListDataMappingReq) (res *dto.ListDataMappingRes, err error) {
|
||||
return service.DataMapping.List(ctx, req)
|
||||
}
|
||||
|
||||
// GetDataMapping 获取数据映射详情
|
||||
func (c *dataMappingController) GetDataMapping(ctx context.Context, req *dto.GetDataMappingReq) (res *dto.GetDataMappingRes, err error) {
|
||||
return service.DataMapping.GetOne(ctx, req)
|
||||
}
|
||||
|
||||
// UpdateDataMapping 更新数据映射
|
||||
func (c *dataMappingController) UpdateDataMapping(ctx context.Context, req *dto.UpdateDataMappingReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.DataMapping.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteDataMapping 删除数据映射
|
||||
func (c *dataMappingController) DeleteDataMapping(ctx context.Context, req *dto.DeleteDataMappingReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.DataMapping.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// ExecuteDataMapping 执行数据映射
|
||||
func (c *dataMappingController) ExecuteDataMapping(ctx context.Context, req *dto.ExecuteDataMappingReq) (res *dto.ExecuteDataMappingRes, err error) {
|
||||
return service.DataMapping.Execute(ctx, req)
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cid/model/dto"
|
||||
"cid/service"
|
||||
)
|
||||
|
||||
var RateLimit = new(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
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cid/model/dto"
|
||||
"cid/service"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
var Strategy = new(strategy)
|
||||
|
||||
type strategy struct{}
|
||||
|
||||
// Create 创建策略
|
||||
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
|
||||
}
|
||||
|
||||
strategy, err := service.Strategy.GetStrategyByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return strategy, nil
|
||||
}
|
||||
|
||||
// Update 更新策略
|
||||
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
|
||||
}
|
||||
if affected == 0 {
|
||||
return nil, gerror.New("策略更新失败")
|
||||
}
|
||||
|
||||
strategy, err := service.Strategy.GetStrategyByID(ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return strategy, nil
|
||||
}
|
||||
|
||||
// Delete 删除策略
|
||||
func (c *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
|
||||
}
|
||||
if affected == 0 {
|
||||
return nil, gerror.New("策略删除失败")
|
||||
}
|
||||
|
||||
return &dto.DeleteStrategyRes{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取策略
|
||||
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
|
||||
}
|
||||
|
||||
return strategy, nil
|
||||
}
|
||||
|
||||
// GetList 获取策略列表
|
||||
func (c *strategy) GetList(ctx context.Context, req *dto.GetStrategyListReq) (res *dto.GetStrategyListRes, err error) {
|
||||
return service.Strategy.GetStrategyList(ctx, req)
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"cid/model/dto"
|
||||
"cid/model/entity"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"gitea.com/red-future/common/db/mongo"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
var AdPosition = &adPosition{}
|
||||
|
||||
type adPosition struct {
|
||||
}
|
||||
|
||||
// Insert 插入广告位
|
||||
func (d *adPosition) Insert(ctx context.Context, req *dto.AddAdPositionReq) (ids []any, err error) {
|
||||
var result entity.AdPosition
|
||||
if err = gconv.Struct(req, &result); err != nil {
|
||||
return
|
||||
}
|
||||
ids, err = mongo.DB().Insert(ctx, []interface{}{&result}, entity.AdPositionCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// Update 更新广告位
|
||||
func (d *adPosition) Update(ctx context.Context, id *bson.ObjectID, updateData *entity.AdPosition) (err error) {
|
||||
filter := bson.M{"_id": id}
|
||||
|
||||
if !g.IsEmpty(updateData) {
|
||||
bsonm, err := mongo.BuildUpdateData(ctx, updateData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
update := bson.M{"$set": bsonm}
|
||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdPositionCollection)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告位状态
|
||||
func (d *adPosition) UpdateStatus(ctx context.Context, id *bson.ObjectID, status string) (err error) {
|
||||
filter := bson.M{"_id": id}
|
||||
update := bson.M{"$set": bson.M{"status": status}}
|
||||
|
||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdPositionCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取单个广告位
|
||||
func (d *adPosition) GetOne(ctx context.Context, id *bson.ObjectID) (adPosition *entity.AdPosition, err error) {
|
||||
filter := bson.M{"_id": id}
|
||||
|
||||
adPosition = &entity.AdPosition{}
|
||||
err = mongo.DB().FindOne(ctx, filter, adPosition, entity.AdPositionCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除广告位
|
||||
func (d *adPosition) Delete(ctx context.Context, id *bson.ObjectID) (err error) {
|
||||
filter := bson.M{"_id": id}
|
||||
_, err = mongo.DB().Delete(ctx, filter, entity.AdPositionCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表查询的过滤条件
|
||||
func (d *adPosition) buildListFilter(req *dto.ListAdPositionReq) bson.M {
|
||||
filter := bson.M{}
|
||||
|
||||
if !g.IsEmpty(req.Name) {
|
||||
filter["name"] = bson.M{"$regex": req.Name, "$options": "i"}
|
||||
}
|
||||
if !g.IsEmpty(req.PositionCode) {
|
||||
filter["positionCode"] = req.PositionCode
|
||||
}
|
||||
if !g.IsEmpty(req.PageName) {
|
||||
filter["page"] = req.PageName
|
||||
}
|
||||
if !g.IsEmpty(req.Section) {
|
||||
filter["section"] = req.Section
|
||||
}
|
||||
if !g.IsEmpty(req.Status) {
|
||||
filter["status"] = req.Status
|
||||
}
|
||||
if !g.IsEmpty(req.AdFormat) {
|
||||
filter["adFormat"] = req.AdFormat
|
||||
}
|
||||
|
||||
// 处理日期范围
|
||||
if len(req.DateRange) == 2 {
|
||||
startTime := gconv.Int64(req.DateRange[0])
|
||||
endTime := gconv.Int64(req.DateRange[1])
|
||||
filter["createdAt"] = bson.M{
|
||||
"$gte": startTime,
|
||||
"$lte": endTime,
|
||||
}
|
||||
}
|
||||
|
||||
return filter
|
||||
}
|
||||
|
||||
// List 获取广告位列表
|
||||
func (d *adPosition) List(ctx context.Context, req *dto.ListAdPositionReq) (list []*entity.AdPosition, total int64, err error) {
|
||||
// 构建查询过滤条件
|
||||
filter := d.buildListFilter(req)
|
||||
|
||||
// 使用common/mongo的Find方法,自动处理分页、租户等
|
||||
total, err = mongo.DB().Find(ctx, filter, &list, entity.AdPositionCollection, req.Page, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// GetAvailableAdPositions 获取可用的广告位列表
|
||||
func (d *adPosition) GetAvailableAdPositions(ctx context.Context) (list []*entity.AdPosition, err error) {
|
||||
filter := bson.M{
|
||||
"status": "启用", // 只返回启用的广告位
|
||||
}
|
||||
|
||||
// 使用空的Page参数获取所有数据
|
||||
page := &beans.Page{PageNum: 1, PageSize: -1} // -1表示不分页
|
||||
_, err = mongo.DB().Find(ctx, filter, &list, entity.AdPositionCollection, page, nil)
|
||||
return
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cid/consts"
|
||||
"cid/model/entity"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"gitea.com/red-future/common/db/mongo"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
var AdSource = &adSourceDao{}
|
||||
|
||||
type adSourceDao struct {
|
||||
}
|
||||
|
||||
// GetByName 根据名称获取广告源
|
||||
func (d *adSourceDao) GetByName(ctx context.Context, name string) (adSource *entity.AdSource, err error) {
|
||||
err = mongo.DB().FindOne(ctx, bson.M{"name": name}, &adSource, consts.AdSourceCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// GetAvailableSources 获取可用的广告源
|
||||
func (d *adSourceDao) GetAvailableSources(ctx context.Context) (list []*entity.AdSource, err error) {
|
||||
// 使用空的Page参数获取所有数据
|
||||
page := &beans.Page{PageNum: 1, PageSize: -1} // -1表示不分页
|
||||
_, err = mongo.DB().Find(ctx, bson.M{"status": "active"}, &list, consts.AdSourceCollection, page, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// GetSourcesByProvider 根据提供商获取广告源
|
||||
func (d *adSourceDao) GetSourcesByProvider(ctx context.Context, provider string) (list []*entity.AdSource, err error) {
|
||||
// 使用空的Page参数获取所有数据
|
||||
page := &beans.Page{PageNum: 1, PageSize: -1} // -1表示不分页
|
||||
_, err = mongo.DB().Find(ctx, bson.M{"provider": provider, "status": "active"}, &list, consts.AdSourceCollection, page, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Create 创建广告源
|
||||
func (d *adSourceDao) Create(ctx context.Context, adSource *entity.AdSource) (id string, err error) {
|
||||
ids, err := mongo.DB().Insert(ctx, []interface{}{adSource}, consts.AdSourceCollection)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
id = ids[0].(string)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Update 更新广告源
|
||||
func (d *adSourceDao) Update(ctx context.Context, adSource *entity.AdSource) (affected int64, err error) {
|
||||
result, err := mongo.DB().Update(ctx, bson.M{"_id": adSource.Id}, bson.M{"$set": adSource}, consts.AdSourceCollection)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Delete 删除广告源
|
||||
func (d *adSourceDao) Delete(ctx context.Context, id string) (affected int64, err error) {
|
||||
count, err := mongo.DB().Delete(ctx, bson.M{"_id": id}, consts.AdSourceCollection)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取广告源
|
||||
func (d *adSourceDao) GetByID(ctx context.Context, id string) (adSource *entity.AdSource, err error) {
|
||||
err = mongo.DB().FindOne(ctx, bson.M{"_id": id}, &adSource, consts.AdSourceCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateFields 更新广告源部分字段
|
||||
func (d *adSourceDao) UpdateFields(ctx context.Context, id string, data *entity.AdSource) (affected int64, err error) {
|
||||
result, err := mongo.DB().Update(ctx, bson.M{"_id": id}, bson.M{"$set": data}, consts.AdSourceCollection)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,235 +0,0 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"cid/model/dto"
|
||||
"cid/model/entity"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"gitea.com/red-future/common/db/mongo"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
var Advertisement = &advertisement{}
|
||||
|
||||
type advertisement struct {
|
||||
}
|
||||
|
||||
// Insert 插入广告
|
||||
func (d *advertisement) Insert(ctx context.Context, advertisement *entity.Advertisement) (err error) {
|
||||
// 获取stream消息
|
||||
redis := g.Redis()
|
||||
streamMsg, err := redis.Do(ctx, "XREAD", "STREAMS", "advertisement_stream", "$")
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "获取stream消息失败: %v", err)
|
||||
} else {
|
||||
g.Log().Infof(ctx, "获取到stream消息: %v", streamMsg)
|
||||
}
|
||||
|
||||
_, err = mongo.DB().Insert(ctx, []interface{}{advertisement}, entity.AdvertisementCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// Update 更新广告
|
||||
func (d *advertisement) Update(ctx context.Context, req *dto.UpdateAdvertisementReq) (err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(req.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
|
||||
// 构建动态更新字段
|
||||
updateFields := bson.M{}
|
||||
|
||||
// 广告基本信息
|
||||
if !g.IsEmpty(req.Title) {
|
||||
updateFields["title"] = req.Title
|
||||
}
|
||||
if !g.IsEmpty(req.Description) {
|
||||
updateFields["description"] = req.Description
|
||||
}
|
||||
if !g.IsEmpty(req.AdvertiserId) {
|
||||
updateFields["advertiserId"] = req.AdvertiserId
|
||||
}
|
||||
if !g.IsEmpty(req.AdPositionId) {
|
||||
updateFields["adPositionId"] = req.AdPositionId
|
||||
}
|
||||
if !g.IsEmpty(req.AdType) {
|
||||
updateFields["adType"] = req.AdType
|
||||
}
|
||||
if !g.IsEmpty(req.AdFormat) {
|
||||
updateFields["adFormat"] = req.AdFormat
|
||||
}
|
||||
if !g.IsEmpty(req.MaterialUrl) {
|
||||
updateFields["materialUrl"] = req.MaterialUrl
|
||||
}
|
||||
if !g.IsEmpty(req.TargetUrl) {
|
||||
updateFields["targetUrl"] = req.TargetUrl
|
||||
}
|
||||
|
||||
// 投放设置
|
||||
if req.StartDate != nil {
|
||||
updateFields["startDate"] = *req.StartDate
|
||||
}
|
||||
if req.EndDate != nil {
|
||||
updateFields["endDate"] = *req.EndDate
|
||||
}
|
||||
if req.Budget != nil {
|
||||
updateFields["budget"] = *req.Budget
|
||||
}
|
||||
if req.DailyBudget != nil {
|
||||
updateFields["dailyBudget"] = *req.DailyBudget
|
||||
}
|
||||
if req.BidAmount != nil {
|
||||
updateFields["bidAmount"] = *req.BidAmount
|
||||
}
|
||||
if !g.IsEmpty(req.BillingType) {
|
||||
updateFields["billingType"] = req.BillingType
|
||||
}
|
||||
|
||||
// 投放条件
|
||||
if req.Targeting != nil {
|
||||
updateFields["targeting"] = req.Targeting
|
||||
}
|
||||
|
||||
// 状态信息
|
||||
if req.Status != nil {
|
||||
updateFields["status"] = *req.Status
|
||||
}
|
||||
if req.AuditStatus != nil {
|
||||
updateFields["auditStatus"] = *req.AuditStatus
|
||||
}
|
||||
if req.AuditReason != nil {
|
||||
updateFields["auditReason"] = *req.AuditReason
|
||||
}
|
||||
|
||||
if len(updateFields) > 0 {
|
||||
update := bson.M{"$set": updateFields}
|
||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertisementCollection)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告状态
|
||||
func (d *advertisement) UpdateStatus(ctx context.Context, id, status string) (err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
update := bson.M{"$set": bson.M{"status": status}}
|
||||
|
||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertisementCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// Audit 审核广告
|
||||
func (d *advertisement) Audit(ctx context.Context, id, auditStatus, auditReason string) (err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
|
||||
// 获取当前用户ID(实际项目中应从上下文获取)
|
||||
auditBy := "system"
|
||||
auditTime := time.Now().Unix()
|
||||
|
||||
update := bson.M{
|
||||
"$set": bson.M{
|
||||
"auditStatus": auditStatus,
|
||||
"auditReason": auditReason,
|
||||
"auditTime": auditTime,
|
||||
"auditBy": auditBy,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertisementCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatistics 更新广告统计数据
|
||||
func (d *advertisement) UpdateStatistics(ctx context.Context, id string, stats map[string]interface{}) (err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
update := bson.M{"$set": stats}
|
||||
|
||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertisementCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取单个广告
|
||||
func (d *advertisement) GetOne(ctx context.Context, id string) (advertisement *entity.Advertisement, err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
|
||||
advertisement = &entity.Advertisement{}
|
||||
err = mongo.DB().FindOne(ctx, filter, advertisement, entity.AdvertisementCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表查询的过滤条件
|
||||
func (d *advertisement) buildListFilter(req *dto.ListAdvertisementReq) bson.M {
|
||||
filter := bson.M{}
|
||||
|
||||
if !g.IsEmpty(req.AdvertiserId) {
|
||||
filter["advertiserId"] = req.AdvertiserId
|
||||
}
|
||||
if !g.IsEmpty(req.AdPositionId) {
|
||||
filter["adPositionId"] = req.AdPositionId
|
||||
}
|
||||
if !g.IsEmpty(req.AdType) {
|
||||
filter["adType"] = req.AdType
|
||||
}
|
||||
if !g.IsEmpty(req.Status) {
|
||||
filter["status"] = req.Status
|
||||
}
|
||||
if !g.IsEmpty(req.AuditStatus) {
|
||||
filter["auditStatus"] = req.AuditStatus
|
||||
}
|
||||
if !g.IsEmpty(req.Title) {
|
||||
filter["title"] = bson.M{"$regex": req.Title, "$options": "i"}
|
||||
}
|
||||
|
||||
// 处理日期范围
|
||||
if len(req.DateRange) == 2 {
|
||||
startTime := gconv.Int64(req.DateRange[0])
|
||||
endTime := gconv.Int64(req.DateRange[1])
|
||||
filter["createdAt"] = bson.M{
|
||||
"$gte": startTime,
|
||||
"$lte": endTime,
|
||||
}
|
||||
}
|
||||
|
||||
return filter
|
||||
}
|
||||
|
||||
// checkTotalCount 检查总数
|
||||
func (d *advertisement) checkTotalCount(ctx context.Context, filter bson.M) (total int64, err error) {
|
||||
total, err = mongo.DB().Count(ctx, filter, entity.AdvertisementCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取广告列表
|
||||
func (d *advertisement) List(ctx context.Context, req *dto.ListAdvertisementReq) (list []*entity.Advertisement, total int64, err error) {
|
||||
// 构建查询过滤条件
|
||||
filter := d.buildListFilter(req)
|
||||
|
||||
// 检查总数
|
||||
total, err = d.checkTotalCount(ctx, filter)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 使用common/mongo的Find方法,自动处理分页、租户等
|
||||
total, err = mongo.DB().Find(ctx, filter, &list, entity.AdvertisementCollection, req.Page, nil)
|
||||
return
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"cid/model/dto"
|
||||
"cid/model/entity"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"gitea.com/red-future/common/db/mongo"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
var Advertiser = &advertiser{}
|
||||
|
||||
type advertiser struct {
|
||||
}
|
||||
|
||||
// Insert 插入广告主
|
||||
func (d *advertiser) Insert(ctx context.Context, advertiser *entity.Advertiser) (err error) {
|
||||
// 获取stream消息
|
||||
redis := g.Redis()
|
||||
streamMsg, err := redis.Do(ctx, "XREAD", "STREAMS", "advertiser_stream", "$")
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "获取stream消息失败: %v", err)
|
||||
} else {
|
||||
g.Log().Infof(ctx, "获取到stream消息: %v", streamMsg)
|
||||
}
|
||||
|
||||
_, err = mongo.DB().Insert(ctx, []interface{}{advertiser}, entity.AdvertiserCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// Update 更新广告主
|
||||
func (d *advertiser) Update(ctx context.Context, req *dto.UpdateAdvertiserReq) (err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(req.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
|
||||
// 构建动态更新字段
|
||||
updateFields := bson.M{}
|
||||
|
||||
// 基本信息
|
||||
if !g.IsEmpty(req.Name) {
|
||||
updateFields["name"] = req.Name
|
||||
}
|
||||
if !g.IsEmpty(req.ContactName) {
|
||||
updateFields["contactName"] = req.ContactName
|
||||
}
|
||||
if !g.IsEmpty(req.ContactPhone) {
|
||||
updateFields["contactPhone"] = req.ContactPhone
|
||||
}
|
||||
if !g.IsEmpty(req.ContactEmail) {
|
||||
updateFields["contactEmail"] = req.ContactEmail
|
||||
}
|
||||
if !g.IsEmpty(req.Company) {
|
||||
updateFields["company"] = req.Company
|
||||
}
|
||||
if !g.IsEmpty(req.Industry) {
|
||||
updateFields["industry"] = req.Industry
|
||||
}
|
||||
if !g.IsEmpty(req.Scale) {
|
||||
updateFields["scale"] = req.Scale
|
||||
}
|
||||
|
||||
// 证件信息
|
||||
if !g.IsEmpty(req.BusinessLicenseUrl) {
|
||||
updateFields["businessLicenseUrl"] = req.BusinessLicenseUrl
|
||||
}
|
||||
if !g.IsEmpty(req.ICPLicenseUrl) {
|
||||
updateFields["icpLicenseUrl"] = req.ICPLicenseUrl
|
||||
}
|
||||
if req.OtherLicenseUrls != nil {
|
||||
updateFields["otherLicenseUrls"] = req.OtherLicenseUrls
|
||||
}
|
||||
|
||||
// 财务信息
|
||||
if !g.IsEmpty(req.BankName) {
|
||||
updateFields["bankName"] = req.BankName
|
||||
}
|
||||
if !g.IsEmpty(req.BankAccount) {
|
||||
updateFields["bankAccount"] = req.BankAccount
|
||||
}
|
||||
if !g.IsEmpty(req.AccountName) {
|
||||
updateFields["accountName"] = req.AccountName
|
||||
}
|
||||
|
||||
// 合同信息
|
||||
if !g.IsEmpty(req.ContractId) {
|
||||
updateFields["contractId"] = req.ContractId
|
||||
}
|
||||
if !g.IsEmpty(req.ContractType) {
|
||||
updateFields["contractType"] = req.ContractType
|
||||
}
|
||||
if !g.IsEmpty(req.ContractUrl) {
|
||||
updateFields["contractUrl"] = req.ContractUrl
|
||||
}
|
||||
if req.SignDate != nil {
|
||||
updateFields["signDate"] = *req.SignDate
|
||||
}
|
||||
if req.ExpireDate != nil {
|
||||
updateFields["expireDate"] = *req.ExpireDate
|
||||
}
|
||||
|
||||
// 系统信息
|
||||
if req.AccountBalance != nil {
|
||||
updateFields["accountBalance"] = *req.AccountBalance
|
||||
}
|
||||
if req.CreditLimit != nil {
|
||||
updateFields["creditLimit"] = *req.CreditLimit
|
||||
}
|
||||
if !g.IsEmpty(req.Remark) {
|
||||
updateFields["remark"] = req.Remark
|
||||
}
|
||||
|
||||
// 状态信息
|
||||
if req.Status != nil {
|
||||
updateFields["status"] = *req.Status
|
||||
}
|
||||
if req.AuditStatus != nil {
|
||||
updateFields["auditStatus"] = *req.AuditStatus
|
||||
}
|
||||
if req.AuditReason != nil {
|
||||
updateFields["auditReason"] = *req.AuditReason
|
||||
}
|
||||
|
||||
if len(updateFields) > 0 {
|
||||
update := bson.M{"$set": updateFields}
|
||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertiserCollection)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告主状态
|
||||
func (d *advertiser) UpdateStatus(ctx context.Context, id, status string) (err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
update := bson.M{"$set": bson.M{"status": status}}
|
||||
|
||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertiserCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// Audit 审核广告主
|
||||
func (d *advertiser) Audit(ctx context.Context, id, auditStatus, auditReason string) (err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
|
||||
// 获取当前用户ID(实际项目中应从上下文获取)
|
||||
auditBy := "system"
|
||||
auditTime := time.Now().Unix()
|
||||
|
||||
update := bson.M{
|
||||
"$set": bson.M{
|
||||
"auditStatus": auditStatus,
|
||||
"auditReason": auditReason,
|
||||
"auditTime": auditTime,
|
||||
"auditBy": auditBy,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertiserCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// Recharge 充值
|
||||
func (d *advertiser) Recharge(ctx context.Context, id string, amount int64, remark string) (err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
|
||||
// 先获取当前余额
|
||||
advertiser := &entity.Advertiser{}
|
||||
err = mongo.DB().FindOne(ctx, filter, advertiser, entity.AdvertiserCollection)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 更新余额
|
||||
newBalance := advertiser.AccountBalance + amount
|
||||
update := bson.M{"$set": bson.M{"accountBalance": newBalance}}
|
||||
|
||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertiserCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateCreditLimit 更新授信额度
|
||||
func (d *advertiser) UpdateCreditLimit(ctx context.Context, id string, creditLimit int64) (err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
update := bson.M{"$set": bson.M{"creditLimit": creditLimit}}
|
||||
|
||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertiserCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取单个广告主
|
||||
func (d *advertiser) GetOne(ctx context.Context, id string) (advertiser *entity.Advertiser, err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
|
||||
advertiser = &entity.Advertiser{}
|
||||
err = mongo.DB().FindOne(ctx, filter, advertiser, entity.AdvertiserCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表查询的过滤条件
|
||||
func (d *advertiser) buildListFilter(req *dto.ListAdvertiserReq) bson.M {
|
||||
filter := bson.M{}
|
||||
|
||||
if !g.IsEmpty(req.Name) {
|
||||
filter["name"] = bson.M{"$regex": req.Name, "$options": "i"}
|
||||
}
|
||||
if !g.IsEmpty(req.ContactName) {
|
||||
filter["contactName"] = bson.M{"$regex": req.ContactName, "$options": "i"}
|
||||
}
|
||||
if !g.IsEmpty(req.Company) {
|
||||
filter["company"] = bson.M{"$regex": req.Company, "$options": "i"}
|
||||
}
|
||||
if !g.IsEmpty(req.Industry) {
|
||||
filter["industry"] = req.Industry
|
||||
}
|
||||
if !g.IsEmpty(req.Status) {
|
||||
filter["status"] = req.Status
|
||||
}
|
||||
if !g.IsEmpty(req.AuditStatus) {
|
||||
filter["auditStatus"] = req.AuditStatus
|
||||
}
|
||||
|
||||
// 处理日期范围
|
||||
if len(req.DateRange) == 2 {
|
||||
startTime := gconv.Int64(req.DateRange[0])
|
||||
endTime := gconv.Int64(req.DateRange[1])
|
||||
filter["createdAt"] = bson.M{
|
||||
"$gte": startTime,
|
||||
"$lte": endTime,
|
||||
}
|
||||
}
|
||||
|
||||
return filter
|
||||
}
|
||||
|
||||
// checkTotalCount 检查总数
|
||||
func (d *advertiser) checkTotalCount(ctx context.Context, filter bson.M) (total int64, err error) {
|
||||
total, err = mongo.DB().Count(ctx, filter, entity.AdvertiserCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取广告主列表
|
||||
func (d *advertiser) List(ctx context.Context, req *dto.ListAdvertiserReq) (list []*entity.Advertiser, total int64, err error) {
|
||||
// 构建查询过滤条件
|
||||
filter := d.buildListFilter(req)
|
||||
|
||||
// 检查总数
|
||||
total, err = d.checkTotalCount(ctx, filter)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 使用common/mongo的Find方法,自动处理分页、租户等
|
||||
total, err = mongo.DB().Find(ctx, filter, &list, entity.AdvertiserCollection, req.Page, nil)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
consts "cid/consts/public"
|
||||
dto "cid/model/dto/app"
|
||||
entity "cid/model/entity/app"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/db/gfdb"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var Application = new(applicationDao)
|
||||
|
||||
type applicationDao struct{}
|
||||
|
||||
// Insert 插入应用
|
||||
func (d *applicationDao) Insert(ctx context.Context, req *dto.CreateApplicationReq) (id int64, err error) {
|
||||
var res *entity.Application
|
||||
if err = gconv.Struct(req, &res); err != nil {
|
||||
return
|
||||
}
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApplicationTable).Data(&res).Insert()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
// Update 更新应用
|
||||
func (d *applicationDao) Update(ctx context.Context, req *dto.UpdateApplicationReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApplicationTable).Data(&req).OmitEmpty().Where(entity.ApplicationCols.Id, req.Id).Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// Delete 删除应用
|
||||
func (d *applicationDao) Delete(ctx context.Context, req *dto.DeleteApplicationReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApplicationTable).Where(entity.ApplicationCols.Id, req.Id).Delete()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetOne 获取单个应用
|
||||
func (d *applicationDao) GetOne(ctx context.Context, req *dto.GetApplicationReq) (res *entity.Application, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApplicationTable).Where(entity.ApplicationCols.Id, req.Id).One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// Count 获取应用数量
|
||||
func (d *applicationDao) Count(ctx context.Context, req *dto.ListApplicationReq) (count int, err error) {
|
||||
return d.buildListFilter(ctx, req).Count()
|
||||
}
|
||||
|
||||
// List 获取应用列表
|
||||
func (d *applicationDao) List(ctx context.Context, req *dto.ListApplicationReq) (res []entity.Application, total int, err error) {
|
||||
model := d.buildListFilter(ctx, req)
|
||||
model.OrderDesc(entity.ApplicationCols.CreatedAt)
|
||||
if req.Page != nil {
|
||||
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
|
||||
}
|
||||
r, total, err := model.AllAndCount(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表查询的过滤条件
|
||||
func (d *applicationDao) buildListFilter(ctx context.Context, req *dto.ListApplicationReq) *gdb.Model {
|
||||
model := gfdb.DB(ctx).Model(ctx, consts.ApplicationTable).Model
|
||||
if !g.IsEmpty(req.Keyword) {
|
||||
model.WhereLike(entity.ApplicationCols.Name, "%"+req.Keyword+"%")
|
||||
model.WhereOrLike(entity.ApplicationCols.AppCode, "%"+req.Keyword+"%")
|
||||
}
|
||||
model.Where(entity.ApplicationCols.Name, req.Name)
|
||||
model.Where(entity.ApplicationCols.AppCode, req.AppCode)
|
||||
model.Where(entity.ApplicationCols.Type, req.Type)
|
||||
model.Where(entity.ApplicationCols.Status, req.Status)
|
||||
model.OmitEmptyWhere()
|
||||
return model
|
||||
}
|
||||
|
||||
// UpdateStatus 更新应用状态
|
||||
func (d *applicationDao) UpdateStatus(ctx context.Context, id int64, status string) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApplicationTable).
|
||||
Data(map[string]interface{}{"status": status}).
|
||||
Where(entity.ApplicationCols.Id, id).
|
||||
Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetByAppCode 根据应用编码获取应用
|
||||
func (d *applicationDao) GetByAppCode(ctx context.Context, appCode string) (res *entity.Application, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApplicationTable).
|
||||
Where(entity.ApplicationCols.AppCode, appCode).
|
||||
One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cid/model/entity"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"gitea.com/red-future/common/db/mongo"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
// applicationDao 应用DAO
|
||||
type applicationDao struct {
|
||||
}
|
||||
|
||||
var Application = &applicationDao{}
|
||||
|
||||
// Create 创建应用
|
||||
func (d *applicationDao) Create(ctx context.Context, app *entity.Application) (string, error) {
|
||||
ids, err := mongo.DB().Insert(ctx, []interface{}{app}, "application")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
return ids[0].(string), nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取应用
|
||||
func (d *applicationDao) GetByID(ctx context.Context, id string) (*entity.Application, error) {
|
||||
var app *entity.Application
|
||||
err := mongo.DB().FindOne(ctx, bson.M{"_id": id}, &app, "application")
|
||||
return app, err
|
||||
}
|
||||
|
||||
// GetByTenantID 根据租户ID获取应用列表
|
||||
func (d *applicationDao) GetByTenantID(ctx context.Context, tenantID string) ([]*entity.Application, error) {
|
||||
var apps []*entity.Application
|
||||
// 使用空的Page参数获取所有数据
|
||||
page := &beans.Page{PageNum: 1, PageSize: -1} // -1表示不分页
|
||||
_, err := mongo.DB().Find(ctx,
|
||||
bson.M{"tenantId": tenantID}, &apps, "application", page, nil)
|
||||
return apps, err
|
||||
}
|
||||
|
||||
// GetByAPIKey 根据API密钥获取应用
|
||||
func (d *applicationDao) GetByAPIKey(ctx context.Context, apiKey string) (*entity.Application, error) {
|
||||
var app *entity.Application
|
||||
err := mongo.DB().FindOne(ctx,
|
||||
bson.M{"appKey": apiKey}, &app, "application")
|
||||
return app, err
|
||||
}
|
||||
|
||||
// Update 更新应用
|
||||
func (d *applicationDao) Update(ctx context.Context, app *entity.Application) error {
|
||||
_, err := mongo.DB().Update(ctx, bson.M{"_id": app.Id}, bson.M{"$set": app}, "application")
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete 删除应用
|
||||
func (d *applicationDao) Delete(ctx context.Context, id string) error {
|
||||
_, err := mongo.DB().Delete(ctx, bson.M{"_id": id}, "application")
|
||||
return err
|
||||
}
|
||||
|
||||
// List 应用列表
|
||||
func (d *applicationDao) List(ctx context.Context, tenantID string, page, pageSize int) ([]*entity.Application, int, error) {
|
||||
filter := bson.M{}
|
||||
if tenantID != "" {
|
||||
filter["tenantId"] = tenantID
|
||||
}
|
||||
|
||||
var apps []*entity.Application
|
||||
total, err := mongo.DB().Count(ctx, filter, "application")
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 使用common/mongo的Find方法,自动处理分页、租户等
|
||||
pageBean := &beans.Page{PageNum: int64(page), PageSize: int64(pageSize)}
|
||||
total, err = mongo.DB().Find(ctx, filter, &apps, "application", pageBean, nil)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return apps, int(total), nil
|
||||
}
|
||||
|
||||
// GetByName 根据名称获取应用
|
||||
func (d *applicationDao) GetByName(ctx context.Context, name string) (*entity.Application, error) {
|
||||
var app *entity.Application
|
||||
err := mongo.DB().FindOne(ctx, bson.M{"name": name}, &app, "application")
|
||||
return app, err
|
||||
}
|
||||
|
||||
// UpdateFields 更新应用部分字段
|
||||
func (d *applicationDao) UpdateFields(ctx context.Context, id string, data *entity.Application) error {
|
||||
_, err := mongo.DB().Update(ctx, bson.M{"_id": id}, bson.M{"$set": data}, "application")
|
||||
return err
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cid/model/entity"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"gitea.com/red-future/common/db/mongo"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
var CIDRequest = &cidRequestDao{}
|
||||
|
||||
type cidRequestDao struct {
|
||||
}
|
||||
|
||||
// Create 创建CID请求记录
|
||||
func (d *cidRequestDao) Create(ctx context.Context, request *entity.CidRequest) (id string, err error) {
|
||||
ids, err := mongo.DB().Insert(ctx, []interface{}{request}, entity.CidRequestCollection)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
id = ids[0].(string)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetHistory 获取CID请求历史
|
||||
func (d *cidRequestDao) GetHistory(ctx context.Context, userId string, page, size int) (list []*entity.CidRequest, total int64, err error) {
|
||||
filter := bson.M{"userId": userId}
|
||||
|
||||
// 分页查询,使用common/mongo的Find方法,自动处理分页、租户等
|
||||
pageBean := &beans.Page{PageNum: int64(page), PageSize: int64(size)}
|
||||
total, err = mongo.DB().Find(ctx, filter, &list, entity.CidRequestCollection, pageBean, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// GetStatistics 获取统计信息
|
||||
func (d *cidRequestDao) GetStatistics(ctx context.Context, userId string) (stats map[string]interface{}, err error) {
|
||||
stats = make(map[string]interface{})
|
||||
|
||||
// 总请求数
|
||||
totalRequests, err := mongo.DB().Count(ctx, bson.M{"userId": userId}, entity.CidRequestCollection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stats["total_requests"] = totalRequests
|
||||
|
||||
// 成功请求数
|
||||
successfulRequests, err := mongo.DB().Count(ctx, bson.M{"userId": userId, "status": "completed"}, entity.CidRequestCollection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stats["successful_requests"] = successfulRequests
|
||||
|
||||
// 平均处理时间需要单独计算,MongoDB聚合查询
|
||||
// 这里简化处理,返回0
|
||||
stats["average_process_time"] = 0
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
consts "cid/consts/public"
|
||||
dto "cid/model/dto/data"
|
||||
entity "cid/model/entity/data"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/db/gfdb"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var ApiInterface = new(apiInterfaceDao)
|
||||
|
||||
type apiInterfaceDao struct{}
|
||||
|
||||
// Insert 插入接口
|
||||
func (d *apiInterfaceDao) Insert(ctx context.Context, req *dto.CreateApiInterfaceReq) (id int64, err error) {
|
||||
var res *entity.ApiInterface
|
||||
if err = gconv.Struct(req, &res); err != nil {
|
||||
return
|
||||
}
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApiInterfaceTable).Data(&res).Insert()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
// Update 更新接口
|
||||
func (d *apiInterfaceDao) Update(ctx context.Context, req *dto.UpdateApiInterfaceReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApiInterfaceTable).Data(&req).OmitEmpty().Where(entity.ApiInterfaceCols.Id, req.Id).Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// Delete 删除接口
|
||||
func (d *apiInterfaceDao) Delete(ctx context.Context, req *dto.DeleteApiInterfaceReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApiInterfaceTable).Where(entity.ApiInterfaceCols.Id, req.Id).Delete()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetOne 获取单个接口
|
||||
func (d *apiInterfaceDao) GetOne(ctx context.Context, req *dto.GetApiInterfaceReq) (res *entity.ApiInterface, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApiInterfaceTable).Where(entity.ApiInterfaceCols.Id, req.Id).One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// Count 获取接口数量
|
||||
func (d *apiInterfaceDao) Count(ctx context.Context, req *dto.ListApiInterfaceReq) (count int, err error) {
|
||||
return d.buildListFilter(ctx, req).Count()
|
||||
}
|
||||
|
||||
// List 获取接口列表
|
||||
func (d *apiInterfaceDao) List(ctx context.Context, req *dto.ListApiInterfaceReq) (res []entity.ApiInterface, total int, err error) {
|
||||
model := d.buildListFilter(ctx, req)
|
||||
model.OrderDesc(entity.ApiInterfaceCols.CreatedAt)
|
||||
if req.Page != nil {
|
||||
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
|
||||
}
|
||||
r, total, err := model.AllAndCount(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表查询的过滤条件
|
||||
func (d *apiInterfaceDao) buildListFilter(ctx context.Context, req *dto.ListApiInterfaceReq) *gdb.Model {
|
||||
model := gfdb.DB(ctx).Model(ctx, consts.ApiInterfaceTable).Model
|
||||
if !g.IsEmpty(req.Keyword) {
|
||||
model.WhereLike(entity.ApiInterfaceCols.Name, "%"+req.Keyword+"%")
|
||||
model.WhereOrLike(entity.ApiInterfaceCols.Code, "%"+req.Keyword+"%")
|
||||
}
|
||||
model.Where(entity.ApiInterfaceCols.PlatformId, req.PlatformId)
|
||||
model.Where(entity.ApiInterfaceCols.Name, req.Name)
|
||||
model.Where(entity.ApiInterfaceCols.Code, req.Code)
|
||||
model.Where(entity.ApiInterfaceCols.Method, req.Method)
|
||||
model.Where(entity.ApiInterfaceCols.Status, req.Status)
|
||||
model.OmitEmptyWhere()
|
||||
return model
|
||||
}
|
||||
|
||||
// UpdateStatus 更新接口状态
|
||||
func (d *apiInterfaceDao) UpdateStatus(ctx context.Context, id int64, status string) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApiInterfaceTable).
|
||||
Data(map[string]interface{}{"status": status}).
|
||||
Where(entity.ApiInterfaceCols.Id, id).
|
||||
Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetByIds 根据ID列表获取接口列表
|
||||
func (d *apiInterfaceDao) GetByIds(ctx context.Context, ids []int64) (res []entity.ApiInterface, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.ApiInterfaceTable).
|
||||
WhereIn(entity.ApiInterfaceCols.Id, ids).
|
||||
All()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
consts "cid/consts/public"
|
||||
dto "cid/model/dto/data"
|
||||
entity "cid/model/entity/data"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/db/gfdb"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
var DataFetchLog = new(dataFetchLogDao)
|
||||
|
||||
type dataFetchLogDao struct{}
|
||||
|
||||
// Insert 插入数据获取日志
|
||||
func (d *dataFetchLogDao) Insert(ctx context.Context, log *entity.DataFetchLog) (id int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataFetchLogTable).Data(&log).Insert()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
// Update 更新数据获取日志
|
||||
func (d *dataFetchLogDao) Update(ctx context.Context, id int64, data map[string]interface{}) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataFetchLogTable).
|
||||
Data(data).
|
||||
OmitEmpty().
|
||||
Where(entity.DataFetchLogCols.Id, id).
|
||||
Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetOne 获取单个数据获取日志
|
||||
func (d *dataFetchLogDao) GetOne(ctx context.Context, req *dto.GetDataFetchLogReq) (res *entity.DataFetchLog, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataFetchLogTable).Where(entity.DataFetchLogCols.Id, req.Id).One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// Count 获取数据获取日志数量
|
||||
func (d *dataFetchLogDao) Count(ctx context.Context, req *dto.ListDataFetchLogReq) (count int, err error) {
|
||||
return d.buildListFilter(ctx, req).Count()
|
||||
}
|
||||
|
||||
// List 获取数据获取日志列表
|
||||
func (d *dataFetchLogDao) List(ctx context.Context, req *dto.ListDataFetchLogReq) (res []entity.DataFetchLog, total int, err error) {
|
||||
model := d.buildListFilter(ctx, req)
|
||||
model.OrderDesc(entity.DataFetchLogCols.CreatedAt)
|
||||
if req.Page != nil {
|
||||
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
|
||||
}
|
||||
r, total, err := model.AllAndCount(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表查询的过滤条件
|
||||
func (d *dataFetchLogDao) buildListFilter(ctx context.Context, req *dto.ListDataFetchLogReq) *gdb.Model {
|
||||
model := gfdb.DB(ctx).Model(ctx, consts.DataFetchLogTable).Model
|
||||
model.Where(entity.DataFetchLogCols.PlatformId, req.PlatformId)
|
||||
model.Where(entity.DataFetchLogCols.InterfaceId, req.InterfaceId)
|
||||
model.Where(entity.DataFetchLogCols.RequestId, req.RequestId)
|
||||
model.Where(entity.DataFetchLogCols.Status, req.Status)
|
||||
if req.StartTime > 0 {
|
||||
model.WhereGTE(entity.DataFetchLogCols.StartTime, req.StartTime)
|
||||
}
|
||||
if req.EndTime > 0 {
|
||||
model.WhereLTE(entity.DataFetchLogCols.StartTime, req.EndTime)
|
||||
}
|
||||
model.OmitEmptyWhere()
|
||||
return model
|
||||
}
|
||||
|
||||
// GetByRequestId 根据请求ID获取日志
|
||||
func (d *dataFetchLogDao) GetByRequestId(ctx context.Context, requestId string) (res *entity.DataFetchLog, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataFetchLogTable).
|
||||
Where(entity.DataFetchLogCols.RequestId, requestId).
|
||||
One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新日志状态
|
||||
func (d *dataFetchLogDao) UpdateStatus(ctx context.Context, id int64, status string, endTime int64, duration int, responseData, errorMessage string) (rows int64, err error) {
|
||||
updateData := map[string]interface{}{
|
||||
"status": status,
|
||||
}
|
||||
if endTime > 0 {
|
||||
updateData["end_time"] = endTime
|
||||
}
|
||||
if duration > 0 {
|
||||
updateData["duration"] = duration
|
||||
}
|
||||
if responseData != "" {
|
||||
updateData["response_data"] = responseData
|
||||
}
|
||||
if errorMessage != "" {
|
||||
updateData["error_message"] = errorMessage
|
||||
}
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataFetchLogTable).
|
||||
Data(updateData).
|
||||
Where(entity.DataFetchLogCols.Id, id).
|
||||
Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// IncrementRetryCount 增加重试次数
|
||||
func (d *dataFetchLogDao) IncrementRetryCount(ctx context.Context, id int64) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataFetchLogTable).
|
||||
Where(entity.DataFetchLogCols.Id, id).
|
||||
Data(gdb.Raw(entity.DataFetchLogCols.RetryCount + " + 1")).
|
||||
Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
consts "cid/consts/public"
|
||||
dto "cid/model/dto/data"
|
||||
entity "cid/model/entity/data"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/db/gfdb"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var Platform = new(platformDao)
|
||||
|
||||
type platformDao struct{}
|
||||
|
||||
// Insert 插入平台
|
||||
func (d *platformDao) Insert(ctx context.Context, req *dto.CreatePlatformReq) (id int64, err error) {
|
||||
var res *entity.Platform
|
||||
if err = gconv.Struct(req, &res); err != nil {
|
||||
return
|
||||
}
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.PlatformTable).Data(&res).Insert()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
// Update 更新平台
|
||||
func (d *platformDao) Update(ctx context.Context, req *dto.UpdatePlatformReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.PlatformTable).Data(&req).OmitEmpty().Where(entity.PlatformCols.Id, req.Id).Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// Delete 删除平台
|
||||
func (d *platformDao) Delete(ctx context.Context, req *dto.DeletePlatformReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.PlatformTable).Where(entity.PlatformCols.Id, req.Id).Delete()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetOne 获取单个平台
|
||||
func (d *platformDao) GetOne(ctx context.Context, req *dto.GetPlatformReq) (res *entity.Platform, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.PlatformTable).Where(entity.PlatformCols.Id, req.Id).One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// Count 获取平台数量
|
||||
func (d *platformDao) Count(ctx context.Context, req *dto.ListPlatformReq) (count int, err error) {
|
||||
return d.buildListFilter(ctx, req).Count()
|
||||
}
|
||||
|
||||
// List 获取平台列表
|
||||
func (d *platformDao) List(ctx context.Context, req *dto.ListPlatformReq) (res []entity.Platform, total int, err error) {
|
||||
model := d.buildListFilter(ctx, req)
|
||||
model.OrderDesc(entity.PlatformCols.CreatedAt)
|
||||
if req.Page != nil {
|
||||
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
|
||||
}
|
||||
r, total, err := model.AllAndCount(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表查询的过滤条件
|
||||
func (d *platformDao) buildListFilter(ctx context.Context, req *dto.ListPlatformReq) *gdb.Model {
|
||||
model := gfdb.DB(ctx).Model(ctx, consts.PlatformTable).Model
|
||||
if !g.IsEmpty(req.Keyword) {
|
||||
model.WhereLike(entity.PlatformCols.Name, "%"+req.Keyword+"%")
|
||||
}
|
||||
model.Where(entity.PlatformCols.Name, req.Name)
|
||||
model.Where(entity.PlatformCols.Type, req.Type)
|
||||
model.Where(entity.PlatformCols.Status, req.Status)
|
||||
model.OmitEmptyWhere()
|
||||
return model
|
||||
}
|
||||
|
||||
// UpdateStatus 更新平台状态
|
||||
func (d *platformDao) UpdateStatus(ctx context.Context, id int64, status string) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.PlatformTable).
|
||||
Data(map[string]interface{}{"status": status}).
|
||||
Where(entity.PlatformCols.Id, id).
|
||||
Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetByType 根据类型获取平台
|
||||
func (d *platformDao) GetByType(ctx context.Context, platformType string) (res *entity.Platform, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.PlatformTable).
|
||||
Where(entity.PlatformCols.Type, platformType).
|
||||
One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package mapping
|
||||
|
||||
import (
|
||||
consts "cid/consts/public"
|
||||
dto "cid/model/dto/mapping"
|
||||
entity "cid/model/entity/mapping"
|
||||
"context"
|
||||
|
||||
"gitea.com/red-future/common/db/gfdb"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var DataMapping = new(dataMappingDao)
|
||||
|
||||
type dataMappingDao struct{}
|
||||
|
||||
// Insert 插入数据映射
|
||||
func (d *dataMappingDao) Insert(ctx context.Context, req *dto.CreateDataMappingReq) (id int64, err error) {
|
||||
var res *entity.DataMapping
|
||||
if err = gconv.Struct(req, &res); err != nil {
|
||||
return
|
||||
}
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataMappingTable).Data(&res).Insert()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
// BatchInsert 批量插入数据映射
|
||||
func (d *dataMappingDao) BatchInsert(ctx context.Context, mappings []entity.DataMapping) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataMappingTable).Data(&mappings).Insert()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// Update 更新数据映射
|
||||
func (d *dataMappingDao) Update(ctx context.Context, req *dto.UpdateDataMappingReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataMappingTable).Data(&req).OmitEmpty().Where(entity.DataMappingCols.Id, req.Id).Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// Delete 删除数据映射
|
||||
func (d *dataMappingDao) Delete(ctx context.Context, req *dto.DeleteDataMappingReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataMappingTable).Where(entity.DataMappingCols.Id, req.Id).Delete()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// GetOne 获取单个数据映射
|
||||
func (d *dataMappingDao) GetOne(ctx context.Context, req *dto.GetDataMappingReq) (res *entity.DataMapping, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataMappingTable).Where(entity.DataMappingCols.Id, req.Id).One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// Count 获取数据映射数量
|
||||
func (d *dataMappingDao) Count(ctx context.Context, req *dto.ListDataMappingReq) (count int, err error) {
|
||||
return d.buildListFilter(ctx, req).Count()
|
||||
}
|
||||
|
||||
// List 获取数据映射列表
|
||||
func (d *dataMappingDao) List(ctx context.Context, req *dto.ListDataMappingReq) (res []entity.DataMapping, total int, err error) {
|
||||
model := d.buildListFilter(ctx, req)
|
||||
model.OrderAsc(entity.DataMappingCols.Priority)
|
||||
model.OrderDesc(entity.DataMappingCols.CreatedAt)
|
||||
if req.Page != nil {
|
||||
model.Page(int(req.Page.PageNum), int(req.Page.PageSize))
|
||||
}
|
||||
r, total, err := model.AllAndCount(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表的过滤条件
|
||||
func (d *dataMappingDao) buildListFilter(ctx context.Context, req *dto.ListDataMappingReq) *gdb.Model {
|
||||
model := gfdb.DB(ctx).Model(ctx, consts.DataMappingTable).Model
|
||||
model.Where(entity.DataMappingCols.PlatformId, req.PlatformId)
|
||||
model.Where(entity.DataMappingCols.InterfaceId, req.InterfaceId)
|
||||
model.Where(entity.DataMappingCols.SourceField, req.SourceField)
|
||||
model.Where(entity.DataMappingCols.TargetField, req.TargetField)
|
||||
model.Where(entity.DataMappingCols.Status, req.Status)
|
||||
model.OmitEmptyWhere()
|
||||
return model
|
||||
}
|
||||
|
||||
// GetByInterfaceId 根据接口ID获取映射规则列表(按优先级排序)
|
||||
func (d *dataMappingDao) GetByInterfaceId(ctx context.Context, interfaceId int64) (res []entity.DataMapping, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataMappingTable).
|
||||
Where(entity.DataMappingCols.InterfaceId, interfaceId).
|
||||
Where("status", "active").
|
||||
OrderAsc(entity.DataMappingCols.Priority).
|
||||
All()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// GetByInterfaceIdAndTargetField 根据接口ID和目标字段获取映射规则
|
||||
func (d *dataMappingDao) GetByInterfaceIdAndTargetField(ctx context.Context, interfaceId int64, targetField string) (res *entity.DataMapping, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataMappingTable).
|
||||
Where(entity.DataMappingCols.InterfaceId, interfaceId).
|
||||
Where(entity.DataMappingCols.TargetField, targetField).
|
||||
Where("status", "active").
|
||||
One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteByInterfaceId 根据接口ID删除所有映射规则
|
||||
func (d *dataMappingDao) DeleteByInterfaceId(ctx context.Context, interfaceId int64) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, consts.DataMappingTable).
|
||||
Where(entity.DataMappingCols.InterfaceId, interfaceId).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cid/model/entity"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"gitea.com/red-future/common/db/mongo"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
var Strategy = &strategyDao{}
|
||||
|
||||
type strategyDao struct {
|
||||
}
|
||||
|
||||
// GetByName 根据名称获取策略
|
||||
func (d *strategyDao) GetByName(ctx context.Context, name string) (strategy *entity.Strategy, err error) {
|
||||
err = mongo.DB().FindOne(ctx, bson.M{"name": name}, &strategy, "strategies")
|
||||
return
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取策略
|
||||
func (d *strategyDao) GetByID(ctx context.Context, id string) (strategy *entity.Strategy, err error) {
|
||||
err = mongo.DB().FindOne(ctx, bson.M{"_id": id}, &strategy, "strategies")
|
||||
return
|
||||
}
|
||||
|
||||
// GetByTenantLevel 根据租户级别获取策略
|
||||
func (d *strategyDao) GetByTenantLevel(ctx context.Context, tenantLevel string) (strategy *entity.Strategy, err error) {
|
||||
err = mongo.DB().FindOne(ctx, bson.M{"tenantLevel": tenantLevel, "status": "active"}, &strategy, "strategies")
|
||||
return
|
||||
}
|
||||
|
||||
// Create 创建策略
|
||||
func (d *strategyDao) Create(ctx context.Context, strategy *entity.Strategy) (id string, err error) {
|
||||
ids, err := mongo.DB().Insert(ctx, []interface{}{strategy}, "strategies")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
id = ids[0].(string)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Update 更新策略
|
||||
func (d *strategyDao) Update(ctx context.Context, strategy *entity.Strategy) (affected int64, err error) {
|
||||
result, err := mongo.DB().Update(ctx, bson.M{"_id": strategy.Id}, bson.M{"$set": strategy}, "strategies")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Delete 删除策略
|
||||
func (d *strategyDao) Delete(ctx context.Context, id string) (affected int64, err error) {
|
||||
count, err := mongo.DB().Delete(ctx, bson.M{"_id": id}, "strategies")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// GetList 获取策略列表
|
||||
func (d *strategyDao) GetList(ctx context.Context, page, size int, tenantLevel, status string) (list []*entity.Strategy, total int64, err error) {
|
||||
filter := bson.M{}
|
||||
|
||||
// 筛选条件
|
||||
if tenantLevel != "" {
|
||||
filter["tenantLevel"] = tenantLevel
|
||||
}
|
||||
if status != "" {
|
||||
filter["status"] = status
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
total, err = mongo.DB().Count(ctx, filter, "strategies")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 分页查询,使用common/mongo的Find方法,自动处理分页、租户等
|
||||
pageBean := &beans.Page{PageNum: int64(page), PageSize: int64(size)}
|
||||
total, err = mongo.DB().Find(ctx, filter, &list, "strategies", pageBean, nil)
|
||||
return
|
||||
}
|
||||
@@ -7,7 +7,6 @@ require (
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.5
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.5
|
||||
github.com/gogf/gf/v2 v2.9.5
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.1
|
||||
golang.org/x/net v0.47.0
|
||||
)
|
||||
|
||||
@@ -16,6 +15,7 @@ require (
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/armon/go-metrics v0.4.1 // indirect
|
||||
github.com/bwmarrin/snowflake v0.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||
@@ -69,6 +69,7 @@ require (
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
gitea.com/red-future/common v0.0.2 h1:KjiIyZo0JeSN9ldXofuGkFifJ/H66kTybOU34Yew7R0=
|
||||
gitea.com/red-future/common v0.0.2/go.mod h1:CUurYN0elToJTwB2pX9wSnjQqZv9D/Vxbo5ueb7i9BI=
|
||||
gitea.com/red-future/common v0.0.3/go.mod h1:mq4smQZFI5nYul6gvLH7ScnC/26bAOcTvR3hP625NYY=
|
||||
gitea.com/red-future/common v0.0.4 h1:2QgKc+B2iNfPRncKpmIqIzVwaMGJ3y3dt5v+35YD8SU=
|
||||
gitea.com/red-future/common v0.0.4/go.mod h1:UI9N5UUjilbMPF7+/lypZSnqDVHigt14300oSRrAyZg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
@@ -25,6 +23,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
||||
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
@@ -172,8 +172,7 @@ github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
|
||||
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
|
||||
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
||||
@@ -217,8 +216,9 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
|
||||
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
|
||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
@@ -297,8 +297,8 @@ github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfS
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.1 h1:hGDMngUao03OVQ6sgV5csk+RWOIkF+CuLsTPobNMGNI=
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.1/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI=
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0 h1:Oq6BmUAAFTzMeh6AonuDlgZMuAuEiUxoAD1koK5MuFo=
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI=
|
||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
@@ -330,8 +330,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
||||
golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae h1:COZdc9Ut6wLq7MO9GIYxfZl4n4ScmgqQLoHocKXrxco=
|
||||
golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
@@ -339,6 +338,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -416,6 +417,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"cid/controller"
|
||||
"cid/controller/app"
|
||||
"cid/controller/data"
|
||||
"cid/controller/mapping"
|
||||
|
||||
_ "gitea.com/red-future/common/db/mongo"
|
||||
"gitea.com/red-future/common/http"
|
||||
"gitea.com/red-future/common/jaeger"
|
||||
_ "gitea.com/red-future/common/ragflow" // RAGFlow 客户端自动初始化
|
||||
@@ -17,14 +18,16 @@ func main() {
|
||||
defer jaeger.ShutDown(ctx)
|
||||
|
||||
http.RouteRegister([]interface{}{
|
||||
controller.AdSource,
|
||||
controller.CID,
|
||||
controller.Strategy,
|
||||
controller.Advertisement,
|
||||
controller.Advertiser,
|
||||
controller.AdPosition,
|
||||
controller.RateLimit,
|
||||
controller.Application,
|
||||
// 平台管理
|
||||
data.Platform,
|
||||
// 接口管理
|
||||
data.ApiInterface,
|
||||
// 数据获取
|
||||
data.DataFetch,
|
||||
// 数据映射
|
||||
mapping.DataMapping,
|
||||
// 应用管理
|
||||
app.Application,
|
||||
})
|
||||
select {}
|
||||
}
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"cid/consts"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// BaseConfig 基础配置结构
|
||||
type BaseConfig struct {
|
||||
// 优先级和权重
|
||||
Priority int `bson:"priority" json:"priority"` // 优先级
|
||||
Weight float64 `bson:"weight" json:"weight"` // 权重
|
||||
Order int `bson:"order" json:"order"` // 排序顺序
|
||||
|
||||
// 标签和分类
|
||||
Tags []string `bson:"tags" json:"tags"` // 标签
|
||||
Category string `bson:"category" json:"category"` // 分类
|
||||
Industry string `bson:"industry" json:"industry"` // 行业
|
||||
|
||||
// 配置信息
|
||||
Config string `bson:"config" json:"config"` // 配置信息(JSON格式)
|
||||
Extra map[string]interface{} `bson:"extra" json:"extra"` // 扩展字段
|
||||
Remark string `bson:"remark" json:"remark"` // 备注
|
||||
}
|
||||
|
||||
// Validate 基础配置验证
|
||||
func (c *BaseConfig) Validate() error {
|
||||
if c.Priority < 0 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
if c.Weight < 0 || c.Weight > 1 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BiddingConfig 竞价配置
|
||||
type BiddingConfig struct {
|
||||
// 竞价类型
|
||||
BiddingType string `bson:"biddingType" json:"biddingType"` // 竞价类型:cpm、cpc、cpa、rtb
|
||||
BiddingStrategy string `bson:"biddingStrategy" json:"biddingStrategy"` // 出价策略:manual、auto、target_cpa、target_roas等
|
||||
|
||||
// 出价范围
|
||||
MinBidAmount int64 `bson:"minBidAmount" json:"minBidAmount"` // 最小出价(分)
|
||||
MaxBidAmount int64 `bson:"maxBidAmount" json:"maxBidAmount"` // 最大出价(分)
|
||||
DefaultBidAmount int64 `bson:"defaultBidAmount" json:"defaultBidAmount"` // 默认出价(分)
|
||||
BidIncrement int64 `bson:"bidIncrement" json:"bidIncrement"` // 出价增量(分)
|
||||
|
||||
// 自动优化
|
||||
AutoOptimization bool `bson:"autoOptimization" json:"autoOptimization"` // 是否自动优化
|
||||
TargetCPA int64 `bson:"targetCPA" json:"targetCPA"` // 目标CPA(分)
|
||||
TargetROAS float64 `bson:"targetROAS" json:"targetROAS"` // 目标ROAS
|
||||
OptimizationGoal string `bson:"optimizationGoal" json:"optimizationGoal"` // 优化目标:impressions、clicks、conversions、revenue等
|
||||
}
|
||||
|
||||
// Validate 竞价配置验证
|
||||
func (c *BiddingConfig) Validate() error {
|
||||
if c.MinBidAmount < 0 || c.MaxBidAmount < 0 || c.DefaultBidAmount < 0 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
if c.MinBidAmount > c.MaxBidAmount {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
if c.TargetROAS < 0 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BudgetConfig 预算配置
|
||||
type BudgetConfig struct {
|
||||
// 预算设置
|
||||
TotalBudget int64 `bson:"totalBudget" json:"totalBudget"` // 总预算(分)
|
||||
DailyBudget int64 `bson:"dailyBudget" json:"dailyBudget"` // 日预算(分)
|
||||
|
||||
// 投放节奏
|
||||
PaceType string `bson:"paceType" json:"paceType"` // 投放节奏:even、accelerated、standard
|
||||
IsBudgetPacing bool `bson:"isBudgetPacing" json:"isBudgetPacing"` // 是否预算匀速投放
|
||||
|
||||
// 时间配置
|
||||
StartDate int64 `bson:"startDate" json:"startDate"` // 开始投放时间
|
||||
EndDate int64 `bson:"endDate" json:"endDate"` // 结束投放时间
|
||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
||||
}
|
||||
|
||||
// Validate 预算配置验证
|
||||
func (c *BudgetConfig) Validate() error {
|
||||
if c.TotalBudget < 0 || c.DailyBudget < 0 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
if c.StartDate > c.EndDate {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// APIConfig API配置
|
||||
type APIConfig struct {
|
||||
// 基础配置
|
||||
Endpoint string `bson:"endpoint" json:"endpoint"` // API端点
|
||||
Version string `bson:"version" json:"version"` // API版本
|
||||
Timeout int `bson:"timeout" json:"timeout"` // 超时时间(毫秒)
|
||||
RetryCount int `bson:"retryCount" json:"retryCount"` // 重试次数
|
||||
|
||||
// 认证配置
|
||||
AuthType string `bson:"authType" json:"authType"` // 认证类型:api_key、oauth、basic
|
||||
AuthConfig string `bson:"authConfig" json:"authConfig"` // 认证配置(JSON字符串)
|
||||
|
||||
// 请求配置
|
||||
Headers string `bson:"headers" json:"headers"` // 请求头配置(JSON字符串)
|
||||
|
||||
// 限流配置
|
||||
RateLimit int64 `bson:"rateLimit" json:"rateLimit"` // 速率限制
|
||||
}
|
||||
|
||||
// Validate API配置验证
|
||||
func (c *APIConfig) Validate() error {
|
||||
if c.Timeout <= 0 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
if c.RetryCount < 0 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
if c.RateLimit <= 0 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreativeConfig 创意配置
|
||||
type CreativeConfig struct {
|
||||
// 轮播设置
|
||||
CreativeRotation string `bson:"creativeRotation" json:"creativeRotation"` // 创意轮播方式:optimize、even、random
|
||||
SelectedCreatives []string `bson:"selectedCreatives" json:"selectedCreatives"` // 选中的创意列表
|
||||
ExcludedCreatives []string `bson:"excludedCreatives" json:"excludedCreatives"` // 排除的创意列表
|
||||
|
||||
// 技术要求
|
||||
MaxFileSize int64 `bson:"maxFileSize" json:"maxFileSize"` // 最大文件大小(bytes)
|
||||
MaxDuration int64 `bson:"maxDuration" json:"maxDuration"` // 最大时长(秒)
|
||||
|
||||
// 支持的格式
|
||||
SupportedFormats []string `bson:"supportedFormats" json:"supportedFormats"` // 支持的格式
|
||||
SupportedSizes []string `bson:"supportedSizes" json:"supportedSizes"` // 支持的尺寸
|
||||
}
|
||||
|
||||
// Validate 创意配置验证
|
||||
func (c *CreativeConfig) Validate() error {
|
||||
if c.MaxFileSize <= 0 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
if c.MaxDuration <= 0 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PaymentConfig 支付配置
|
||||
type PaymentConfig struct {
|
||||
// 计费模式
|
||||
BillingModel string `bson:"billingModel" json:"billingModel"` // 计费模式:CPC、CPM、CPA等
|
||||
CommissionRate float64 `bson:"commissionRate" json:"commissionRate"` // 佣金比例
|
||||
MinimumBudget int64 `bson:"minimumBudget" json:"minimumBudget"` // 最低预算(分)
|
||||
|
||||
// 结算配置
|
||||
SettlementCycle string `bson:"settlementCycle" json:"settlementCycle"` // 结算周期:daily、weekly、monthly
|
||||
PaymentTerms string `bson:"paymentTerms" json:"paymentTerms"` // 支付条款
|
||||
Currency string `bson:"currency" json:"currency"` // 货币单位
|
||||
|
||||
// 收入分成
|
||||
RevShareRate float64 `bson:"revShareRate" json:"revShareRate"` // 收入分成比例(0-1)
|
||||
MinPayment int64 `bson:"minPayment" json:"minPayment"` // 最小支付金额(分)
|
||||
TaxInclusive bool `bson:"taxInclusive" json:"taxInclusive"` // 是否含税
|
||||
}
|
||||
|
||||
// Validate 支付配置验证
|
||||
func (c *PaymentConfig) Validate() error {
|
||||
if c.CommissionRate < 0 || c.CommissionRate > 1 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
if c.RevShareRate < 0 || c.RevShareRate > 1 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
if c.MinimumBudget < 0 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
if c.MinPayment < 0 {
|
||||
return errors.New(consts.ErrInvalidConfiguration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FrequencyCapConfig 频次控制配置
|
||||
type FrequencyCapConfig struct {
|
||||
// 频次限制
|
||||
Impressions int `bson:"impressions" json:"impressions"` // 展示次数
|
||||
TimeWindow int `bson:"timeWindow" json:"timeWindow"` // 时间窗口(小时)
|
||||
PerUser int `bson:"perUser" json:"perUser"` // 每用户频次
|
||||
PerHour int `bson:"perHour" json:"perHour"` // 每小时频次
|
||||
PerDay int `bson:"perDay" json:"perDay"` // 每日频次
|
||||
|
||||
// 频次控制规则
|
||||
CapType string `bson:"capType" json:"capType"` // 频次类型:lifetime、daily、hourly
|
||||
CapScope string `bson:"capScope" json:"capScope"` // 频次范围:user、device、ip
|
||||
ResetRule string `bson:"resetRule" json:"resetRule"` // 重置规则:daily、weekly、monthly
|
||||
}
|
||||
|
||||
// RestrictionConfig 限制配置
|
||||
type RestrictionConfig struct {
|
||||
// 年龄限制
|
||||
AgeRestriction bool `bson:"ageRestriction" json:"ageRestriction"` // 年龄限制
|
||||
MinAge int `bson:"minAge" json:"minAge"` // 最小年龄
|
||||
MaxAge int `bson:"maxAge" json:"maxAge"` // 最大年龄
|
||||
|
||||
// 地域限制
|
||||
GeoRestrictions []string `bson:"geoRestrictions" json:"geoRestrictions"` // 地域限制
|
||||
|
||||
// 设备限制
|
||||
DeviceRestrictions []string `bson:"deviceRestrictions" json:"deviceRestrictions"` // 设备限制
|
||||
|
||||
// 分类限制
|
||||
CategoryRestrictions []string `bson:"categoryRestrictions" json:"categoryRestrictions"` // 分类限制
|
||||
|
||||
// 内容限制
|
||||
ContentRestrictions []string `bson:"contentRestrictions" json:"contentRestrictions"` // 内容限制
|
||||
|
||||
// 品牌安全
|
||||
BrandSafety bool `bson:"brandSafety" json:"brandSafety"` // 品牌安全
|
||||
BlockedCategories []string `bson:"blockedCategories" json:"blockedCategories"` // 阻止的分类
|
||||
AllowedCategories []string `bson:"allowedCategories" json:"allowedCategories"` // 允许的分类
|
||||
ExcludedKeywords []string `bson:"excludedKeywords" json:"excludedKeywords"` // 排除的关键词
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"cid/model/entity"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
// AddAdPositionReq 添加广告位请求
|
||||
type AddAdPositionReq struct {
|
||||
g.Meta `path:"/add" method:"post" tags:"广告位管理" summary:"添加广告位" dc:"添加新的广告位"`
|
||||
|
||||
// 基本信息
|
||||
Name string `json:"name" v:"required"` // 广告位名称
|
||||
Description string `json:"description"` // 广告位描述
|
||||
PositionCode string `json:"positionCode" v:"required"` // 广告位编码,用于标识
|
||||
AdFormat string `json:"adFormat" v:"required"` // 支持的广告格式
|
||||
|
||||
// 尺寸信息
|
||||
Width int `json:"width" v:"required"` // 宽度(px)
|
||||
Height int `json:"height" v:"required"` // 高度(px)
|
||||
|
||||
// 位置信息
|
||||
Page string `json:"page" v:"required"` // 所属页面
|
||||
Section string `json:"section" v:"required"` // 页面区域
|
||||
Location string `json:"location" v:"required"` // 具体位置
|
||||
|
||||
// 展示设置
|
||||
MaxAds int `json:"maxAds"` // 最大广告数量
|
||||
RefreshInterval int `json:"refreshInterval"` // 刷新间隔(秒)
|
||||
IsLazyLoad bool `json:"isLazyLoad"` // 是否懒加载
|
||||
|
||||
// 定价设置
|
||||
PricingModel string `json:"pricingModel" v:"required"` // 计费模型:CPC、CPM、CPA等
|
||||
BasePrice int64 `json:"basePrice" v:"required"` // 基础价格(分)
|
||||
FloorPrice int64 `json:"floorPrice" v:"required"` // 底价(分)
|
||||
PriceUnit string `json:"priceUnit" v:"required"` // 价格单位:千次展示、单次点击、单次转化等
|
||||
|
||||
// 展示规则
|
||||
DisplayRules *entity.DisplayRules `json:"displayRules"` // 展示规则
|
||||
|
||||
// 状态信息
|
||||
Status string `json:"status" v:"required"` // 广告位状态:启用、禁用、测试
|
||||
IsExclusive bool `json:"isExclusive"` // 是否独占广告位
|
||||
}
|
||||
|
||||
type AddAdPositionRes struct {
|
||||
Id *bson.ObjectID `json:"id"`
|
||||
}
|
||||
|
||||
// UpdateAdPositionReq 更新广告位请求
|
||||
type UpdateAdPositionReq struct {
|
||||
g.Meta `path:"/update" method:"put" tags:"广告位管理" summary:"更新广告位" dc:"更新广告位信息"`
|
||||
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
|
||||
// 基本信息
|
||||
Name string `json:"name"` // 广告位名称
|
||||
Description string `json:"description"` // 广告位描述
|
||||
PositionCode string `json:"positionCode"` // 广告位编码,用于标识
|
||||
AdFormat string `json:"adFormat"` // 支持的广告格式
|
||||
|
||||
// 尺寸信息
|
||||
Width *int `json:"width"` // 宽度(px)
|
||||
Height *int `json:"height"` // 高度(px)
|
||||
|
||||
// 位置信息
|
||||
Page string `json:"page"` // 所属页面
|
||||
Section string `json:"section"` // 页面区域
|
||||
Location string `json:"location"` // 具体位置
|
||||
|
||||
// 展示设置
|
||||
MaxAds *int `json:"maxAds"` // 最大广告数量
|
||||
RefreshInterval *int `json:"refreshInterval"` // 刷新间隔(秒)
|
||||
IsLazyLoad *bool `json:"isLazyLoad"` // 是否懒加载
|
||||
|
||||
// 定价设置
|
||||
PricingModel string `json:"pricingModel"` // 计费模型:CPC、CPM、CPA等
|
||||
BasePrice *int64 `json:"basePrice"` // 基础价格(分)
|
||||
FloorPrice *int64 `json:"floorPrice"` // 底价(分)
|
||||
PriceUnit string `json:"priceUnit"` // 价格单位:千次展示、单次点击、单次转化等
|
||||
|
||||
// 展示规则
|
||||
DisplayRules *entity.DisplayRules `json:"displayRules"` // 展示规则
|
||||
|
||||
// 状态信息
|
||||
Status *string `json:"status"` // 广告位状态:启用、禁用、测试
|
||||
IsExclusive *bool `json:"isExclusive"` // 是否独占广告位
|
||||
}
|
||||
|
||||
// GetAdPositionReq 获取广告位详情请求
|
||||
type GetAdPositionReq struct {
|
||||
g.Meta `path:"/one" method:"get" tags:"广告位管理" summary:"获取广告位详情" dc:"根据ID获取单个广告位详情"`
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
}
|
||||
|
||||
type GetAdPositionRes struct {
|
||||
*entity.AdPosition
|
||||
}
|
||||
|
||||
// ListAdPositionReq 获取广告位列表请求
|
||||
type ListAdPositionReq struct {
|
||||
g.Meta `path:"/list" method:"get" tags:"广告位管理" summary:"获取广告位列表" dc:"分页查询广告位列表,支持多条件筛选"`
|
||||
*beans.Page
|
||||
|
||||
Name string `json:"name"` // 广告位名称模糊查询
|
||||
PositionCode string `json:"positionCode"` // 广告位编码
|
||||
PageName string `json:"pageName"` // 所属页面
|
||||
Section string `json:"section"` // 页面区域
|
||||
Status string `json:"status"` // 广告位状态
|
||||
AdFormat string `json:"adFormat"` // 广告格式
|
||||
DateRange []string `json:"dateRange"` // 创建时间范围 [start, end]
|
||||
}
|
||||
|
||||
type ListAdPositionRes struct {
|
||||
List []*entity.AdPosition `json:"list"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// UpdateAdPositionStatusReq 更新广告位状态请求
|
||||
type UpdateAdPositionStatusReq struct {
|
||||
g.Meta `path:"/updateStatus" method:"patch" tags:"广告位管理" summary:"更新广告位状态" dc:"更新广告位状态"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告位ID
|
||||
Status string `json:"status" v:"required"` // 广告位状态:启用、禁用、测试
|
||||
}
|
||||
|
||||
// GetAvailableAdPositionsReq 获取可用广告位请求
|
||||
type GetAvailableAdPositionsReq struct {
|
||||
g.Meta `path:"/getAvailableAdPositions" method:"get" tags:"广告位管理" summary:"获取可用广告位列表" dc:"获取所有启用的广告位列表"`
|
||||
}
|
||||
|
||||
type GetAvailableAdPositionsRes struct {
|
||||
List []*entity.AdPosition `json:"list"`
|
||||
}
|
||||
|
||||
// MatchAdReq 匹配广告请求
|
||||
type MatchAdReq struct {
|
||||
g.Meta `path:"/matchAd" method:"post" tags:"广告位管理" summary:"匹配广告" dc:"根据广告位编码和用户信息匹配适合的广告"`
|
||||
|
||||
PositionCode string `json:"positionCode" v:"required"` // 广告位编码
|
||||
UserInfo map[string]interface{} `json:"userInfo"` // 用户信息
|
||||
}
|
||||
|
||||
type MatchAdRes struct {
|
||||
*entity.Advertisement `json:"advertisement"`
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"cid/model/entity"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreateAdSourceReq 创建广告源请求
|
||||
type CreateAdSourceReq struct {
|
||||
g.Meta `path:"/create" method:"post" tags:"广告源管理" summary:"创建广告源" dc:"创建新的广告源配置"`
|
||||
|
||||
// 基本信息
|
||||
Name string `json:"name" v:"required"` // 广告源名称
|
||||
Code string `json:"code" v:"required"` // 广告源编码,唯一标识
|
||||
Provider string `json:"provider" v:"required"` // 提供商:google、facebook、baidu、tencent、self等
|
||||
Type string `json:"type" v:"required|in:self,third_party,exchange"` // 类型
|
||||
Description string `json:"description"` // 描述
|
||||
|
||||
// 连接配置
|
||||
APIEndpoint string `json:"apiEndpoint" v:"required"` // API端点
|
||||
APIVersion string `json:"apiVersion"` // API版本
|
||||
AuthType string `json:"authType" v:"required|in:api_key,oauth,basic"` // 认证类型
|
||||
AuthConfig map[string]interface{} `json:"authConfig" v:"required"` // 认证配置
|
||||
Headers map[string]string `json:"headers"` // 请求头配置
|
||||
Timeout int `json:"timeout"` // 超时时间(毫秒)
|
||||
RetryCount int `json:"retryCount"` // 重试次数
|
||||
|
||||
// 基础配置
|
||||
SupportedFormats []string `json:"supportedFormats" v:"required"` // 支持的广告格式
|
||||
SupportedSizes []string `json:"supportedSizes"` // 支持的尺寸
|
||||
SupportedDevices []string `json:"supportedDevices"` // 支持的设备类型
|
||||
SupportedOS []string `json:"supportedOS"` // 支持的操作系统
|
||||
SupportedCountries []string `json:"supportedCountries"` // 支持的国家/地区
|
||||
|
||||
// 竞价配置
|
||||
BiddingType string `json:"biddingType" v:"required|in:cpm,cpc,cpa,rtb"` // 竞价类型
|
||||
MinBidAmount int64 `json:"minBidAmount"` // 最小出价(分)
|
||||
MaxBidAmount int64 `json:"maxBidAmount"` // 最大出价(分)
|
||||
BidIncrement int64 `json:"bidIncrement"` // 出价增量(分)
|
||||
DefaultBidAmount int64 `json:"defaultBidAmount"` // 默认出价(分)
|
||||
AutoOptimization bool `json:"autoOptimization"` // 是否自动优化
|
||||
|
||||
// 最大广告数
|
||||
MaxAdsPerRequest int `json:"maxAdsPerRequest"` // 单次请求最大广告数量
|
||||
|
||||
// 其他配置
|
||||
BrandSafety bool `json:"brandSafety"` // 品牌安全
|
||||
Viewability bool `json:"viewability"` // 可见性支持
|
||||
RealTimeBidding bool `json:"realTimeBidding"` // 实时竞价
|
||||
HeaderBidding bool `json:"headerBidding"` // 标题竞价
|
||||
|
||||
// 财务设置
|
||||
BillingModel string `json:"billingModel" v:"required|in:cpm,cpc,cpa,rev_share"` // 计费模式
|
||||
PaymentTerms string `json:"paymentTerms" v:"in:net_30,net_60,net_90"` // 支付条款
|
||||
RevShareRate float64 `json:"revShareRate" v:"between:0,1"` // 收入分成比例
|
||||
MinPayment int64 `json:"minPayment"` // 最小支付金额(分)
|
||||
Currency string `json:"currency"` // 货币单位
|
||||
TaxInclusive bool `json:"taxInclusive"` // 是否含税
|
||||
|
||||
// 系统信息
|
||||
Priority int `json:"priority"` // 优先级
|
||||
}
|
||||
|
||||
type CreateAdSourceRes struct {
|
||||
Id string `json:"id"` // 广告源ID
|
||||
}
|
||||
|
||||
// GetAdSourceReq 获取广告源详情请求
|
||||
type GetAdSourceReq struct {
|
||||
g.Meta `path:"/getByID" method:"get" tags:"广告源管理" summary:"获取广告源详情" dc:"根据ID获取单个广告源详情"`
|
||||
Id string `json:"id" v:"required"` // 广告源ID
|
||||
}
|
||||
|
||||
type GetAdSourceRes struct {
|
||||
*entity.AdSource
|
||||
}
|
||||
|
||||
// ListAdSourceReq 获取广告源列表请求
|
||||
type ListAdSourceReq struct {
|
||||
g.Meta `path:"/getList" method:"get" tags:"广告源管理" summary:"获取广告源列表" dc:"分页查询广告源列表,支持多条件筛选"`
|
||||
*beans.Page
|
||||
|
||||
Name string `json:"name"` // 广告源名称模糊查询
|
||||
Code string `json:"code"` // 广告源编码
|
||||
Provider string `json:"provider"` // 提供商
|
||||
Type string `json:"type"` // 类型
|
||||
Status string `json:"status"` // 状态
|
||||
Health string `json:"health"` // 健康状态
|
||||
}
|
||||
|
||||
type ListAdSourceRes struct {
|
||||
List []*entity.AdSource `json:"list"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// UpdateAdSourceReq 更新广告源请求
|
||||
type UpdateAdSourceReq struct {
|
||||
g.Meta `path:"/update" method:"put" tags:"广告源管理" summary:"更新广告源" dc:"更新广告源信息"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告源ID
|
||||
|
||||
// 基本信息
|
||||
Name string `json:"name"` // 广告源名称
|
||||
Description string `json:"description"` // 描述
|
||||
|
||||
// 连接配置
|
||||
APIEndpoint string `json:"apiEndpoint"` // API端点
|
||||
APIVersion string `json:"apiVersion"` // API版本
|
||||
AuthType string `json:"authType"` // 认证类型
|
||||
AuthConfig map[string]interface{} `json:"authConfig"` // 认证配置
|
||||
Headers map[string]string `json:"headers"` // 请求头配置
|
||||
Timeout int `json:"timeout"` // 超时时间(毫秒)
|
||||
RetryCount int `json:"retryCount"` // 重试次数
|
||||
|
||||
// 基础配置
|
||||
SupportedFormats []string `json:"supportedFormats"` // 支持的广告格式
|
||||
SupportedSizes []string `json:"supportedSizes"` // 支持的尺寸
|
||||
SupportedDevices []string `json:"supportedDevices"` // 支持的设备类型
|
||||
SupportedOS []string `json:"supportedOS"` // 支持的操作系统
|
||||
SupportedCountries []string `json:"supportedCountries"` // 支持的国家/地区
|
||||
|
||||
// 竞价配置
|
||||
BiddingType string `json:"biddingType"` // 竞价类型
|
||||
MinBidAmount int64 `json:"minBidAmount"` // 最小出价(分)
|
||||
MaxBidAmount int64 `json:"maxBidAmount"` // 最大出价(分)
|
||||
BidIncrement int64 `json:"bidIncrement"` // 出价增量(分)
|
||||
DefaultBidAmount int64 `json:"defaultBidAmount"` // 默认出价(分)
|
||||
AutoOptimization bool `json:"autoOptimization"` // 是否自动优化
|
||||
|
||||
// 最大广告数
|
||||
MaxAdsPerRequest int `json:"maxAdsPerRequest"` // 单次请求最大广告数量
|
||||
|
||||
// 其他配置
|
||||
BrandSafety bool `json:"brandSafety"` // 品牌安全
|
||||
Viewability bool `json:"viewability"` // 可见性支持
|
||||
RealTimeBidding bool `json:"realTimeBidding"` // 实时竞价
|
||||
HeaderBidding bool `json:"headerBidding"` // 标题竞价
|
||||
|
||||
// 财务设置
|
||||
BillingModel string `json:"billingModel"` // 计费模式
|
||||
PaymentTerms string `json:"paymentTerms"` // 支付条款
|
||||
RevShareRate float64 `json:"revShareRate"` // 收入分成比例
|
||||
MinPayment int64 `json:"minPayment"` // 最小支付金额(分)
|
||||
Currency string `json:"currency"` // 货币单位
|
||||
TaxInclusive bool `json:"taxInclusive"` // 是否含税
|
||||
|
||||
// 系统信息
|
||||
Priority int `json:"priority"` // 优先级
|
||||
}
|
||||
|
||||
// UpdateAdSourceStatusReq 更新广告源状态请求
|
||||
type UpdateAdSourceStatusReq struct {
|
||||
// g.Meta `path:"/adsource" method:"patch" tags:"广告源管理" summary:"更新广告源状态" dc:"更新广告源状态"` // 暂时注释,缺少对应的controller方法
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告源ID
|
||||
Status string `json:"status" v:"required"` // 广告源状态:active、inactive、maintenance
|
||||
}
|
||||
|
||||
// DeleteAdSourceReq 删除广告源请求
|
||||
type DeleteAdSourceReq struct {
|
||||
g.Meta `path:"/delete" 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:"测试广告源的连接性和可用性"` // 暂时注释,缺少对应的controller方法
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告源ID
|
||||
}
|
||||
|
||||
type TestAdSourceRes struct {
|
||||
Success bool `json:"success"` // 测试是否成功
|
||||
ResponseTime int64 `json:"responseTime"` // 响应时间(毫秒)
|
||||
ErrorMessage string `json:"errorMessage"` // 错误信息
|
||||
SupportedFormats []string `json:"supportedFormats"` // 支持的广告格式
|
||||
}
|
||||
|
||||
// DeleteAdSourceRes 删除广告源响应
|
||||
type DeleteAdSourceRes struct {
|
||||
Success bool `json:"success"` // 删除是否成功
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package dto
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// GetAdSourceStatisticsReq 获取广告源统计数据请求
|
||||
type GetAdSourceStatisticsReq struct {
|
||||
g.Meta `path:"/adsource-statistics" method:"get" tags:"广告源管理" summary:"获取广告源统计数据" dc:"获取广告源的详细统计数据"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告源ID
|
||||
StartDate int64 `json:"startDate" v:"required"` // 开始日期
|
||||
EndDate int64 `json:"endDate" v:"required"` // 结束日期
|
||||
Dimension string `json:"dimension"` // 统计维度:day、week、month
|
||||
}
|
||||
|
||||
type GetAdSourceStatisticsRes struct {
|
||||
// 概览数据
|
||||
Overview AdSourceOverviewStats `json:"overview"`
|
||||
|
||||
// 趋势数据
|
||||
Trends []AdSourceTrendData `json:"trends"`
|
||||
|
||||
// 性能数据
|
||||
Performance AdSourcePerformanceStats `json:"performance"`
|
||||
|
||||
// 错误统计
|
||||
Errors []AdSourceErrorStats `json:"errors"`
|
||||
}
|
||||
|
||||
// AdSourceOverviewStats 广告源概览统计
|
||||
type AdSourceOverviewStats struct {
|
||||
TotalRequests int64 `json:"totalRequests"` // 总请求数
|
||||
SuccessfulRequests int64 `json:"successfulRequests"` // 成功请求数
|
||||
FailedRequests int64 `json:"failedRequests"` // 失败请求数
|
||||
TotalImpressions int64 `json:"totalImpressions"` // 总展示次数
|
||||
TotalClicks int64 `json:"totalClicks"` // 总点击次数
|
||||
TotalConversions int64 `json:"totalConversions"` // 总转化次数
|
||||
TotalRevenue int64 `json:"totalRevenue"` // 总收入(分)
|
||||
SuccessRate float64 `json:"successRate"` // 成功率
|
||||
ErrorRate float64 `json:"errorRate"` // 错误率
|
||||
CTR float64 `json:"ctr"` // 点击率
|
||||
CVR float64 `json:"cvr"` // 转化率
|
||||
FillRate float64 `json:"fillRate"` // 填充率
|
||||
ECPM int64 `json:"ecpm"` // 有效千次展示成本(分)
|
||||
ECPC int64 `json:"ecpc"` // 有效点击成本(分)
|
||||
AverageResponseTime float64 `json:"averageResponseTime"` // 平均响应时间(毫秒)
|
||||
Uptime float64 `json:"uptime"` // 可用性(百分比)
|
||||
}
|
||||
|
||||
// AdSourceTrendData 广告源趋势数据
|
||||
type AdSourceTrendData struct {
|
||||
Date int64 `json:"date"` // 日期
|
||||
Requests int64 `json:"requests"` // 请求数
|
||||
Impressions int64 `json:"impressions"` // 展示次数
|
||||
Clicks int64 `json:"clicks"` // 点击次数
|
||||
Conversions int64 `json:"conversions"` // 转化次数
|
||||
Revenue int64 `json:"revenue"` // 收入(分)
|
||||
SuccessRate float64 `json:"successRate"` // 成功率
|
||||
ErrorRate float64 `json:"errorRate"` // 错误率
|
||||
CTR float64 `json:"ctr"` // 点击率
|
||||
CVR float64 `json:"cvr"` // 转化率
|
||||
FillRate float64 `json:"fillRate"` // 填充率
|
||||
ECPM int64 `json:"ecpm"` // 有效千次展示成本(分)
|
||||
ResponseTime float64 `json:"responseTime"` // 平均响应时间(毫秒)
|
||||
}
|
||||
|
||||
// AdSourcePerformanceStats 广告源性能统计
|
||||
type AdSourcePerformanceStats struct {
|
||||
// 响应时间分布
|
||||
ResponseTimeDistribution map[string]int64 `json:"responseTimeDistribution"` // 响应时间分布
|
||||
|
||||
// 错误类型统计
|
||||
ErrorTypes map[string]int64 `json:"errorTypes"` // 错误类型统计
|
||||
|
||||
// 地区性能
|
||||
RegionalPerformance map[string]AdSourceRegionalStats `json:"regionalPerformance"` // 地区性能
|
||||
|
||||
// 设备性能
|
||||
DevicePerformance map[string]AdSourceDeviceStats `json:"devicePerformance"` // 设备性能
|
||||
}
|
||||
|
||||
// AdSourceErrorStats 广告源错误统计
|
||||
type AdSourceErrorStats struct {
|
||||
ErrorType string `json:"errorType"` // 错误类型
|
||||
Count int64 `json:"count"` // 错误次数
|
||||
Percentage float64 `json:"percentage"` // 占比
|
||||
LastOccurred int64 `json:"lastOccurred"` // 最后发生时间
|
||||
}
|
||||
|
||||
// AdSourceRegionalStats 广告源地区统计
|
||||
type AdSourceRegionalStats struct {
|
||||
Region string `json:"region"` // 地区
|
||||
Requests int64 `json:"requests"` // 请求数
|
||||
Impressions int64 `json:"impressions"` // 展示次数
|
||||
Clicks int64 `json:"clicks"` // 点击次数
|
||||
Revenue int64 `json:"revenue"` // 收入(分)
|
||||
CTR float64 `json:"ctr"` // 点击率
|
||||
ResponseTime float64 `json:"responseTime"` // 平均响应时间(毫秒)
|
||||
}
|
||||
|
||||
// AdSourceDeviceStats 广告源设备统计
|
||||
type AdSourceDeviceStats struct {
|
||||
Device string `json:"device"` // 设备类型
|
||||
Requests int64 `json:"requests"` // 请求数
|
||||
Impressions int64 `json:"impressions"` // 展示次数
|
||||
Clicks int64 `json:"clicks"` // 点击次数
|
||||
Revenue int64 `json:"revenue"` // 收入(分)
|
||||
CTR float64 `json:"ctr"` // 点击率
|
||||
ResponseTime float64 `json:"responseTime"` // 平均响应时间(毫秒)
|
||||
}
|
||||
|
||||
// AdSourceTestMetrics 广告源测试质量指标
|
||||
type AdSourceTestMetrics struct {
|
||||
SuccessRate float64 `json:"successRate"` // 成功率
|
||||
AverageResponseTime float64 `json:"averageResponseTime"` // 平均响应时间(毫秒)
|
||||
FillRate float64 `json:"fillRate"` // 填充率
|
||||
CTR float64 `json:"ctr"` // 点击率
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"cid/model/entity"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// AddAdvertisementReq 添加广告请求
|
||||
type AddAdvertisementReq struct {
|
||||
g.Meta `path:"/add" method:"post" tags:"广告管理" summary:"添加广告" dc:"添加新的广告"`
|
||||
|
||||
// 广告基本信息
|
||||
Title string `json:"title" v:"required"` // 广告标题
|
||||
Description string `json:"description"` // 广告描述
|
||||
AdvertiserId string `json:"advertiserId" v:"required"` // 广告主ID
|
||||
AdPositionId string `json:"adPositionId" v:"required"` // 广告位ID
|
||||
AdType string `json:"adType" v:"required"` // 广告类型:图片、视频、文字等
|
||||
AdFormat string `json:"adFormat" v:"required"` // 广告格式
|
||||
MaterialUrl string `json:"materialUrl" v:"required"` // 广告素材URL
|
||||
TargetUrl string `json:"targetUrl" v:"required"` // 目标链接
|
||||
|
||||
// 投放设置
|
||||
StartDate int64 `json:"startDate" v:"required"` // 开始投放时间
|
||||
EndDate int64 `json:"endDate" v:"required"` // 结束投放时间
|
||||
Budget int64 `json:"budget" v:"required"` // 预算(分)
|
||||
DailyBudget int64 `json:"dailyBudget"` // 日预算(分)
|
||||
BidAmount int64 `json:"bidAmount" v:"required"` // 出价(分)
|
||||
BillingType string `json:"billingType" v:"required"` // 计费类型:CPC、CPM、CPA等
|
||||
|
||||
// 投放条件
|
||||
Targeting *entity.UnifiedTargeting `json:"targeting"` // 定向条件
|
||||
}
|
||||
|
||||
type AddAdvertisementRes struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
// UpdateAdvertisementReq 更新广告请求
|
||||
type UpdateAdvertisementReq struct {
|
||||
g.Meta `path:"/update" method:"put" tags:"广告管理" summary:"更新广告" dc:"更新广告信息"`
|
||||
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
|
||||
// 广告基本信息
|
||||
Title string `json:"title"` // 广告标题
|
||||
Description string `json:"description"` // 广告描述
|
||||
AdvertiserId string `json:"advertiserId"` // 广告主ID
|
||||
AdPositionId string `json:"adPositionId"` // 广告位ID
|
||||
AdType string `json:"adType"` // 广告类型:图片、视频、文字等
|
||||
AdFormat string `json:"adFormat"` // 广告格式
|
||||
MaterialUrl string `json:"materialUrl"` // 广告素材URL
|
||||
TargetUrl string `json:"targetUrl"` // 目标链接
|
||||
|
||||
// 投放设置
|
||||
StartDate *int64 `json:"startDate"` // 开始投放时间
|
||||
EndDate *int64 `json:"endDate"` // 结束投放时间
|
||||
Budget *int64 `json:"budget"` // 预算(分)
|
||||
DailyBudget *int64 `json:"dailyBudget"` // 日预算(分)
|
||||
BidAmount *int64 `json:"bidAmount"` // 出价(分)
|
||||
BillingType string `json:"billingType"` // 计费类型:CPC、CPM、CPA等
|
||||
|
||||
// 投放条件
|
||||
Targeting *entity.UnifiedTargeting `json:"targeting"` // 定向条件
|
||||
|
||||
// 状态信息
|
||||
Status *string `json:"status"` // 广告状态:待审核、审核中、已通过、已拒绝、投放中、已暂停、已结束
|
||||
AuditStatus *string `json:"auditStatus"` // 审核状态:通过、拒绝
|
||||
AuditReason *string `json:"auditReason"` // 审核不通过原因
|
||||
}
|
||||
|
||||
// GetAdvertisementReq 获取广告详情请求
|
||||
type GetAdvertisementReq struct {
|
||||
g.Meta `path:"/getOne" method:"get" tags:"广告管理" summary:"获取广告详情" dc:"根据ID获取单个广告详情"`
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
}
|
||||
|
||||
type GetAdvertisementRes struct {
|
||||
*entity.Advertisement
|
||||
}
|
||||
|
||||
// ListAdvertisementReq 获取广告列表请求
|
||||
type ListAdvertisementReq struct {
|
||||
g.Meta `path:"/list" method:"get" tags:"广告管理" summary:"获取广告列表" dc:"分页查询广告列表,支持多条件筛选"`
|
||||
*beans.Page
|
||||
|
||||
AdvertiserId string `json:"advertiserId"` // 广告主ID
|
||||
AdPositionId string `json:"adPositionId"` // 广告位ID
|
||||
AdType string `json:"adType"` // 广告类型
|
||||
Status string `json:"status"` // 广告状态
|
||||
AuditStatus string `json:"auditStatus"` // 审核状态
|
||||
Title string `json:"title"` // 广告标题模糊查询
|
||||
DateRange []string `json:"dateRange"` // 创建时间范围 [start, end]
|
||||
}
|
||||
|
||||
type ListAdvertisementRes struct {
|
||||
List []*entity.Advertisement `json:"list"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// AuditAdvertisementReq 审核广告请求
|
||||
type AuditAdvertisementReq struct {
|
||||
g.Meta `path:"/audit" method:"post" tags:"广告管理" summary:"审核广告" dc:"审核广告,通过或拒绝"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告ID
|
||||
AuditStatus string `json:"auditStatus" v:"required"` // 审核状态:通过、拒绝
|
||||
AuditReason string `json:"auditReason"` // 审核不通过原因
|
||||
}
|
||||
|
||||
// UpdateAdStatusReq 更新广告状态请求
|
||||
type UpdateAdStatusReq struct {
|
||||
g.Meta `path:"/updateStatus" method:"patch" tags:"广告管理" summary:"更新广告状态" dc:"更新广告状态"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告ID
|
||||
Status string `json:"status" v:"required"` // 广告状态:启用、禁用
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"cid/model/entity"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// AddAdvertiserReq 添加广告主请求
|
||||
type AddAdvertiserReq struct {
|
||||
g.Meta `path:"/add" method:"post" tags:"广告主管理" summary:"添加广告主" dc:"添加新的广告主"`
|
||||
|
||||
// 基本信息
|
||||
Name string `json:"name" v:"required"` // 广告主名称
|
||||
ContactName string `json:"contactName" v:"required"` // 联系人姓名
|
||||
ContactPhone string `json:"contactPhone" v:"required"` // 联系电话
|
||||
ContactEmail string `json:"contactEmail" v:"required"` // 联系邮箱
|
||||
Company string `json:"company" v:"required"` // 公司名称
|
||||
Industry string `json:"industry" v:"required"` // 所属行业
|
||||
Scale string `json:"scale"` // 公司规模
|
||||
|
||||
// 证件信息
|
||||
BusinessLicenseUrl string `json:"businessLicenseUrl" v:"required"` // 营业执照URL
|
||||
ICPLicenseUrl string `json:"icpLicenseUrl"` // ICP备案截图URL
|
||||
OtherLicenseUrls []string `json:"otherLicenseUrls"` // 其他证件URL
|
||||
|
||||
// 财务信息
|
||||
BankName string `json:"bankName" v:"required"` // 开户银行
|
||||
BankAccount string `json:"bankAccount" v:"required"` // 银行账号
|
||||
AccountName string `json:"accountName" v:"required"` // 账户名称
|
||||
|
||||
// 合同信息
|
||||
ContractId string `json:"contractId"` // 合同编号
|
||||
ContractType string `json:"contractType"` // 合同类型
|
||||
ContractUrl string `json:"contractUrl"` // 合同文件URL
|
||||
SignDate int64 `json:"signDate"` // 签约日期
|
||||
ExpireDate int64 `json:"expireDate"` // 到期日期
|
||||
|
||||
// 系统信息
|
||||
AccountBalance int64 `json:"accountBalance"` // 账户余额(分)
|
||||
CreditLimit int64 `json:"creditLimit"` // 授信额度(分)
|
||||
Remark string `json:"remark"` // 备注
|
||||
}
|
||||
|
||||
type AddAdvertiserRes struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
// UpdateAdvertiserReq 更新广告主请求
|
||||
type UpdateAdvertiserReq struct {
|
||||
g.Meta `path:"/update" method:"put" tags:"广告主管理" summary:"更新广告主" dc:"更新广告主信息"`
|
||||
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
|
||||
// 基本信息
|
||||
Name string `json:"name"` // 广告主名称
|
||||
ContactName string `json:"contactName"` // 联系人姓名
|
||||
ContactPhone string `json:"contactPhone"` // 联系电话
|
||||
ContactEmail string `json:"contactEmail"` // 联系邮箱
|
||||
Company string `json:"company"` // 公司名称
|
||||
Industry string `json:"industry"` // 所属行业
|
||||
Scale string `json:"scale"` // 公司规模
|
||||
|
||||
// 证件信息
|
||||
BusinessLicenseUrl string `json:"businessLicenseUrl"` // 营业执照URL
|
||||
ICPLicenseUrl string `json:"icpLicenseUrl"` // ICP备案截图URL
|
||||
OtherLicenseUrls []string `json:"otherLicenseUrls"` // 其他证件URL
|
||||
|
||||
// 财务信息
|
||||
BankName string `json:"bankName"` // 开户银行
|
||||
BankAccount string `json:"bankAccount"` // 银行账号
|
||||
AccountName string `json:"accountName"` // 账户名称
|
||||
|
||||
// 合同信息
|
||||
ContractId string `json:"contractId"` // 合同编号
|
||||
ContractType string `json:"contractType"` // 合同类型
|
||||
ContractUrl string `json:"contractUrl"` // 合同文件URL
|
||||
SignDate *int64 `json:"signDate"` // 签约日期
|
||||
ExpireDate *int64 `json:"expireDate"` // 到期日期
|
||||
|
||||
// 系统信息
|
||||
AccountBalance *int64 `json:"accountBalance"` // 账户余额(分)
|
||||
CreditLimit *int64 `json:"creditLimit"` // 授信额度(分)
|
||||
Remark string `json:"remark"` // 备注
|
||||
|
||||
// 状态信息
|
||||
Status *string `json:"status"` // 广告主状态:待审核、已审核、已拒绝、已冻结
|
||||
AuditStatus *string `json:"auditStatus"` // 审核状态
|
||||
AuditReason *string `json:"auditReason"` // 审核不通过原因
|
||||
}
|
||||
|
||||
// GetAdvertiserReq 获取广告主详情请求
|
||||
type GetAdvertiserReq struct {
|
||||
g.Meta `path:"/getOne" method:"get" tags:"广告主管理" summary:"获取广告主详情" dc:"根据ID获取单个广告主详情"`
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
}
|
||||
|
||||
type GetAdvertiserRes struct {
|
||||
*entity.Advertiser
|
||||
}
|
||||
|
||||
// ListAdvertiserReq 获取广告主列表请求
|
||||
type ListAdvertiserReq struct {
|
||||
g.Meta `path:"/list" method:"get" tags:"广告主管理" summary:"获取广告主列表" dc:"分页查询广告主列表,支持多条件筛选"`
|
||||
*beans.Page
|
||||
|
||||
Name string `json:"name"` // 广告主名称模糊查询
|
||||
ContactName string `json:"contactName"` // 联系人模糊查询
|
||||
Company string `json:"company"` // 公司名称模糊查询
|
||||
Industry string `json:"industry"` // 所属行业
|
||||
Status string `json:"status"` // 广告主状态
|
||||
AuditStatus string `json:"auditStatus"` // 审核状态
|
||||
DateRange []string `json:"dateRange"` // 创建时间范围 [start, end]
|
||||
}
|
||||
|
||||
type ListAdvertiserRes struct {
|
||||
List []*entity.Advertiser `json:"list"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// AuditAdvertiserReq 审核广告主请求
|
||||
type AuditAdvertiserReq struct {
|
||||
g.Meta `path:"/audit" method:"post" tags:"广告主管理" summary:"审核广告主" dc:"审核广告主,通过或拒绝"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告主ID
|
||||
AuditStatus string `json:"auditStatus" v:"required"` // 审核状态:通过、拒绝
|
||||
AuditReason string `json:"auditReason"` // 审核不通过原因
|
||||
}
|
||||
|
||||
// UpdateAdvertiserStatusReq 更新广告主状态请求
|
||||
type UpdateAdvertiserStatusReq struct {
|
||||
g.Meta `path:"/updateStatus" method:"patch" tags:"广告主管理" summary:"更新广告主状态" dc:"更新广告主状态"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告主ID
|
||||
Status string `json:"status" v:"required"` // 广告主状态:启用、禁用、冻结
|
||||
}
|
||||
|
||||
// RechargeAdvertiserReq 广告主充值请求
|
||||
type RechargeAdvertiserReq struct {
|
||||
g.Meta `path:"/recharge" method:"post" tags:"广告主管理" summary:"广告主充值" dc:"为广告主账户充值"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告主ID
|
||||
Amount int64 `json:"amount" v:"required"` // 充值金额(分)
|
||||
Remark string `json:"remark"` // 充值备注
|
||||
}
|
||||
|
||||
// UpdateCreditLimitReq 更新授信额度请求
|
||||
type UpdateCreditLimitReq struct {
|
||||
g.Meta `path:"/updateCreditLimit" method:"post" tags:"广告主管理" summary:"更新授信额度" dc:"更新广告主的授信额度"`
|
||||
|
||||
Id string `json:"id" v:"required"` // 广告主ID
|
||||
CreditLimit int64 `json:"creditLimit" v:"required"` // 授信额度(分)
|
||||
Remark string `json:"remark"` // 备注说明
|
||||
}
|
||||
|
||||
// GetAdvertiserBalanceReq 获取广告主余额请求
|
||||
type GetAdvertiserBalanceReq struct {
|
||||
g.Meta `path:"/getBalance" method:"get" tags:"广告主管理" summary:"获取广告主余额" dc:"根据ID获取广告主账户余额和授信额度"`
|
||||
Id string `json:"id" v:"required"` // 广告主ID
|
||||
}
|
||||
|
||||
// GetAdvertiserBalanceRes 获取广告主余额响应
|
||||
type GetAdvertiserBalanceRes struct {
|
||||
Balance int64 `json:"balance"` // 账户余额(分)
|
||||
CreditLimit int64 `json:"creditLimit"` // 授信额度(分)
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"cid/consts/app"
|
||||
entity "cid/model/entity/app"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreateApplicationReq 创建应用请求
|
||||
type CreateApplicationReq struct {
|
||||
g.Meta `path:"/createApplication" method:"post" tags:"应用管理" summary:"创建应用" dc:"创建新的应用"`
|
||||
Name string `json:"name" v:"required" dc:"应用名称"`
|
||||
AppCode string `json:"appCode" v:"required" dc:"应用编码(唯一标识)"`
|
||||
Type app.AppType `json:"type" v:"required" dc:"应用类型"`
|
||||
Status app.AppStatus `json:"status" dc:"应用状态" d:"active"`
|
||||
Description string `json:"description" dc:"应用描述"`
|
||||
AccessConfig map[string]interface{} `json:"accessConfig" dc:"接入配置"`
|
||||
LimitConfig map[string]interface{} `json:"limitConfig" dc:"限流配置"`
|
||||
CallbackConfig map[string]interface{} `json:"callbackConfig" dc:"回调配置"`
|
||||
}
|
||||
|
||||
// CreateApplicationRes 创建应用响应
|
||||
type CreateApplicationRes struct {
|
||||
Id int64 `json:"id" dc:"应用ID"`
|
||||
}
|
||||
|
||||
// ListApplicationReq 获取应用列表请求
|
||||
type ListApplicationReq struct {
|
||||
g.Meta `path:"/listApplications" method:"get" tags:"应用管理" summary:"获取应用列表" dc:"分页查询应用列表"`
|
||||
*beans.Page
|
||||
Name string `json:"name" dc:"应用名称"`
|
||||
AppCode string `json:"appCode" dc:"应用编码"`
|
||||
Type app.AppType `json:"type" dc:"应用类型"`
|
||||
Status app.AppStatus `json:"status" dc:"应用状态"`
|
||||
Keyword string `json:"keyword" dc:"关键字(搜索应用名称或编码)"`
|
||||
}
|
||||
|
||||
// ListApplicationRes 获取应用列表响应
|
||||
type ListApplicationRes struct {
|
||||
List []ApplicationItem `json:"list" dc:"应用列表"`
|
||||
Total int `json:"total" dc:"总数"`
|
||||
}
|
||||
|
||||
type ApplicationItem struct {
|
||||
Id int64 `json:"id,string"`
|
||||
Name string `json:"name"`
|
||||
AppCode string `json:"appCode"`
|
||||
Type app.AppType `json:"type"`
|
||||
TypeName string `json:"typeName"`
|
||||
Status app.AppStatus `json:"status"`
|
||||
StatusName string `json:"statusName"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// GetApplicationReq 获取应用详情请求
|
||||
type GetApplicationReq struct {
|
||||
g.Meta `path:"/getApplication" method:"get" tags:"应用管理" summary:"获取应用详情" dc:"获取应用详情"`
|
||||
Id int64 `json:"id" v:"required" dc:"应用ID"`
|
||||
}
|
||||
|
||||
// GetApplicationRes 获取应用详情响应
|
||||
type GetApplicationRes struct {
|
||||
*entity.Application
|
||||
}
|
||||
|
||||
// UpdateApplicationReq 更新应用请求
|
||||
type UpdateApplicationReq struct {
|
||||
g.Meta `path:"/updateApplication" method:"put" tags:"应用管理" summary:"更新应用" dc:"更新应用信息"`
|
||||
Id int64 `json:"id" v:"required" dc:"应用ID"`
|
||||
Name string `json:"name" dc:"应用名称"`
|
||||
AppCode string `json:"appCode" dc:"应用编码"`
|
||||
Type app.AppType `json:"type" dc:"应用类型"`
|
||||
Status app.AppStatus `json:"status,omitempty" dc:"应用状态"`
|
||||
Description string `json:"description" dc:"应用描述"`
|
||||
AccessConfig map[string]interface{} `json:"accessConfig" dc:"接入配置"`
|
||||
LimitConfig map[string]interface{} `json:"limitConfig" dc:"限流配置"`
|
||||
CallbackConfig map[string]interface{} `json:"callbackConfig" dc:"回调配置"`
|
||||
}
|
||||
|
||||
// DeleteApplicationReq 删除应用请求
|
||||
type DeleteApplicationReq struct {
|
||||
g.Meta `path:"/deleteApplication" method:"delete" tags:"应用管理" summary:"删除应用" dc:"删除应用"`
|
||||
Id int64 `json:"id" v:"required" dc:"应用ID"`
|
||||
}
|
||||
|
||||
// UpdateApplicationStatusReq 更新应用状态请求
|
||||
type UpdateApplicationStatusReq struct {
|
||||
g.Meta `path:"/updateApplicationStatus" method:"put" tags:"应用管理" summary:"更新应用状态" dc:"更新应用状态"`
|
||||
Id int64 `json:"id" v:"required" dc:"应用ID"`
|
||||
Status app.AppStatus `json:"status" v:"required|in:active,inactive" dc:"状态:active启用/inactive停用"`
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreateApplicationReq 创建应用请求
|
||||
type CreateApplicationReq struct {
|
||||
g.Meta `path:"/createApplication" method:"post" summary:"创建应用"`
|
||||
|
||||
TenantID interface{} `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 interface{} `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:"/resetAPIKeys" 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:"/validateApplication" 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:"/deleteApplication" method:"delete" summary:"删除应用"`
|
||||
|
||||
ID int64 `json:"id" v:"required#应用ID不能为空"`
|
||||
}
|
||||
|
||||
// DeleteApplicationRes 删除应用响应
|
||||
type DeleteApplicationRes struct {
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// GenerateCIDReq 生成CID请求
|
||||
type GenerateCIDReq struct {
|
||||
g.Meta `path:"/generateCID" method:"post" tags:"CID服务" summary:"生成CID广告" dc:"为当前用户生成CID广告"`
|
||||
UserId int64 `json:"user_id"` // 用户ID(可选,如果不提供则从token获取)
|
||||
RequestType string `json:"request_type"` // 请求类型
|
||||
Parameters map[string]interface{} `json:"parameters"` // 请求参数
|
||||
Position string `json:"position"` // 广告位置
|
||||
Count int `json:"count"` // 广告数量
|
||||
}
|
||||
|
||||
// AdInfo 广告信息
|
||||
type AdInfo struct {
|
||||
Id int64 `json:"id"` // 广告ID
|
||||
Title string `json:"title"` // 广告标题
|
||||
Description string `json:"description"` // 广告描述
|
||||
ImageUrl string `json:"image_url"` // 广告图片URL
|
||||
TargetUrl string `json:"target_url"` // 目标链接
|
||||
ConversionRate float64 `json:"conversion_rate"` // 转化率
|
||||
Source string `json:"source"` // 广告源
|
||||
Bid int `json:"bid"` // 出价(分)
|
||||
}
|
||||
|
||||
// GenerateCIDRes 生成CID响应
|
||||
type GenerateCIDRes struct {
|
||||
CID string `json:"cid"` // 唯一CID
|
||||
Ads []*AdInfo `json:"ads"` // 广告列表
|
||||
TotalAds int `json:"total_ads"` // 总广告数
|
||||
TenantId interface{} `json:"tenant_id"` // 租户ID
|
||||
TenantName string `json:"tenant_name"` // 租户名称
|
||||
GeneratedAt string `json:"generated_at"` // 生成时间
|
||||
}
|
||||
|
||||
// CIDRequestHistory CID请求历史记录
|
||||
type CIDRequestHistory struct {
|
||||
Id int64 `json:"id"` // 记录ID
|
||||
TenantId interface{} `json:"tenant_id"` // 租户ID
|
||||
UserId int64 `json:"user_id"` // 用户ID
|
||||
RequestType string `json:"request_type"` // 请求类型
|
||||
Status string `json:"status"` // 状态
|
||||
ProcessTime int `json:"process_time"` // 处理时间(ms)
|
||||
CreatedAt string `json:"created_at"` // 创建时间
|
||||
}
|
||||
|
||||
// GetCIDHistoryReq 获取CID历史请求
|
||||
type GetCIDHistoryReq struct {
|
||||
g.Meta `path:"/getCidHistory" method:"get" tags:"CID服务" summary:"获取CID历史记录" dc:"分页获取用户的CID请求历史"`
|
||||
Page int `json:"page" v:"required|min:1"` // 页码
|
||||
Size int `json:"size" v:"required|min:1|max:100"` // 每页数量
|
||||
}
|
||||
|
||||
// GetCIDHistoryRes 获取CID历史响应
|
||||
type GetCIDHistoryRes struct {
|
||||
List []*CIDRequestHistory `json:"list"` // 历史记录列表
|
||||
Total int64 `json:"total"` // 总数
|
||||
Page int `json:"page"` // 当前页
|
||||
Size int `json:"size"` // 每页数量
|
||||
}
|
||||
|
||||
// TenantInfo 租户信息
|
||||
type TenantInfo struct {
|
||||
Id string `json:"id"` // 租户ID
|
||||
Name string `json:"name"` // 租户名称
|
||||
Level string `json:"level"` // 租户级别
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"cid/consts/data"
|
||||
entity "cid/model/entity/data"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreateApiInterfaceReq 创建接口请求
|
||||
type CreateApiInterfaceReq struct {
|
||||
g.Meta `path:"/createApiInterface" method:"post" tags:"接口管理" summary:"创建接口" dc:"创建新的数据接口"`
|
||||
PlatformId int64 `json:"platformId" v:"required" dc:"所属平台ID"`
|
||||
Name string `json:"name" v:"required" dc:"接口名称"`
|
||||
Code string `json:"code" v:"required" dc:"接口编码"`
|
||||
Url string `json:"url" v:"required" dc:"接口地址"`
|
||||
Method data.ApiMethod `json:"method" v:"required" dc:"请求方法"`
|
||||
Status data.PlatformStatus `json:"status" dc:"接口状态" d:"active"`
|
||||
AuthType string `json:"authType" dc:"认证类型"`
|
||||
RequestConfig map[string]interface{} `json:"requestConfig" dc:"请求配置"`
|
||||
ResponseConfig map[string]interface{} `json:"responseConfig" dc:"响应配置"`
|
||||
LimitConfig map[string]interface{} `json:"limitConfig" dc:"接口独立限流配置"`
|
||||
}
|
||||
|
||||
// CreateApiInterfaceRes 创建接口响应
|
||||
type CreateApiInterfaceRes struct {
|
||||
Id int64 `json:"id" dc:"接口ID"`
|
||||
}
|
||||
|
||||
// ListApiInterfaceReq 获取接口列表请求
|
||||
type ListApiInterfaceReq struct {
|
||||
g.Meta `path:"/listApiInterfaces" method:"get" tags:"接口管理" summary:"获取接口列表" dc:"分页查询接口列表"`
|
||||
*beans.Page
|
||||
PlatformId int64 `json:"platformId" dc:"平台ID"`
|
||||
Name string `json:"name" dc:"接口名称"`
|
||||
Code string `json:"code" dc:"接口编码"`
|
||||
Method data.ApiMethod `json:"method" dc:"请求方法"`
|
||||
Status data.PlatformStatus `json:"status" dc:"接口状态"`
|
||||
Keyword string `json:"keyword" dc:"关键字(搜索名称或编码)"`
|
||||
}
|
||||
|
||||
// ListApiInterfaceRes 获取接口列表响应
|
||||
type ListApiInterfaceRes struct {
|
||||
List []ApiInterfaceItem `json:"list" dc:"接口列表"`
|
||||
Total int `json:"total" dc:"总数"`
|
||||
}
|
||||
|
||||
type ApiInterfaceItem struct {
|
||||
Id int64 `json:"id,string"`
|
||||
PlatformId int64 `json:"platformId"`
|
||||
PlatformName string `json:"platformName"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Url string `json:"url"`
|
||||
Method data.ApiMethod `json:"method"`
|
||||
Status data.PlatformStatus `json:"status"`
|
||||
StatusName string `json:"statusName"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// GetApiInterfaceReq 获取接口详情请求
|
||||
type GetApiInterfaceReq struct {
|
||||
g.Meta `path:"/getApiInterface" method:"get" tags:"接口管理" summary:"获取接口详情" dc:"获取接口详情"`
|
||||
Id int64 `json:"id" v:"required" dc:"接口ID"`
|
||||
}
|
||||
|
||||
// GetApiInterfaceRes 获取接口详情响应
|
||||
type GetApiInterfaceRes struct {
|
||||
*entity.ApiInterface
|
||||
PlatformName string `json:"platformName,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateApiInterfaceReq 更新接口请求
|
||||
type UpdateApiInterfaceReq struct {
|
||||
g.Meta `path:"/updateApiInterface" method:"put" tags:"接口管理" summary:"更新接口" dc:"更新接口信息"`
|
||||
Id int64 `json:"id" v:"required" dc:"接口ID"`
|
||||
PlatformId int64 `json:"platformId" dc:"所属平台ID"`
|
||||
Name string `json:"name" dc:"接口名称"`
|
||||
Code string `json:"code" dc:"接口编码"`
|
||||
Url string `json:"url" dc:"接口地址"`
|
||||
Method data.ApiMethod `json:"method" dc:"请求方法"`
|
||||
Status data.PlatformStatus `json:"status,omitempty" dc:"接口状态"`
|
||||
AuthType string `json:"authType" dc:"认证类型"`
|
||||
RequestConfig map[string]interface{} `json:"requestConfig" dc:"请求配置"`
|
||||
ResponseConfig map[string]interface{} `json:"responseConfig" dc:"响应配置"`
|
||||
LimitConfig map[string]interface{} `json:"limitConfig" dc:"接口独立限流配置"`
|
||||
}
|
||||
|
||||
// DeleteApiInterfaceReq 删除接口请求
|
||||
type DeleteApiInterfaceReq struct {
|
||||
g.Meta `path:"/deleteApiInterface" method:"delete" tags:"接口管理" summary:"删除接口" dc:"删除接口"`
|
||||
Id int64 `json:"id" v:"required" dc:"接口ID"`
|
||||
}
|
||||
|
||||
// UpdateApiInterfaceStatusReq 更新接口状态请求
|
||||
type UpdateApiInterfaceStatusReq struct {
|
||||
g.Meta `path:"/updateApiInterfaceStatus" method:"put" tags:"接口管理" summary:"更新接口状态" dc:"更新接口状态"`
|
||||
Id int64 `json:"id" v:"required" dc:"接口ID"`
|
||||
Status data.PlatformStatus `json:"status" v:"required|in:active,inactive" dc:"状态:active启用/inactive停用"`
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"cid/consts/data"
|
||||
entity "cid/model/entity/data"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// ExecuteDataFetchReq 执行数据获取请求
|
||||
type ExecuteDataFetchReq struct {
|
||||
g.Meta `path:"/executeDataFetch" method:"post" tags:"数据获取" summary:"执行数据获取" dc:"执行接口数据获取"`
|
||||
PlatformId int64 `json:"platformId" v:"required" dc:"平台ID"`
|
||||
InterfaceId int64 `json:"interfaceId" v:"required" dc:"接口ID"`
|
||||
RequestParams map[string]interface{} `json:"requestParams" dc:"请求参数"`
|
||||
}
|
||||
|
||||
// ExecuteDataFetchRes 执行数据获取响应
|
||||
type ExecuteDataFetchRes struct {
|
||||
RequestId string `json:"requestId" dc:"请求ID"`
|
||||
Status string `json:"status" dc:"状态"`
|
||||
Message string `json:"message" dc:"消息"`
|
||||
}
|
||||
|
||||
// ListDataFetchLogReq 获取数据获取日志列表请求
|
||||
type ListDataFetchLogReq struct {
|
||||
g.Meta `path:"/listDataFetchLogs" method:"get" tags:"数据获取" summary:"获取数据获取日志" dc:"分页查询数据获取日志"`
|
||||
*beans.Page
|
||||
PlatformId int64 `json:"platformId" dc:"平台ID"`
|
||||
InterfaceId int64 `json:"interfaceId" dc:"接口ID"`
|
||||
RequestId string `json:"requestId" dc:"请求ID"`
|
||||
Status data.FetchStatus `json:"status" dc:"执行状态"`
|
||||
StartTime int64 `json:"startTime" dc:"开始时间(时间戳)"`
|
||||
EndTime int64 `json:"endTime" dc:"结束时间(时间戳)"`
|
||||
}
|
||||
|
||||
// ListDataFetchLogRes 获取数据获取日志列表响应
|
||||
type ListDataFetchLogRes struct {
|
||||
List []DataFetchLogItem `json:"list" dc:"日志列表"`
|
||||
Total int `json:"total" dc:"总数"`
|
||||
}
|
||||
|
||||
type DataFetchLogItem struct {
|
||||
Id int64 `json:"id,string"`
|
||||
PlatformId int64 `json:"platformId"`
|
||||
PlatformName string `json:"platformName"`
|
||||
InterfaceId int64 `json:"interfaceId"`
|
||||
InterfaceName string `json:"interfaceName"`
|
||||
RequestId string `json:"requestId"`
|
||||
Status data.FetchStatus `json:"status"`
|
||||
StatusName string `json:"statusName"`
|
||||
StartTime int64 `json:"startTime"`
|
||||
EndTime int64 `json:"endTime"`
|
||||
Duration int `json:"duration"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
RetryCount int `json:"retryCount"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
}
|
||||
|
||||
// GetDataFetchLogReq 获取数据获取日志详情请求
|
||||
type GetDataFetchLogReq struct {
|
||||
g.Meta `path:"/getDataFetchLog" method:"get" tags:"数据获取" summary:"获取数据获取日志详情" dc:"获取数据获取日志详情"`
|
||||
Id int64 `json:"id" v:"required" dc:"日志ID"`
|
||||
}
|
||||
|
||||
// GetDataFetchLogRes 获取数据获取日志详情响应
|
||||
type GetDataFetchLogRes struct {
|
||||
*entity.DataFetchLog
|
||||
PlatformName string `json:"platformName,omitempty"`
|
||||
InterfaceName string `json:"interfaceName,omitempty"`
|
||||
}
|
||||
|
||||
// BatchExecuteDataFetchReq 批量执行数据获取请求
|
||||
type BatchExecuteDataFetchReq struct {
|
||||
g.Meta `path:"/batchExecuteDataFetch" method:"post" tags:"数据获取" summary:"批量执行数据获取" dc:"批量执行接口数据获取"`
|
||||
InterfaceIds []int64 `json:"interfaceIds" v:"required" dc:"接口ID列表"`
|
||||
RequestParams map[string]interface{} `json:"requestParams" dc:"请求参数(所有接口共用)"`
|
||||
}
|
||||
|
||||
// BatchExecuteDataFetchRes 批量执行数据获取响应
|
||||
type BatchExecuteDataFetchRes struct {
|
||||
SuccessCount int `json:"successCount" dc:"成功数量"`
|
||||
FailedCount int `json:"failedCount" dc:"失败数量"`
|
||||
RequestIds []string `json:"requestIds" dc:"请求ID列表"`
|
||||
}
|
||||
|
||||
// ReExecuteDataFetchReq 重新执行数据获取请求
|
||||
type ReExecuteDataFetchReq struct {
|
||||
g.Meta `path:"/reExecuteDataFetch" method:"post" tags:"数据获取" summary:"重新执行数据获取" dc:"重新执行失败的数据获取"`
|
||||
LogId int64 `json:"logId" v:"required" dc:"日志ID"`
|
||||
}
|
||||
|
||||
// ReExecuteDataFetchRes 重新执行数据获取响应
|
||||
type ReExecuteDataFetchRes struct {
|
||||
RequestId string `json:"requestId" dc:"请求ID"`
|
||||
Status string `json:"status" dc:"状态"`
|
||||
Message string `json:"message" dc:"消息"`
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"cid/consts/data"
|
||||
entity "cid/model/entity/data"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreatePlatformReq 创建平台请求
|
||||
type CreatePlatformReq struct {
|
||||
g.Meta `path:"/createPlatform" method:"post" tags:"平台管理" summary:"创建平台" dc:"创建新的数据源平台"`
|
||||
Name string `json:"name" v:"required" dc:"平台名称"`
|
||||
Type data.SyncPlatform `json:"type" v:"required" dc:"平台类型"`
|
||||
Status data.PlatformStatus `json:"status" dc:"平台状态" d:"active"`
|
||||
Description string `json:"description" dc:"平台描述"`
|
||||
AuthConfig map[string]interface{} `json:"authConfig" dc:"认证配置"`
|
||||
LimitConfig map[string]interface{} `json:"limitConfig" dc:"限流配置"`
|
||||
PlatformConfig map[string]interface{} `json:"platformConfig" dc:"平台专用配置"`
|
||||
}
|
||||
|
||||
// CreatePlatformRes 创建平台响应
|
||||
type CreatePlatformRes struct {
|
||||
Id int64 `json:"id" dc:"平台ID"`
|
||||
}
|
||||
|
||||
// ListPlatformReq 获取平台列表请求
|
||||
type ListPlatformReq struct {
|
||||
g.Meta `path:"/listPlatforms" method:"get" tags:"平台管理" summary:"获取平台列表" dc:"分页查询平台列表"`
|
||||
*beans.Page
|
||||
Name string `json:"name" dc:"平台名称"`
|
||||
Type data.SyncPlatform `json:"type" dc:"平台类型"`
|
||||
Status data.PlatformStatus `json:"status" dc:"平台状态"`
|
||||
Keyword string `json:"keyword" dc:"关键字(搜索平台名称)"`
|
||||
}
|
||||
|
||||
// ListPlatformRes 获取平台列表响应
|
||||
type ListPlatformRes struct {
|
||||
List []PlatformItem `json:"list" dc:"平台列表"`
|
||||
Total int `json:"total" dc:"总数"`
|
||||
}
|
||||
|
||||
type PlatformItem struct {
|
||||
Id int64 `json:"id,string"`
|
||||
Name string `json:"name"`
|
||||
Type data.SyncPlatform `json:"type"`
|
||||
TypeName string `json:"typeName"`
|
||||
Status data.PlatformStatus `json:"status"`
|
||||
StatusName string `json:"statusName"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// GetPlatformReq 获取平台详情请求
|
||||
type GetPlatformReq struct {
|
||||
g.Meta `path:"/getPlatform" method:"get" tags:"平台管理" summary:"获取平台详情" dc:"获取平台详情"`
|
||||
Id int64 `json:"id" v:"required" dc:"平台ID"`
|
||||
}
|
||||
|
||||
// GetPlatformRes 获取平台详情响应
|
||||
type GetPlatformRes struct {
|
||||
*entity.Platform
|
||||
}
|
||||
|
||||
// UpdatePlatformReq 更新平台请求
|
||||
type UpdatePlatformReq struct {
|
||||
g.Meta `path:"/updatePlatform" method:"put" tags:"平台管理" summary:"更新平台" dc:"更新平台信息"`
|
||||
Id int64 `json:"id" v:"required" dc:"平台ID"`
|
||||
Name string `json:"name" dc:"平台名称"`
|
||||
Type data.SyncPlatform `json:"type" dc:"平台类型"`
|
||||
Status data.PlatformStatus `json:"status,omitempty" dc:"平台状态"`
|
||||
Description string `json:"description" dc:"平台描述"`
|
||||
AuthConfig map[string]interface{} `json:"authConfig" dc:"认证配置"`
|
||||
LimitConfig map[string]interface{} `json:"limitConfig" dc:"限流配置"`
|
||||
PlatformConfig map[string]interface{} `json:"platformConfig" dc:"平台专用配置"`
|
||||
}
|
||||
|
||||
// DeletePlatformReq 删除平台请求
|
||||
type DeletePlatformReq struct {
|
||||
g.Meta `path:"/deletePlatform" method:"delete" tags:"平台管理" summary:"删除平台" dc:"删除平台"`
|
||||
Id int64 `json:"id" v:"required" dc:"平台ID"`
|
||||
}
|
||||
|
||||
// UpdatePlatformStatusReq 更新平台状态请求
|
||||
type UpdatePlatformStatusReq struct {
|
||||
g.Meta `path:"/updatePlatformStatus" method:"put" tags:"平台管理" summary:"更新平台状态" dc:"更新平台状态"`
|
||||
Id int64 `json:"id" v:"required" dc:"平台ID"`
|
||||
Status data.PlatformStatus `json:"status" v:"required|in:active,inactive" dc:"状态:active启用/inactive停用"`
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package mapping
|
||||
|
||||
import (
|
||||
"cid/consts/mapping"
|
||||
entity "cid/model/entity/mapping"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreateDataMappingReq 创建数据映射请求
|
||||
type CreateDataMappingReq struct {
|
||||
g.Meta `path:"/createDataMapping" method:"post" tags:"数据映射" summary:"创建数据映射" dc:"创建数据映射规则"`
|
||||
PlatformId int64 `json:"platformId" v:"required" dc:"平台ID"`
|
||||
InterfaceId int64 `json:"interfaceId" v:"required" dc:"接口ID"`
|
||||
SourceField string `json:"sourceField" v:"required" dc:"源字段"`
|
||||
TargetField string `json:"targetField" v:"required" dc:"目标字段"`
|
||||
FieldType string `json:"fieldType" v:"required" dc:"字段类型"`
|
||||
DefaultValue string `json:"defaultValue" dc:"默认值"`
|
||||
TransformRule map[string]interface{} `json:"transformRule" dc:"转换规则"`
|
||||
Priority int `json:"priority" dc:"优先级" d:"0"`
|
||||
Status mapping.MappingStatus `json:"status" dc:"状态" d:"active"`
|
||||
}
|
||||
|
||||
// CreateDataMappingRes 创建数据映射响应
|
||||
type CreateDataMappingRes struct {
|
||||
Id int64 `json:"id" dc:"映射ID"`
|
||||
}
|
||||
|
||||
// ListDataMappingReq 获取数据映射列表请求
|
||||
type ListDataMappingReq struct {
|
||||
g.Meta `path:"/listDataMappings" method:"get" tags:"数据映射" summary:"获取数据映射列表" dc:"分页查询数据映射列表"`
|
||||
*beans.Page
|
||||
PlatformId int64 `json:"platformId" dc:"平台ID"`
|
||||
InterfaceId int64 `json:"interfaceId" dc:"接口ID"`
|
||||
SourceField string `json:"sourceField" dc:"源字段"`
|
||||
TargetField string `json:"targetField" dc:"目标字段"`
|
||||
Status mapping.MappingStatus `json:"status" dc:"状态"`
|
||||
}
|
||||
|
||||
// ListDataMappingRes 获取数据映射列表响应
|
||||
type ListDataMappingRes struct {
|
||||
List []DataMappingItem `json:"list" dc:"映射列表"`
|
||||
Total int `json:"total" dc:"总数"`
|
||||
}
|
||||
|
||||
type DataMappingItem struct {
|
||||
Id int64 `json:"id,string"`
|
||||
PlatformId int64 `json:"platformId"`
|
||||
PlatformName string `json:"platformName"`
|
||||
InterfaceId int64 `json:"interfaceId"`
|
||||
InterfaceName string `json:"interfaceName"`
|
||||
SourceField string `json:"sourceField"`
|
||||
TargetField string `json:"targetField"`
|
||||
FieldType string `json:"fieldType"`
|
||||
DefaultValue string `json:"defaultValue"`
|
||||
TransformRule map[string]interface{} `json:"transformRule"`
|
||||
Priority int `json:"priority"`
|
||||
Status mapping.MappingStatus `json:"status"`
|
||||
StatusName string `json:"statusName"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// GetDataMappingReq 获取数据映射详情请求
|
||||
type GetDataMappingReq struct {
|
||||
g.Meta `path:"/getDataMapping" method:"get" tags:"数据映射" summary:"获取数据映射详情" dc:"获取数据映射详情"`
|
||||
Id int64 `json:"id" v:"required" dc:"映射ID"`
|
||||
}
|
||||
|
||||
// GetDataMappingRes 获取数据映射详情响应
|
||||
type GetDataMappingRes struct {
|
||||
*entity.DataMapping
|
||||
PlatformName string `json:"platformName,omitempty"`
|
||||
InterfaceName string `json:"interfaceName,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateDataMappingReq 更新数据映射请求
|
||||
type UpdateDataMappingReq struct {
|
||||
g.Meta `path:"/updateDataMapping" method:"put" tags:"数据映射" summary:"更新数据映射" dc:"更新数据映射规则"`
|
||||
Id int64 `json:"id" v:"required" dc:"映射ID"`
|
||||
PlatformId int64 `json:"platformId" dc:"平台ID"`
|
||||
InterfaceId int64 `json:"interfaceId" dc:"接口ID"`
|
||||
SourceField string `json:"sourceField" dc:"源字段"`
|
||||
TargetField string `json:"targetField" dc:"目标字段"`
|
||||
FieldType string `json:"fieldType" dc:"字段类型"`
|
||||
DefaultValue string `json:"defaultValue" dc:"默认值"`
|
||||
TransformRule map[string]interface{} `json:"transformRule" dc:"转换规则"`
|
||||
Priority int `json:"priority" dc:"优先级"`
|
||||
Status mapping.MappingStatus `json:"status,omitempty" dc:"状态"`
|
||||
}
|
||||
|
||||
// DeleteDataMappingReq 删除数据映射请求
|
||||
type DeleteDataMappingReq struct {
|
||||
g.Meta `path:"/deleteDataMapping" method:"delete" tags:"数据映射" summary:"删除数据映射" dc:"删除数据映射"`
|
||||
Id int64 `json:"id" v:"required" dc:"映射ID"`
|
||||
}
|
||||
|
||||
// BatchCreateDataMappingReq 批量创建数据映射请求
|
||||
type BatchCreateDataMappingReq struct {
|
||||
g.Meta `path:"/batchCreateDataMappings" method:"post" tags:"数据映射" summary:"批量创建数据映射" dc:"批量创建数据映射规则"`
|
||||
PlatformId int64 `json:"platformId" v:"required" dc:"平台ID"`
|
||||
InterfaceId int64 `json:"interfaceId" v:"required" dc:"接口ID"`
|
||||
Mappings []CreateDataMappingReq `json:"mappings" v:"required" dc:"映射规则列表"`
|
||||
}
|
||||
|
||||
// BatchCreateDataMappingRes 批量创建数据映射响应
|
||||
type BatchCreateDataMappingRes struct {
|
||||
SuccessCount int `json:"successCount" dc:"成功数量"`
|
||||
FailedCount int `json:"failedCount" dc:"失败数量"`
|
||||
Ids []int64 `json:"ids" dc:"映射ID列表"`
|
||||
}
|
||||
|
||||
// ExecuteDataMappingReq 执行数据映射请求
|
||||
type ExecuteDataMappingReq struct {
|
||||
g.Meta `path:"/executeDataMapping" method:"post" tags:"数据映射" summary:"执行数据映射" dc:"执行数据字段映射"`
|
||||
InterfaceId int64 `json:"interfaceId" v:"required" dc:"接口ID"`
|
||||
SourceData map[string]interface{} `json:"sourceData" v:"required" dc:"源数据"`
|
||||
}
|
||||
|
||||
// ExecuteDataMappingRes 执行数据映射响应
|
||||
type ExecuteDataMappingRes struct {
|
||||
TargetData map[string]interface{} `json:"targetData" dc:"目标数据"`
|
||||
AppliedRules []string `json:"appliedRules" dc:"应用的映射规则"`
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// SetTenantRateLimitReq 设置租户限流配置请求
|
||||
type SetTenantRateLimitReq struct {
|
||||
g.Meta `path:"/setTenantRateLimit" 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:"/getTenantRateLimitUsage" 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,89 +0,0 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreateStrategyReq 创建策略请求
|
||||
type CreateStrategyReq struct {
|
||||
g.Meta `path:"/create" method:"post" tags:"策略管理" summary:"创建匹配策略" dc:"创建新的广告匹配策略"`
|
||||
Name string `json:"name" v:"required|length:3,50"` // 策略名称
|
||||
Description string `json:"description" v:"max:500"` // 描述
|
||||
TenantLevel string `json:"tenant_level" v:"required|in:basic,standard,premium"` // 租户级别
|
||||
MinConversion float64 `json:"min_conversion" v:"required|min:0|max:1"` // 最低转化率
|
||||
MaxConversion float64 `json:"max_conversion" v:"required|min:0|max:1"` // 最高转化率
|
||||
SourceWeights map[string]int `json:"source_weights" v:"required"` // 广告源权重
|
||||
MaxAdsPerReq int `json:"max_ads_per_req" v:"required|min:1|max:50"` // 每次请求最大广告数
|
||||
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:"/update" method:"put" tags:"策略管理" summary:"更新匹配策略" dc:"更新现有的广告匹配策略"`
|
||||
Id int64 `json:"id" v:"required"` // 策略ID
|
||||
Name string `json:"name" v:"required|length:3,50"` // 策略名称
|
||||
Description string `json:"description" v:"max:500"` // 描述
|
||||
TenantLevel string `json:"tenant_level" v:"required|in:basic,standard,premium"` // 租户级别
|
||||
MinConversion float64 `json:"min_conversion" v:"required|min:0|max:1"` // 最低转化率
|
||||
MaxConversion float64 `json:"max_conversion" v:"required|min:0|max:1"` // 最高转化率
|
||||
SourceWeights map[string]int `json:"source_weights" v:"required"` // 广告源权重
|
||||
MaxAdsPerReq int `json:"max_ads_per_req" v:"required|min:1|max:50"` // 每次请求最大广告数
|
||||
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:"/delete" method:"delete" tags:"策略管理" summary:"删除匹配策略" dc:"删除指定的广告匹配策略"`
|
||||
Id int64 `json:"id" v:"required"` // 策略ID
|
||||
}
|
||||
|
||||
// GetStrategyReq 获取策略请求
|
||||
type GetStrategyReq struct {
|
||||
g.Meta `path:"/getByID" method:"get" tags:"策略管理" summary:"获取策略详情" dc:"获取指定策略的详细信息"`
|
||||
Id int64 `json:"id" v:"required"` // 策略ID
|
||||
}
|
||||
|
||||
// GetStrategyListReq 获取策略列表请求
|
||||
type GetStrategyListReq struct {
|
||||
g.Meta `path:"/getList" method:"get" tags:"策略管理" summary:"获取策略列表" dc:"分页获取策略列表"`
|
||||
Page int `json:"page" v:"required|min:1"` // 页码
|
||||
Size int `json:"size" v:"required|min:1|max:100"` // 每页数量
|
||||
TenantLevel string `json:"tenant_level"` // 租户级别筛选
|
||||
Status string `json:"status"` // 状态筛选
|
||||
}
|
||||
|
||||
// StrategyRes 策略响应
|
||||
type StrategyRes struct {
|
||||
Id int64 `json:"id"` // ID
|
||||
Name string `json:"name"` // 策略名称
|
||||
Description string `json:"description"` // 描述
|
||||
TenantLevel string `json:"tenant_level"` // 租户级别
|
||||
MinConversion float64 `json:"min_conversion"` // 最低转化率
|
||||
MaxConversion float64 `json:"max_conversion"` // 最高转化率
|
||||
SourceWeights map[string]int `json:"source_weights"` // 广告源权重
|
||||
MaxAdsPerReq int `json:"max_ads_per_req"` // 每次请求最大广告数
|
||||
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 获取策略列表响应
|
||||
type GetStrategyListRes struct {
|
||||
List []*StrategyRes `json:"list"` // 策略列表
|
||||
Total int64 `json:"total"` // 总数
|
||||
Page int `json:"page"` // 当前页
|
||||
Size int `json:"size"` // 每页数量
|
||||
}
|
||||
|
||||
// DeleteStrategyRes 删除策略响应
|
||||
type DeleteStrategyRes struct {
|
||||
Success bool `json:"success"` // 是否成功
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"cid/model/config"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const AdCreativeCollection = "ad_creative"
|
||||
|
||||
// AdCreative 广告创意素材实体
|
||||
type AdCreative struct {
|
||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
||||
AdvertiserId string `bson:"advertiserId" json:"advertiserId"` // 广告主ID
|
||||
|
||||
// 基本信息
|
||||
Name string `bson:"name" json:"name"` // 创意名称
|
||||
Title string `bson:"title" json:"title"` // 广告标题
|
||||
Description string `bson:"description" json:"description"` // 广告描述
|
||||
AdType string `bson:"adType" json:"adType"` // 广告类型:image、video、native、interstitial等
|
||||
Format string `bson:"format" json:"format"` // 创意格式:jpg、png、mp4、html等
|
||||
|
||||
// 素材信息
|
||||
MaterialURL string `bson:"materialUrl" json:"materialUrl"` // 素材URL
|
||||
ThumbnailURL string `bson:"thumbnailUrl" json:"thumbnailUrl"` // 缩略图URL
|
||||
LandingPageURL string `bson:"landingPageUrl" json:"landingPageUrl"` // 落地页URL
|
||||
DisplayURL string `bson:"displayUrl" json:"displayUrl"` // 显示URL
|
||||
|
||||
// 尺寸和文件信息
|
||||
Width int64 `bson:"width" json:"width"` // 宽度(px)
|
||||
Height int64 `bson:"height" json:"height"` // 高度(px)
|
||||
Size int64 `bson:"size" json:"size"` // 文件大小(bytes)
|
||||
Duration int64 `bson:"duration" json:"duration"` // 时长(秒)
|
||||
HasAudio bool `bson:"hasAudio" json:"hasAudio"` // 是否有音频
|
||||
AspectRatio string `bson:"aspectRatio" json:"aspectRatio"` // 宽高比
|
||||
|
||||
// 技术信息
|
||||
MimeType string `bson:"mimeType" json:"mimeType"` // MIME类型
|
||||
Source string `bson:"source" json:"source"` // 来源:upload、sync、generate
|
||||
BackupURL string `bson:"backupUrl" json:"backupUrl"` // 备份URL
|
||||
CDNURL string `bson:"cdnUrl" json:"cdnUrl"` // CDN加速URL
|
||||
CompressInfo string `bson:"compressInfo" json:"compressInfo"` // 压缩信息(JSON格式)
|
||||
|
||||
// 平台兼容性
|
||||
SupportedPlatforms []string `bson:"supportedPlatforms" json:"supportedPlatforms"` // 支持的平台
|
||||
PlatformSpecific string `bson:"platformSpecific" json:"platformSpecific"` // 平台特定配置(JSON格式)
|
||||
|
||||
// 外部平台信息
|
||||
ExternalCreativeId string `bson:"externalCreativeId" json:"externalCreativeId"` // 外部创意ID
|
||||
PlatformId string `bson:"platformId" json:"platformId"` // 平台ID
|
||||
SyncStatus string `bson:"syncStatus" json:"syncStatus"` // 同步状态
|
||||
LastSyncTime int64 `bson:"lastSyncTime" json:"lastSyncTime"` // 最后同步时间
|
||||
|
||||
// 基础配置
|
||||
config.BaseConfig `bson:",inline" json:",inline"` // 内联基础配置
|
||||
|
||||
// 限制配置
|
||||
config.RestrictionConfig `bson:",inline" json:",inline"` // 内联限制配置
|
||||
|
||||
// 其他信息
|
||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、archived
|
||||
ExpireTime int64 `bson:"expireTime" json:"expireTime"` // 过期时间
|
||||
}
|
||||
|
||||
// GetCollectionName 获取集合名称
|
||||
func (a *AdCreative) GetCollectionName() string {
|
||||
return AdCreativeCollection
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"cid/model/config"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const AdPlatformCollection = "ad_platform"
|
||||
|
||||
// AdPlatform 广告平台实体
|
||||
type AdPlatform struct {
|
||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
||||
|
||||
// 平台基本信息
|
||||
Name string `bson:"name" json:"name"` // 平台名称:小红书、抖音、快手、京东、淘宝、百度等
|
||||
Code string `bson:"code" json:"code"` // 平台编码,唯一标识
|
||||
DisplayName string `bson:"displayName" json:"displayName"` // 显示名称
|
||||
Logo string `bson:"logo" json:"logo"` // 平台Logo
|
||||
Description string `bson:"description" json:"description"` // 平台描述
|
||||
Category string `bson:"category" json:"category"` // 平台分类:social、ecommerce、search、short_video等
|
||||
|
||||
// 支持的广告类型
|
||||
SupportedAdTypes []string `bson:"supportedAdTypes" json:"supportedAdTypes"` // 支持的广告类型
|
||||
SupportedFormats []string `bson:"supportedFormats" json:"supportedFormats"` // 支持的广告格式
|
||||
|
||||
// 技术能力
|
||||
RealTimeBidding bool `bson:"realTimeBidding" json:"realTimeBidding"` // 是否支持实时竞价
|
||||
ProgrammaticGuaranteed bool `bson:"programmaticGuaranteed" json:"programmaticGuaranteed"` // 是否支持程序化保障
|
||||
HeaderBidding bool `bson:"headerBidding" json:"headerBidding"` // 是否支持Header Bidding
|
||||
|
||||
// API配置
|
||||
config.APIConfig `bson:",inline" json:",inline"` // 内联API配置
|
||||
|
||||
// 竞价配置
|
||||
config.BiddingConfig `bson:",inline" json:",inline"` // 内联竞价配置
|
||||
|
||||
// 支付配置
|
||||
config.PaymentConfig `bson:",inline" json:",inline"` // 内联支付配置
|
||||
|
||||
// 限流配置
|
||||
RateLimit int64 `bson:"rateLimit" json:"rateLimit"` // 速率限制
|
||||
MaxBudgetPerDay int64 `bson:"maxBudgetPerDay" json:"maxBudgetPerDay"` // 每日最大预算
|
||||
|
||||
LastSyncTime int64 `bson:"lastSyncTime" json:"lastSyncTime"` // 最后同步时间
|
||||
|
||||
// 联系信息
|
||||
SupportContact string `bson:"supportContact" json:"supportContact"` // 技术支持联系方式
|
||||
AccountManager string `bson:"accountManager" json:"accountManager"` // 客户经理
|
||||
TechDocumentation string `bson:"techDocumentation" json:"techDocumentation"` // 技术文档链接
|
||||
}
|
||||
|
||||
// GetCollectionName 获取集合名称
|
||||
func (a *AdPlatform) GetCollectionName() string {
|
||||
return AdPlatformCollection
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"cid/model/config"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const AdPositionCollection = "ad_position"
|
||||
|
||||
// AdPosition 广告位实体
|
||||
type AdPosition struct {
|
||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
||||
|
||||
// 基本信息
|
||||
Name string `bson:"name" json:"name"` // 广告位名称
|
||||
Description string `bson:"description" json:"description"` // 广告位描述
|
||||
PositionCode string `bson:"positionCode" json:"positionCode"` // 广告位编码,用于标识
|
||||
AdFormat string `bson:"adFormat" json:"adFormat"` // 支持的广告格式
|
||||
|
||||
// 尺寸信息
|
||||
Width int64 `bson:"width" json:"width"` // 宽度(px)
|
||||
Height int64 `bson:"height" json:"height"` // 高度(px)
|
||||
|
||||
// 位置信息
|
||||
Page string `bson:"page" json:"page"` // 所属页面
|
||||
Section string `bson:"section" json:"section"` // 页面区域
|
||||
Location string `bson:"location" json:"location"` // 具体位置
|
||||
|
||||
// 展示设置
|
||||
MaxAds int `bson:"maxAds" json:"maxAds"` // 最大广告数量
|
||||
RefreshInterval int `bson:"refreshInterval" json:"refreshInterval"` // 刷新间隔(秒)
|
||||
IsLazyLoad bool `bson:"isLazyLoad" json:"isLazyLoad"` // 是否懒加载
|
||||
|
||||
// 定价设置
|
||||
PricingModel string `bson:"pricingModel" json:"pricingModel"` // 计费模型:CPC、CPM、CPA等
|
||||
BasePrice int64 `bson:"basePrice" json:"basePrice"` // 基础价格(分)
|
||||
FloorPrice int64 `bson:"floorPrice" json:"floorPrice"` // 底价(分)
|
||||
PriceUnit string `bson:"priceUnit" json:"priceUnit"` // 价格单位:千次展示、单次点击、单次转化等
|
||||
|
||||
// 展示规则
|
||||
DisplayRules *DisplayRules `bson:"displayRules" json:"displayRules"` // 展示规则
|
||||
|
||||
// 限制配置
|
||||
config.RestrictionConfig `bson:",inline" json:",inline"` // 内联限制配置
|
||||
|
||||
// 其他状态
|
||||
IsExclusive bool `bson:"isExclusive" json:"isExclusive"` // 是否独占广告位
|
||||
}
|
||||
|
||||
// DisplayRules 广告位展示规则
|
||||
type DisplayRules struct {
|
||||
// 频次控制
|
||||
FrequencyCap *FrequencyCap `bson:"frequencyCap" json:"frequencyCap"` // 频次控制
|
||||
|
||||
// 展示条件
|
||||
DisplayConditions []DisplayCondition `bson:"displayConditions" json:"displayConditions"` // 展示条件
|
||||
|
||||
// 排除条件
|
||||
ExcludeConditions []ExcludeCondition `bson:"excludeConditions" json:"excludeConditions"` // 排除条件
|
||||
}
|
||||
|
||||
// FrequencyCap 频次控制
|
||||
type FrequencyCap struct {
|
||||
Impressions int `bson:"impressions" json:"impressions"` // 展示次数
|
||||
TimeWindow int `bson:"timeWindow" json:"timeWindow"` // 时间窗口(小时)
|
||||
}
|
||||
|
||||
// DisplayCondition 展示条件
|
||||
type DisplayCondition struct {
|
||||
Type string `bson:"type" json:"type"` // 条件类型
|
||||
Value interface{} `bson:"value" json:"value"` // 条件值
|
||||
}
|
||||
|
||||
// ExcludeCondition 排除条件
|
||||
type ExcludeCondition struct {
|
||||
Type string `bson:"type" json:"type"` // 条件类型
|
||||
Value interface{} `bson:"value" json:"value"` // 条件值
|
||||
}
|
||||
|
||||
// GetCollectionName 获取集合名称
|
||||
func (a *AdPosition) GetCollectionName() string {
|
||||
return AdPositionCollection
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"cid/model/config"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const AdSourceCollection = "ad_source"
|
||||
|
||||
// AdSource 广告源实体
|
||||
type AdSource struct {
|
||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
||||
|
||||
// 基本信息
|
||||
Name string `bson:"name" json:"name"` // 广告源名称
|
||||
Code string `bson:"code" json:"code"` // 广告源编码,唯一标识
|
||||
Provider string `bson:"provider" json:"provider"` // 提供商:self(自营)、chuanshanjia(穿山甲)、gdt(腾讯广点通)、baidu(百度)、byteance(字节跳动)等
|
||||
Type string `bson:"type" json:"type"` // 类型:self(自营)、third_party(第三方)、exchange(广告交易平台)、platform_ad_source(平台广告源)
|
||||
Category string `bson:"category" json:"category"` // 分类:network、ssp、dsp、rtb等
|
||||
|
||||
// 连接配置
|
||||
Config string `bson:"config" json:"config"` // 广告源配置(JSON字符串)
|
||||
|
||||
// API配置
|
||||
config.APIConfig `bson:",inline" json:",inline"` // 内联API配置
|
||||
|
||||
// 创意配置
|
||||
config.CreativeConfig `bson:",inline" json:",inline"` // 内联创意配置
|
||||
|
||||
// 广告源能力
|
||||
Capabilities *AdSourceCapabilities `bson:"capabilities" json:"capabilities"` // 广告源能力
|
||||
|
||||
// 支付配置
|
||||
config.PaymentConfig `bson:",inline" json:",inline"` // 内联支付配置
|
||||
}
|
||||
|
||||
// AdSourceCapabilities 广告源能力
|
||||
type AdSourceCapabilities struct {
|
||||
// 广告格式
|
||||
SupportedFormats []AdFormat `bson:"supportedFormats" json:"supportedFormats"` // 支持的广告格式
|
||||
|
||||
// 功能特性
|
||||
RealTimeBidding bool `bson:"realTimeBidding" json:"realTimeBidding"` // 实时竞价
|
||||
HeaderBidding bool `bson:"headerBidding" json:"headerBidding"` // 标题竞价
|
||||
ProgrammaticDirect bool `bson:"programmaticDirect" json:"programmaticDirect"` // 程序化直购
|
||||
PrivateMarketplace bool `bson:"privateMarketplace" json:"privateMarketplace"` // 私有交易市场
|
||||
|
||||
// 质量控制
|
||||
FraudDetection bool `bson:"fraudDetection" json:"fraudDetection"` // 反欺诈检测
|
||||
BrandSafety bool `bson:"brandSafety" json:"brandSafety"` // 品牌安全
|
||||
Viewability bool `bson:"viewability" json:"viewability"` // 可见度验证
|
||||
CreativeApproval bool `bson:"creativeApproval" json:"creativeApproval"` // 创意审核
|
||||
|
||||
// 数据能力
|
||||
AudienceTargeting bool `bson:"audienceTargeting" json:"audienceTargeting"` // 受众定向
|
||||
ContextualTargeting bool `bson:"contextualTargeting" json:"contextualTargeting"` // 上下文定向
|
||||
CrossDeviceTargeting bool `bson:"crossDeviceTargeting" json:"crossDeviceTargeting"` // 跨设备定向
|
||||
}
|
||||
|
||||
// AdFormat 广告格式
|
||||
type AdFormat struct {
|
||||
Type string `bson:"type" json:"type"` // 格式类型:banner、video、native、interstitial等
|
||||
Name string `bson:"name" json:"name"` // 格式名称
|
||||
Width int `bson:"width" json:"width"` // 宽度
|
||||
Height int `bson:"height" json:"height"` // 高度
|
||||
MimeType string `bson:"mimeType" json:"mimeType"` // MIME类型
|
||||
}
|
||||
|
||||
// GetCollectionName 获取集合名称
|
||||
func (a *AdSource) GetCollectionName() string {
|
||||
return AdSourceCollection
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const AdTypeCollection = "ad_type"
|
||||
|
||||
// AdType 广告类型实体
|
||||
type AdType struct {
|
||||
beans.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"` // 备注
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"cid/model/config"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const AdvertisementCollection = "advertisement"
|
||||
|
||||
// Advertisement 广告实体
|
||||
type Advertisement struct {
|
||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
||||
AdvertiserId string `bson:"advertiserId" json:"advertiserId"` // 广告主ID
|
||||
|
||||
// 广告基本信息
|
||||
Title string `bson:"title" json:"title"` // 广告标题
|
||||
Description string `bson:"description" json:"description"` // 广告描述
|
||||
AdPositionId string `bson:"adPositionId" json:"adPositionId"` // 广告位ID
|
||||
AdType string `bson:"adType" json:"adType"` // 广告类型:图片、视频、文字等
|
||||
AdFormat string `bson:"adFormat" json:"adFormat"` // 广告格式
|
||||
MaterialUrl string `bson:"materialUrl" json:"materialUrl"` // 广告素材URL
|
||||
TargetUrl string `bson:"targetUrl" json:"targetUrl"` // 目标链接(点击跳转或落地页)
|
||||
|
||||
// 平台和广告源信息
|
||||
AdSourceId string `bson:"adSourceId" json:"adSourceId"` // 广告源ID
|
||||
AdPlatformId string `bson:"adPlatformId" json:"adPlatformId"` // 广告平台ID(当广告来自第三方平台时)
|
||||
ExternalAdId string `bson:"externalAdId" json:"externalAdId"` // 外部广告ID(第三方平台的广告ID)
|
||||
AdProvider string `bson:"adProvider" json:"adProvider"` // 广告提供者:self、chuanshanjia、xiaohongshu、douyin等
|
||||
|
||||
// 投放配置
|
||||
config.BudgetConfig `bson:",inline" json:",inline"` // 内联预算配置
|
||||
BidAmount int64 `bson:"bidAmount" json:"bidAmount"` // 出价(分)
|
||||
BillingType string `bson:"billingType" json:"billingType"` // 计费类型:CPC、CPM、CPA等
|
||||
|
||||
// 定向条件
|
||||
Targeting *UnifiedTargeting `bson:"targeting" json:"targeting"` // 统一定向条件
|
||||
|
||||
// 审核状态
|
||||
AuditStatus string `bson:"auditStatus" json:"auditStatus"` // 广告状态:待审核、审核中、已通过、已拒绝、投放中、已暂停、已结束
|
||||
AuditReason string `bson:"auditReason" json:"auditReason"` // 审核不通过原因
|
||||
AuditTime int64 `bson:"auditTime" json:"auditTime"` // 审核时间
|
||||
AuditBy string `bson:"auditBy" json:"auditBy"` // 审核人
|
||||
|
||||
// 限制配置
|
||||
config.RestrictionConfig `bson:",inline" json:",inline"` // 内联限制配置
|
||||
|
||||
// 其他状态信息
|
||||
Status string `bson:"status" json:"status"` // 业务状态:active、inactive、archived
|
||||
}
|
||||
|
||||
// GetCollectionName 获取集合名称
|
||||
func (a *Advertisement) GetCollectionName() string {
|
||||
return AdvertisementCollection
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const AdvertiserCollection = "advertiser"
|
||||
|
||||
// Advertiser 广告主实体
|
||||
type Advertiser struct {
|
||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
||||
|
||||
// 基本信息
|
||||
Name string `bson:"name" json:"name"` // 广告主名称
|
||||
ContactName string `bson:"contactName" json:"contactName"` // 联系人姓名
|
||||
ContactPhone string `bson:"contactPhone" json:"contactPhone"` // 联系电话
|
||||
ContactEmail string `bson:"contactEmail" json:"contactEmail"` // 联系邮箱
|
||||
Company string `bson:"company" json:"company"` // 公司名称
|
||||
Scale string `bson:"scale" json:"scale"` // 公司规模
|
||||
|
||||
// 证件信息
|
||||
BusinessLicenseUrl string `bson:"businessLicenseUrl" json:"businessLicenseUrl"` // 营业执照URL
|
||||
ICPLicenseUrl string `bson:"icpLicenseUrl" json:"icpLicenseUrl"` // ICP备案截图URL
|
||||
OtherLicenseUrls []string `bson:"otherLicenseUrls" json:"otherLicenseUrls"` // 其他证件URL
|
||||
|
||||
// 财务信息
|
||||
BankName string `bson:"bankName" json:"bankName"` // 开户银行
|
||||
BankAccount string `bson:"bankAccount" json:"bankAccount"` // 银行账号
|
||||
AccountName string `bson:"accountName" json:"accountName"` // 账户名称
|
||||
|
||||
// 合同信息
|
||||
ContractId string `bson:"contractId" json:"contractId"` // 合同编号
|
||||
ContractType string `bson:"contractType" json:"contractType"` // 合同类型
|
||||
ContractUrl string `bson:"contractUrl" json:"contractUrl"` // 合同文件URL
|
||||
SignDate int64 `bson:"signDate" json:"signDate"` // 签约日期
|
||||
ExpireDate int64 `bson:"expireDate" json:"expireDate"` // 到期日期
|
||||
|
||||
// 审核状态
|
||||
AuditStatus string `bson:"auditStatus" json:"auditStatus"` // 广告主状态:待审核、审核中、已通过、已拒绝、已冻结
|
||||
AuditReason string `bson:"auditReason" json:"auditReason"` // 审核不通过原因
|
||||
AuditTime int64 `bson:"auditTime" json:"auditTime"` // 审核时间
|
||||
AuditBy string `bson:"auditBy" json:"auditBy"` // 审核人
|
||||
|
||||
// 系统信息
|
||||
AccountBalance int64 `bson:"accountBalance" json:"accountBalance"` // 账户余额(分)
|
||||
CreditLimit int64 `bson:"creditLimit" json:"creditLimit"` // 授信额度(分)
|
||||
}
|
||||
|
||||
// GetCollectionName 获取集合名称
|
||||
func (a *Advertiser) GetCollectionName() string {
|
||||
return AdvertiserCollection
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
consts "cid/consts/app"
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
// Application 应用管理实体
|
||||
type Application struct {
|
||||
beans.SQLBaseDO `orm:",inherit"`
|
||||
// 基础信息
|
||||
Name string `orm:"name" json:"name" description:"应用名称"`
|
||||
AppCode string `orm:"app_code" json:"appCode" description:"应用编码(唯一标识)"`
|
||||
Type consts.AppType `orm:"type" json:"type" description:"应用类型"`
|
||||
Status consts.AppStatus `orm:"status" json:"status" description:"应用状态:active启用/inactive停用"`
|
||||
Description string `orm:"description" json:"description" description:"应用描述"`
|
||||
// 接入配置 (JSONB)
|
||||
AccessConfig map[string]interface{} `orm:"access_config" json:"accessConfig" description:"接入配置"`
|
||||
// 限流配置 (JSONB)
|
||||
LimitConfig map[string]interface{} `orm:"limit_config" json:"limitConfig" description:"限流配置"`
|
||||
// 回调配置 (JSONB)
|
||||
CallbackConfig map[string]interface{} `orm:"callback_config" json:"callbackConfig" description:"回调配置"`
|
||||
}
|
||||
|
||||
// ApplicationCol 应用表字段定义
|
||||
type ApplicationCol struct {
|
||||
beans.SQLBaseCol
|
||||
Name string
|
||||
AppCode string
|
||||
Type string
|
||||
Status string
|
||||
Description string
|
||||
AccessConfig string
|
||||
LimitConfig string
|
||||
CallbackConfig string
|
||||
}
|
||||
|
||||
// ApplicationCols 应用表字段常量
|
||||
var ApplicationCols = ApplicationCol{
|
||||
SQLBaseCol: beans.DefSQLBaseCol,
|
||||
Name: "name",
|
||||
AppCode: "app_code",
|
||||
Type: "type",
|
||||
Status: "status",
|
||||
Description: "description",
|
||||
AccessConfig: "access_config",
|
||||
LimitConfig: "limit_config",
|
||||
CallbackConfig: "callback_config",
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const AppPlatformConfigCollection = "app_platform_config"
|
||||
|
||||
// AppPlatformConfig 应用平台配置实体
|
||||
type AppPlatformConfig struct {
|
||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
||||
|
||||
// 关联信息
|
||||
AppID string `bson:"appId" json:"appId"` // 应用ID
|
||||
PlatformID string `bson:"platformId" json:"platformId"` // 平台ID
|
||||
|
||||
// 配置信息
|
||||
Config string `bson:"config" json:"config"` // 配置信息(JSON字符串)
|
||||
MaxAdsPerReq int `bson:"maxAdsPerReq" json:"maxAdsPerReq"` // 每次请求最大广告数
|
||||
|
||||
// 定向配置
|
||||
TargetingRules string `bson:"targetingRules" json:"targetingRules"` // 定向规则(JSON字符串)
|
||||
|
||||
// 过滤配置
|
||||
FilterRules string `bson:"filterRules" json:"filterRules"` // 过滤规则(JSON字符串)
|
||||
}
|
||||
|
||||
// GetCollectionName 获取集合名称
|
||||
func (a *AppPlatformConfig) GetCollectionName() string {
|
||||
return AppPlatformConfigCollection
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const ApplicationCollection = "application"
|
||||
|
||||
// Application 应用实体
|
||||
type Application struct {
|
||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
||||
|
||||
// 应用基本信息
|
||||
Name string `bson:"name" json:"name"` // 应用名称
|
||||
Code string `bson:"code" json:"code"` // 应用编码
|
||||
Description string `bson:"description" json:"description"` // 应用描述
|
||||
AppKey string `bson:"appKey" json:"appKey"` // 应用密钥
|
||||
AppSecret string `bson:"appSecret" json:"appSecret"` // 应用秘钥
|
||||
Platform string `bson:"platform" json:"platform"` // 平台:web、ios、android、h5
|
||||
Version string `bson:"version" json:"version"` // 版本号
|
||||
PackageName string `bson:"packageName" json:"packageName"` // 包名(移动应用)
|
||||
BundleID string `bson:"bundleId" json:"bundleId"` // Bundle ID(iOS应用)
|
||||
AppStoreURL string `bson:"appStoreUrl" json:"appStoreUrl"` // 应用商店URL
|
||||
|
||||
// 应用配置
|
||||
Config string `bson:"config" json:"config"` // 应用配置(JSON字符串)
|
||||
Permissions string `bson:"permissions" json:"permissions"` // 权限配置(JSON字符串)
|
||||
|
||||
// 应用分类和标签
|
||||
Categories []string `bson:"categories" json:"categories"` // 应用分类
|
||||
Tags []string `bson:"tags" json:"tags"` // 标签
|
||||
AdTypes []string `bson:"adTypes" json:"adTypes"` // 支持的广告类型
|
||||
|
||||
// 回调配置
|
||||
CallbackURL string `bson:"callbackUrl" json:"callbackUrl"` // 回调URL
|
||||
|
||||
// 应用特定统计
|
||||
DailyActiveUsers int64 `bson:"dailyActiveUsers" json:"dailyActiveUsers"` // 日活用户数
|
||||
MonthlyActiveUsers int64 `bson:"monthlyActiveUsers" json:"monthlyActiveUsers"` // 月活用户数
|
||||
TotalRequests int64 `bson:"totalRequests" json:"totalRequests"` // 总请求数
|
||||
DailyRequests int64 `bson:"dailyRequests" json:"dailyRequests"` // 日请求数
|
||||
MonthlyRequests int64 `bson:"monthlyRequests" json:"monthlyRequests"` // 月请求数
|
||||
|
||||
// 联系信息
|
||||
ContactName string `bson:"contactName" json:"contactName"` // 联系人姓名
|
||||
ContactEmail string `bson:"contactEmail" json:"contactEmail"` // 联系邮箱
|
||||
ContactPhone string `bson:"contactPhone" json:"contactPhone"` // 联系电话
|
||||
}
|
||||
|
||||
// GetCollectionName 获取集合名称
|
||||
func (a *Application) GetCollectionName() string {
|
||||
return ApplicationCollection
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const CidRequestCollection = "cid_request"
|
||||
|
||||
// CidRequest CID请求实体(合并后的统一版本)
|
||||
type CidRequest struct {
|
||||
beans.MongoBaseDO `bson:",inline" json:",inline"` // 嵌入基础字段:Id, Creator, CreatedAt, Updater, UpdatedAt, IsDeleted
|
||||
|
||||
// 请求基础信息
|
||||
RequestID string `bson:"requestId" json:"requestId"` // 请求唯一ID
|
||||
SessionID string `bson:"sessionId" json:"sessionId"` // 会话ID
|
||||
UserID string `bson:"userId" json:"userId"` // 用户ID
|
||||
|
||||
// 网络信息
|
||||
IPAddress string `bson:"ipAddress" json:"ipAddress"` // IP地址
|
||||
UserAgent string `bson:"userAgent" json:"userAgent"` // 用户代理
|
||||
Referer string `bson:"referer" json:"referer"` // 来源页面
|
||||
|
||||
// 广告位信息(使用内联结构)
|
||||
PositionCode string `bson:"positionCode" json:"positionCode"` // 广告位编码
|
||||
PositionSize string `bson:"positionSize" json:"positionSize"` // 广告位尺寸
|
||||
PositionFormat string `bson:"positionFormat" json:"positionFormat"` // 广告位格式
|
||||
PositionType string `bson:"positionType" json:"positionType"` // 广告位类型
|
||||
|
||||
// 页面信息
|
||||
PageURL string `bson:"pageUrl" json:"pageUrl"` // 页面URL
|
||||
PageTitle string `bson:"pageTitle" json:"pageTitle"` // 页面标题
|
||||
PageCategory string `bson:"pageCategory" json:"pageCategory"` // 页面分类
|
||||
PageKeywords []string `bson:"pageKeywords" json:"pageKeywords"` // 页面关键词
|
||||
PageTags map[string]string `bson:"pageTags" json:"pageTags"` // 页面标签
|
||||
|
||||
// 用户上下文信息(使用统一版本)
|
||||
UserContext *UnifiedUserContext `bson:"userContext" json:"userContext"` // 用户上下文
|
||||
DeviceInfo *DeviceInfo `bson:"deviceInfo" json:"deviceInfo"` // 设备信息
|
||||
LocationInfo *UnifiedLocationInfo `bson:"locationInfo" json:"locationInfo"` // 位置信息
|
||||
TemporalInfo *UnifiedTemporalInfo `bson:"temporalInfo" json:"temporalInfo"` // 时间信息
|
||||
|
||||
// 请求参数(使用合并版本)
|
||||
RequestParams *RequestParams `bson:"requestParams" json:"requestParams"` // 请求参数
|
||||
|
||||
// 定向规则(使用统一的定向结构)
|
||||
TargetingRules *UnifiedTargeting `bson:"targetingRules" json:"targetingRules"` // 定向规则
|
||||
|
||||
// 策略配置
|
||||
StrategyConfig *StrategyConfig `bson:"strategyConfig" json:"strategyConfig"` // 策略配置
|
||||
|
||||
// 响应信息
|
||||
Response *CidResponse `bson:"response" json:"response"` // 响应结果
|
||||
ProcessingTime int64 `bson:"processingTime" json:"processingTime"` // 处理时间(毫秒)
|
||||
ResponseTime int64 `bson:"responseTime" json:"responseTime"` // 响应时间(毫秒)
|
||||
|
||||
// 状态信息
|
||||
Status string `bson:"status" json:"status"` // 请求状态:pending、processing、completed、failed、timeout
|
||||
ErrorMessage string `bson:"errorMessage" json:"errorMessage"` // 错误信息
|
||||
ErrorCode string `bson:"errorCode" json:"errorCode"` // 错误代码
|
||||
|
||||
// 广告源信息
|
||||
RequestedAdSources []string `bson:"requestedAdSources" json:"requestedAdSources"` // 请求的广告源列表
|
||||
RespondedAdSources []string `bson:"respondedAdSources" json:"respondedAdSources"` // 响应的广告源列表
|
||||
AdSourceResponses map[string]*AdSourceResponse `bson:"adSourceResponses" json:"adSourceResponses"` // 各广告源响应
|
||||
|
||||
// 统计信息
|
||||
TotalAdsReturned int `bson:"totalAdsReturned" json:"totalAdsReturned"` // 返回的广告总数
|
||||
ValidAdsReturned int `bson:"validAdsReturned" json:"validAdsReturned"` // 有效广告数
|
||||
FilteredAds int `bson:"filteredAds" json:"filteredAds"` // 过滤的广告数
|
||||
DuplicateAds int `bson:"duplicateAds" json:"duplicateAds"` // 重复广告数
|
||||
|
||||
// 系统信息
|
||||
ServerInstance string `bson:"serverInstance" json:"serverInstance"` // 服务实例ID
|
||||
Region string `bson:"region" json:"region"` // 服务区域
|
||||
Version string `bson:"version" json:"version"` // 系统版本
|
||||
}
|
||||
|
||||
// GetCollectionName 获取集合名称
|
||||
func (c *CidRequest) GetCollectionName() string {
|
||||
return CidRequestCollection
|
||||
}
|
||||
|
||||
// UnifiedUserContext 统一的用户上下文
|
||||
type UnifiedUserContext struct {
|
||||
UserID string `bson:"userId" json:"userId"` // 用户ID
|
||||
SessionID string `bson:"sessionId" json:"sessionId"` // 会话ID
|
||||
CookieID string `bson:"cookieId" json:"cookieId"` // Cookie ID
|
||||
IP string `bson:"ip" json:"ip"` // IP地址
|
||||
UserAgent string `bson:"userAgent" json:"userAgent"` // 用户代理
|
||||
Language string `bson:"language" json:"language"` // 语言
|
||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
||||
CustomData map[string]interface{} `bson:"customData" json:"customData"` // 自定义数据
|
||||
}
|
||||
|
||||
// UnifiedLocationInfo 统一的位置信息
|
||||
type UnifiedLocationInfo struct {
|
||||
Country string `bson:"country" json:"country"` // 国家
|
||||
Region string `bson:"region" json:"region"` // 地区/省份
|
||||
City string `bson:"city" json:"city"` // 城市
|
||||
PostalCode string `bson:"postalCode" json:"postalCode"` // 邮政编码
|
||||
Latitude float64 `bson:"latitude" json:"latitude"` // 纬度
|
||||
Longitude float64 `bson:"longitude" json:"longitude"` // 经度
|
||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
||||
Metro string `bson:"metro" json:"metro"` // 都市区
|
||||
Area string `bson:"area" json:"area"` // 区域
|
||||
Network string `bson:"network" json:"network"` // 网络运营商
|
||||
ConnectionType string `bson:"connectionType" json:"connectionType"` // 连接类型
|
||||
ISP string `bson:"isp" json:"isp"` // 互联网服务提供商
|
||||
}
|
||||
|
||||
// UnifiedTemporalInfo 统一的时间信息
|
||||
type UnifiedTemporalInfo struct {
|
||||
Timestamp int64 `bson:"timestamp" json:"timestamp"` // 时间戳(秒)
|
||||
Milliseconds int64 `bson:"milliseconds" json:"milliseconds"` // 毫秒数
|
||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
||||
DayOfWeek int `bson:"dayOfWeek" json:"dayOfWeek"` // 星期几(0-6)
|
||||
HourOfDay int `bson:"hourOfDay" json:"hourOfDay"` // 小时(0-23)
|
||||
DayOfMonth int `bson:"dayOfMonth" json:"dayOfMonth"` // 月份中的天数
|
||||
Month int `bson:"month" json:"month"` // 月份(1-12)
|
||||
Year int `bson:"year" json:"year"` // 年份
|
||||
IsWeekend bool `bson:"isWeekend" json:"isWeekend"` // 是否周末
|
||||
IsBusinessHours bool `bson:"isBusinessHours" json:"isBusinessHours"` // 是否营业时间
|
||||
Season string `bson:"season" json:"season"` // 季节
|
||||
Holiday string `bson:"holiday" json:"holiday"` // 节假日
|
||||
}
|
||||
|
||||
// DeviceInfo 设备信息
|
||||
type DeviceInfo struct {
|
||||
Type string `bson:"type" json:"type"` // 设备类型:desktop、mobile、tablet
|
||||
Brand string `bson:"brand" json:"brand"` // 设备品牌
|
||||
Model string `bson:"model" json:"model"` // 设备型号
|
||||
OS string `bson:"os" json:"os"` // 操作系统
|
||||
OSVersion string `bson:"osVersion" json:"osVersion"` // 操作系统版本
|
||||
Browser string `bson:"browser" json:"browser"` // 浏览器
|
||||
BrowserVersion string `bson:"browserVersion" json:"browserVersion"` // 浏览器版本
|
||||
ScreenWidth int `bson:"screenWidth" json:"screenWidth"` // 屏幕宽度
|
||||
ScreenHeight int `bson:"screenHeight" json:"screenHeight"` // 屏幕高度
|
||||
ViewportWidth int `bson:"viewportWidth" json:"viewportWidth"` // 视口宽度
|
||||
ViewportHeight int `bson:"viewportHeight" json:"viewportHeight"` // 视口高度
|
||||
DPI int `bson:"dpi" json:"dpi"` // 设备DPI
|
||||
IsJavaScript bool `bson:"isJavaScript" json:"isJavaScript"` // 是否支持JavaScript
|
||||
IsCookie bool `bson:"isCookie" json:"isCookie"` // 是否支持Cookie
|
||||
IsFlash bool `bson:"isFlash" json:"isFlash"` // 是否支持Flash
|
||||
IsHTTPS bool `bson:"isHTTPS" json:"isHTTPS"` // 是否HTTPS连接
|
||||
}
|
||||
|
||||
// RequestParams 请求参数(合并版本)
|
||||
type RequestParams struct {
|
||||
AdCount int `bson:"adCount" json:"adCount"` // 请求的广告数量
|
||||
AdTypes []string `bson:"adTypes" json:"adTypes"` // 广告类型
|
||||
AdSizes []string `bson:"adSizes" json:"adSizes"` // 广告尺寸
|
||||
ExcludedAdSources []string `bson:"excludedAdSources" json:"excludedAdSources"` // 排除的广告源
|
||||
RequiredAdSources []string `bson:"requiredAdSources" json:"requiredAdSources"` // 必需的广告源
|
||||
MinBidAmount int64 `bson:"minBidAmount" json:"minBidAmount"` // 最小出价(分)
|
||||
MaxBidAmount int64 `bson:"maxBidAmount" json:"maxBidAmount"` // 最大出价(分)
|
||||
AllowDuplicates bool `bson:"allowDuplicates" json:"allowDuplicates"` // 是否允许重复广告
|
||||
FloorPrice int64 `bson:"floorPrice" json:"floorPrice"` // 底价(分)
|
||||
CeilingPrice int64 `bson:"ceilingPrice" json:"ceilingPrice"` // 封顶价(分)
|
||||
CustomParams map[string]interface{} `bson:"customParams" json:"customParams"` // 自定义参数
|
||||
}
|
||||
|
||||
// StrategyConfig 策略配置(合并版本)
|
||||
type StrategyConfig struct {
|
||||
StrategyType string `bson:"strategyType" json:"strategyType"` // 策略类型
|
||||
Priority int `bson:"priority" json:"priority"` // 优先级
|
||||
Weight float64 `bson:"weight" json:"weight"` // 权重
|
||||
MinAds int `bson:"minAds" json:"minAds"` // 最小广告数
|
||||
MaxAds int `bson:"maxAds" json:"maxAds"` // 最大广告数
|
||||
AllowDuplicates bool `bson:"allowDuplicates" json:"allowDuplicates"` // 是否允许重复
|
||||
Timeout int64 `bson:"timeout" json:"timeout"` // 超时时间(毫秒)
|
||||
RetryCount int `bson:"retryCount" json:"retryCount"` // 重试次数
|
||||
CustomSettings map[string]interface{} `bson:"customSettings" json:"customSettings"` // 自定义设置
|
||||
}
|
||||
|
||||
// CidResponse CID响应(合并版本)
|
||||
type CidResponse struct {
|
||||
Ads []Ad `bson:"ads" json:"ads"` // 广告列表
|
||||
TrackingInfo *TrackingInfo `bson:"trackingInfo" json:"trackingInfo"` // 跟踪信息
|
||||
Metadata *ResponseMetadata `bson:"metadata" json:"metadata"` // 响应元数据
|
||||
}
|
||||
|
||||
// Ad 广告结构(合并版本)
|
||||
type Ad struct {
|
||||
ID string `bson:"id" json:"id"` // 广告ID
|
||||
AdSource string `bson:"adSource" json:"adSource"` // 广告源
|
||||
Advertiser string `bson:"advertiser" json:"advertiser"` // 广告主
|
||||
Title string `bson:"title" json:"title"` // 广告标题
|
||||
Description string `bson:"description" json:"description"` // 广告描述
|
||||
CreativeURL string `bson:"creativeUrl" json:"creativeUrl"` // 创意URL
|
||||
LandingURL string `bson:"landingUrl" json:"landingUrl"` // 落地页URL
|
||||
DisplayURL string `bson:"displayUrl" json:"displayUrl"` // 显示URL
|
||||
AdType string `bson:"adType" json:"adType"` // 广告类型
|
||||
Format string `bson:"format" json:"format"` // 广告格式
|
||||
Width int `bson:"width" json:"width"` // 宽度
|
||||
Height int `bson:"height" json:"height"` // 高度
|
||||
MimeType string `bson:"mimeType" json:"mimeType"` // MIME类型
|
||||
BidAmount int64 `bson:"bidAmount" json:"bidAmount"` // 出价(分)
|
||||
Revenue int64 `bson:"revenue" json:"revenue"` // 预估收入(分)
|
||||
CTR float64 `bson:"ctr" json:"ctr"` // 点击率
|
||||
CVR float64 `bson:"cvr" json:"cvr"` // 转化率
|
||||
Targeting map[string]interface{} `bson:"targeting" json:"targeting"` // 定向条件
|
||||
Restrictions map[string]interface{} `bson:"restrictions" json:"restrictions"` // 限制条件
|
||||
TrackingPixels []string `bson:"trackingPixels" json:"trackingPixels"` // 跟踪像素
|
||||
CustomData map[string]interface{} `bson:"customData" json:"customData"` // 自定义数据
|
||||
ExpiresAt int64 `bson:"expiresAt" json:"expiresAt"` // 过期时间
|
||||
Priority int `bson:"priority" json:"priority"` // 优先级
|
||||
Score float64 `bson:"score" json:"score"` // 评分
|
||||
}
|
||||
|
||||
// TrackingInfo 跟踪信息(合并版本)
|
||||
type TrackingInfo struct {
|
||||
ImpressionURLs []string `bson:"impressionUrls" json:"impressionUrls"` // 展示跟踪URL
|
||||
ClickURLs []string `bson:"clickUrls" json:"clickUrls"` // 点击跟踪URL
|
||||
ConversionURLs []string `bson:"conversionUrls" json:"conversionUrls"` // 转化跟踪URL
|
||||
ViewThroughURLs []string `bson:"viewThroughUrls" json:"viewThroughUrls"` // 查看跟踪URL
|
||||
EventURLs map[string][]string `bson:"eventUrls" json:"eventUrls"` // 事件跟踪URL
|
||||
BeaconURLs []string `bson:"beaconUrls" json:"beaconUrls"` // 信标URL
|
||||
}
|
||||
|
||||
// ResponseMetadata 响应元数据(合并版本)
|
||||
type ResponseMetadata struct {
|
||||
TotalAvailableAds int `bson:"totalAvailableAds" json:"totalAvailableAds"` // 总可用广告数
|
||||
SelectedAds int `bson:"selectedAds" json:"selectedAds"` // 选择的广告数
|
||||
FilteredAds int `bson:"filteredAds" json:"filteredAds"` // 过滤的广告数
|
||||
DuplicateAds int `bson:"duplicateAds" json:"duplicateAds"` // 重复的广告数
|
||||
AverageBidAmount int64 `bson:"averageBidAmount" json:"averageBidAmount"` // 平均出价
|
||||
HighestBidAmount int64 `bson:"highestBidAmount" json:"highestBidAmount"` // 最高出价
|
||||
LowestBidAmount int64 `bson:"lowestBidAmount" json:"lowestBidAmount"` // 最低出价
|
||||
AverageCTR float64 `bson:"averageCTR" json:"averageCTR"` // 平均点击率
|
||||
AverageCVR float64 `bson:"averageCVR" json:"averageCVR"` // 平均转化率
|
||||
ResponseTime int64 `bson:"responseTime" json:"responseTime"` // 响应时间(毫秒)
|
||||
CacheHit bool `bson:"cacheHit" json:"cacheHit"` // 是否命中缓存
|
||||
StrategyUsed string `bson:"strategyUsed" json:"strategyUsed"` // 使用的策略
|
||||
AdSourcesUsed []string `bson:"adSourcesUsed" json:"adSourcesUsed"` // 使用的广告源
|
||||
}
|
||||
|
||||
// AdSourceResponse 广告源响应(合并版本)
|
||||
type AdSourceResponse struct {
|
||||
AdSource string `bson:"adSource" json:"adSource"` // 广告源名称
|
||||
Status string `bson:"status" json:"status"` // 响应状态:success、timeout、error
|
||||
ResponseTime int64 `bson:"responseTime" json:"responseTime"` // 响应时间(毫秒)
|
||||
AdsReturned int `bson:"adsReturned" json:"adsReturned"` // 返回的广告数
|
||||
AdsAccepted int `bson:"adsAccepted" json:"adsAccepted"` // 接受的广告数
|
||||
AdsFiltered int `bson:"adsFiltered" json:"adsFiltered"` // 过滤的广告数
|
||||
ErrorMessage string `bson:"errorMessage" json:"errorMessage"` // 错误信息
|
||||
ErrorCode string `bson:"errorCode" json:"errorCode"` // 错误代码
|
||||
RetryCount int `bson:"retryCount" json:"retryCount"` // 重试次数
|
||||
CacheHit bool `bson:"cacheHit" json:"cacheHit"` // 是否命中缓存
|
||||
TotalRevenue int64 `bson:"totalRevenue" json:"totalRevenue"` // 总收入(分)
|
||||
AverageBidAmount int64 `bson:"averageBidAmount" json:"averageBidAmount"` // 平均出价(分)
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
consts "cid/consts/data"
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
// ApiInterface 接口管理实体
|
||||
type ApiInterface struct {
|
||||
beans.SQLBaseDO `orm:",inherit"`
|
||||
// 基础信息
|
||||
PlatformId int64 `orm:"platform_id" json:"platformId" description:"所属平台ID"`
|
||||
Name string `orm:"name" json:"name" description:"接口名称"`
|
||||
Code string `orm:"code" json:"code" description:"接口编码"`
|
||||
Url string `orm:"url" json:"url" description:"接口地址"`
|
||||
Method consts.ApiMethod `orm:"method" json:"method" description:"请求方法:GET/POST/PUT/DELETE等"`
|
||||
Status consts.PlatformStatus `orm:"status" json:"status" description:"接口状态:active启用/inactive停用"`
|
||||
// 认证类型
|
||||
AuthType string `orm:"auth_type" json:"authType" description:"认证类型:oauth2/apikey/basic等"`
|
||||
// 请求配置 (JSONB)
|
||||
RequestConfig map[string]interface{} `orm:"request_config" json:"requestConfig" description:"请求配置"`
|
||||
// 响应配置 (JSONB)
|
||||
ResponseConfig map[string]interface{} `orm:"response_config" json:"responseConfig" description:"响应配置"`
|
||||
// 独立限流配置 (JSONB)
|
||||
LimitConfig map[string]interface{} `orm:"limit_config" json:"limitConfig" description:"接口独立限流配置(可选,覆盖平台配置)"`
|
||||
}
|
||||
|
||||
// ApiInterfaceCol 接口表字段定义
|
||||
type ApiInterfaceCol struct {
|
||||
beans.SQLBaseCol
|
||||
PlatformId string
|
||||
Name string
|
||||
Code string
|
||||
Url string
|
||||
Method string
|
||||
Status string
|
||||
AuthType string
|
||||
RequestConfig string
|
||||
ResponseConfig string
|
||||
LimitConfig string
|
||||
}
|
||||
|
||||
// ApiInterfaceCols 接口表字段常量
|
||||
var ApiInterfaceCols = ApiInterfaceCol{
|
||||
SQLBaseCol: beans.DefSQLBaseCol,
|
||||
PlatformId: "platform_id",
|
||||
Name: "name",
|
||||
Code: "code",
|
||||
Url: "url",
|
||||
Method: "method",
|
||||
Status: "status",
|
||||
AuthType: "auth_type",
|
||||
RequestConfig: "request_config",
|
||||
ResponseConfig: "response_config",
|
||||
LimitConfig: "limit_config",
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
consts "cid/consts/data"
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
// DataFetchLog 数据获取日志实体
|
||||
type DataFetchLog struct {
|
||||
beans.SQLBaseDO `orm:",inherit"`
|
||||
// 关联信息
|
||||
PlatformId int64 `orm:"platform_id" json:"platformId" description:"平台ID"`
|
||||
InterfaceId int64 `orm:"interface_id" json:"interfaceId" description:"接口ID"`
|
||||
RequestId string `orm:"request_id" json:"requestId" description:"请求ID"`
|
||||
// 执行状态
|
||||
Status consts.FetchStatus `orm:"status" json:"status" description:"执行状态:pending/running/success/failed/rate_limit"`
|
||||
StartTime int64 `orm:"start_time" json:"startTime" description:"开始时间(时间戳)"`
|
||||
EndTime int64 `orm:"end_time" json:"endTime" description:"结束时间(时间戳)"`
|
||||
Duration int `orm:"duration" json:"duration" description:"执行时长(毫秒)"`
|
||||
// 请求响应数据
|
||||
RequestConfig map[string]interface{} `orm:"request_config" json:"requestConfig" description:"请求配置参数"`
|
||||
ResponseData string `orm:"response_data" json:"responseData" description:"响应数据(JSON)"`
|
||||
ErrorMessage string `orm:"error_message" json:"errorMessage" description:"错误信息"`
|
||||
// 重试信息
|
||||
RetryCount int `orm:"retry_count" json:"retryCount" description:"重试次数"`
|
||||
}
|
||||
|
||||
// DataFetchLogCol 数据获取日志表字段定义
|
||||
type DataFetchLogCol struct {
|
||||
beans.SQLBaseCol
|
||||
PlatformId string
|
||||
InterfaceId string
|
||||
RequestId string
|
||||
Status string
|
||||
StartTime string
|
||||
EndTime string
|
||||
Duration string
|
||||
RequestConfig string
|
||||
ResponseData string
|
||||
ErrorMessage string
|
||||
RetryCount string
|
||||
}
|
||||
|
||||
// DataFetchLogCols 数据获取日志表字段常量
|
||||
var DataFetchLogCols = DataFetchLogCol{
|
||||
SQLBaseCol: beans.DefSQLBaseCol,
|
||||
PlatformId: "platform_id",
|
||||
InterfaceId: "interface_id",
|
||||
RequestId: "request_id",
|
||||
Status: "status",
|
||||
StartTime: "start_time",
|
||||
EndTime: "end_time",
|
||||
Duration: "duration",
|
||||
RequestConfig: "request_config",
|
||||
ResponseData: "response_data",
|
||||
ErrorMessage: "error_message",
|
||||
RetryCount: "retry_count",
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
consts "cid/consts/data"
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
// Platform 平台管理实体
|
||||
type Platform struct {
|
||||
beans.SQLBaseDO `orm:",inherit"`
|
||||
// 基础信息
|
||||
Name string `orm:"name" json:"name" description:"平台名称"`
|
||||
Type consts.SyncPlatform `orm:"type" json:"type" description:"平台类型"`
|
||||
Status consts.PlatformStatus `orm:"status" json:"status" description:"平台状态:active启用/inactive停用"`
|
||||
Description string `orm:"description" json:"description" description:"平台描述"`
|
||||
// 认证配置 (JSONB)
|
||||
AuthConfig map[string]interface{} `orm:"auth_config" json:"authConfig" description:"认证配置"`
|
||||
// 限流配置 (JSONB)
|
||||
LimitConfig map[string]interface{} `orm:"limit_config" json:"limitConfig" description:"限流配置"`
|
||||
// 平台专用配置 (JSONB)
|
||||
PlatformConfig map[string]interface{} `orm:"platform_config" json:"platformConfig" description:"平台专用配置"`
|
||||
}
|
||||
|
||||
// PlatformCol 平台表字段定义
|
||||
type PlatformCol struct {
|
||||
beans.SQLBaseCol
|
||||
Name string
|
||||
Type string
|
||||
Status string
|
||||
Description string
|
||||
AuthConfig string
|
||||
LimitConfig string
|
||||
PlatformConfig string
|
||||
}
|
||||
|
||||
// PlatformCols 平台表字段常量
|
||||
var PlatformCols = PlatformCol{
|
||||
SQLBaseCol: beans.DefSQLBaseCol,
|
||||
Name: "name",
|
||||
Type: "type",
|
||||
Status: "status",
|
||||
Description: "description",
|
||||
AuthConfig: "auth_config",
|
||||
LimitConfig: "limit_config",
|
||||
PlatformConfig: "platform_config",
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package mapping
|
||||
|
||||
import (
|
||||
"cid/consts/mapping"
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
// DataMapping 数据映射实体
|
||||
type DataMapping struct {
|
||||
beans.SQLBaseDO `orm:",inherit"`
|
||||
// 关联信息
|
||||
PlatformId int64 `orm:"platform_id" json:"platformId" description:"平台ID"`
|
||||
InterfaceId int64 `orm:"interface_id" json:"interfaceId" description:"接口ID"`
|
||||
// 映射规则
|
||||
SourceField string `orm:"source_field" json:"sourceField" description:"源字段(接口返回字段)"`
|
||||
TargetField string `orm:"target_field" json:"targetField" description:"目标字段(本地表字段)"`
|
||||
FieldType string `orm:"field_type" json:"fieldType" description:"字段类型:string/int/float/bool/array/object"`
|
||||
DefaultValue string `orm:"default_value" json:"defaultValue" description:"默认值"`
|
||||
// 转换规则 (JSONB)
|
||||
TransformRule map[string]interface{} `orm:"transform_rule" json:"transformRule" description:"转换规则"`
|
||||
// 优先级和状态
|
||||
Priority int `orm:"priority" json:"priority" description:"优先级(数字越小优先级越高)"`
|
||||
Status mapping.MappingStatus `orm:"status" json:"status" description:"状态:active启用/inactive停用"`
|
||||
}
|
||||
|
||||
// DataMappingCol 数据映射表字段定义
|
||||
type DataMappingCol struct {
|
||||
beans.SQLBaseCol
|
||||
PlatformId string
|
||||
InterfaceId string
|
||||
SourceField string
|
||||
TargetField string
|
||||
FieldType string
|
||||
DefaultValue string
|
||||
TransformRule string
|
||||
Priority string
|
||||
Status string
|
||||
}
|
||||
|
||||
// DataMappingCols 数据映射表字段常量
|
||||
var DataMappingCols = DataMappingCol{
|
||||
SQLBaseCol: beans.DefSQLBaseCol,
|
||||
PlatformId: "platform_id",
|
||||
InterfaceId: "interface_id",
|
||||
SourceField: "source_field",
|
||||
TargetField: "target_field",
|
||||
FieldType: "field_type",
|
||||
DefaultValue: "default_value",
|
||||
TransformRule: "transform_rule",
|
||||
Priority: "priority",
|
||||
Status: "status",
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"cid/model/config"
|
||||
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const PlatformDeliveryRuleCollection = "platform_delivery_rule"
|
||||
|
||||
// PlatformDeliveryRule 平台投放规则实体
|
||||
type PlatformDeliveryRule struct {
|
||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
||||
|
||||
// 关联信息
|
||||
AppID string `bson:"appId" json:"appId"` // 应用ID
|
||||
PlatformID string `bson:"platformId" json:"platformId"` // 平台ID
|
||||
|
||||
// 规则基本信息
|
||||
Name string `bson:"name" json:"name"` // 规则名称
|
||||
Description string `bson:"description" json:"description"` // 规则描述
|
||||
RuleType string `bson:"ruleType" json:"ruleType"` // 规则类型:budget、targeting、bidding、frequency等
|
||||
|
||||
// 预算配置
|
||||
config.BudgetConfig `bson:",inline" json:",inline"` // 内联预算配置
|
||||
|
||||
// 出价配置
|
||||
config.BiddingConfig `bson:",inline" json:",inline"` // 内联竞价配置
|
||||
|
||||
// 定向配置
|
||||
TargetingConfig string `bson:"targetingConfig" json:"targetingConfig"` // 定向配置(JSON格式)
|
||||
IncludeAudience []string `bson:"includeAudience" json:"includeAudience"` // 包含受众
|
||||
ExcludeAudience []string `bson:"excludeAudience" json:"excludeAudience"` // 排除受众
|
||||
|
||||
// 频次控制配置
|
||||
config.FrequencyCapConfig `bson:",inline" json:",inline"` // 内联频次控制配置
|
||||
|
||||
// 创意配置
|
||||
CreativeRotation string `bson:"creativeRotation" json:"creativeRotation"` // 创意轮播方式:optimize、even、random
|
||||
SelectedCreatives []string `bson:"selectedCreatives" json:"selectedCreatives"` // 选中的创意列表
|
||||
ExcludedCreatives []string `bson:"excludedCreatives" json:"excludedCreatives"` // 排除的创意列表
|
||||
|
||||
// 平台特定配置
|
||||
PlatformSpecific string `bson:"platformSpecific" json:"platformSpecific"` // 平台特定配置(JSON格式)
|
||||
|
||||
// 监控和告警
|
||||
PerformanceThresholds string `bson:"performanceThresholds" json:"performanceThresholds"` // 性能阈值(JSON格式)
|
||||
|
||||
// 自动优化配置
|
||||
IsAutoOptimize bool `bson:"isAutoOptimize" json:"isAutoOptimize"` // 是否自动优化
|
||||
LastOptimizeTime int64 `bson:"lastOptimizeTime" json:"lastOptimizeTime"` // 最后优化时间
|
||||
AutoOptimizeConfig string `bson:"autoOptimizeConfig" json:"autoOptimizeConfig"` // 自动优化配置(JSON格式)
|
||||
|
||||
// 执行统计
|
||||
ExecutionCount int64 `bson:"executionCount" json:"executionCount"` // 执行次数
|
||||
SuccessCount int64 `bson:"successCount" json:"successCount"` // 成功次数
|
||||
FailureCount int64 `bson:"failureCount" json:"failureCount"` // 失败次数
|
||||
LastExecutionTime int64 `bson:"lastExecutionTime" json:"lastExecutionTime"` // 最后执行时间
|
||||
NextExecutionTime int64 `bson:"nextExecutionTime" json:"nextExecutionTime"` // 下次执行时间
|
||||
|
||||
// 执行信息
|
||||
CreatedBy string `bson:"createdBy" json:"createdBy"` // 创建人
|
||||
LastModifiedBy string `bson:"lastModifiedBy" json:"lastModifiedBy"` // 最后修改人
|
||||
ModifiedReason string `bson:"modifiedReason" json:"modifiedReason"` // 修改原因
|
||||
}
|
||||
|
||||
// GetCollectionName 获取集合名称
|
||||
func (p *PlatformDeliveryRule) GetCollectionName() string {
|
||||
return PlatformDeliveryRuleCollection
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"gitea.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
const StrategyCollection = "strategy"
|
||||
|
||||
// Strategy 匹配策略表
|
||||
type Strategy struct {
|
||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
||||
|
||||
// 策略基本信息
|
||||
Name string `bson:"name" json:"name"` // 策略名称
|
||||
Description string `bson:"description" json:"description"` // 描述
|
||||
MinConversion float64 `bson:"minConversion" json:"minConversion"` // 最低转化率
|
||||
MaxConversion float64 `bson:"maxConversion" json:"maxConversion"` // 最高转化率
|
||||
SourceWeights string `bson:"sourceWeights" json:"sourceWeights"` // 广告源权重 (JSON格式)
|
||||
MaxAdsPerReq int `bson:"maxAdsPerReq" json:"maxAdsPerReq"` // 每次请求最大广告数
|
||||
MaxReqPerHour int `bson:"maxReqPerHour" json:"maxReqPerHour"` // 每小时最大请求次数
|
||||
Priority int `bson:"priority" json:"priority"` // 优先级(用于策略排序)
|
||||
}
|
||||
|
||||
// GetCollectionName 获取集合名称
|
||||
func (s *Strategy) GetCollectionName() string {
|
||||
return StrategyCollection
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package entity
|
||||
|
||||
// UnifiedTargeting 统一的定向条件
|
||||
type UnifiedTargeting struct {
|
||||
// 地理定向
|
||||
Countries []string `bson:"countries" json:"countries"` // 国家列表
|
||||
Regions []string `bson:"regions" json:"regions"` // 地区列表
|
||||
Cities []string `bson:"cities" json:"cities"` // 城市列表
|
||||
PostalCodes []string `bson:"postalCodes" json:"postalCodes"` // 邮政编码列表
|
||||
|
||||
// 人口统计定向
|
||||
AgeRange *UnifiedAgeRange `bson:"ageRange" json:"ageRange"` // 年龄范围
|
||||
Gender []string `bson:"gender" json:"gender"` // 性别
|
||||
Income []string `bson:"income" json:"income"` // 收入水平
|
||||
Education []string `bson:"education" json:"education"` // 教育程度
|
||||
Occupation []string `bson:"occupation" json:"occupation"` // 职业类型
|
||||
|
||||
// 兴趣定向
|
||||
Interests []string `bson:"interests" json:"interests"` // 兴趣标签
|
||||
Lifestyle []string `bson:"lifestyle" json:"lifestyle"` // 生活方式
|
||||
|
||||
// 行为定向
|
||||
SearchHistory []string `bson:"searchHistory" json:"searchHistory"` // 搜索历史
|
||||
BrowseHistory []string `bson:"browseHistory" json:"browseHistory"` // 浏览历史
|
||||
PurchaseHistory []string `bson:"purchaseHistory" json:"purchaseHistory"` // 购买历史
|
||||
AdInteractions []string `bson:"adInteractions" json:"adInteractions"` // 广告互动
|
||||
Behaviors []string `bson:"behaviors" json:"behaviors"` // 行为标签
|
||||
Segments []string `bson:"segments" json:"segments"` // 用户分群
|
||||
|
||||
// 上下文定向
|
||||
Categories []string `bson:"categories" json:"categories"` // 内容分类
|
||||
Keywords []string `bson:"keywords" json:"keywords"` // 关键词
|
||||
Tags []string `bson:"tags" json:"tags"` // 标签
|
||||
Sentiment string `bson:"sentiment" json:"sentiment"` // 情感倾向
|
||||
ContentType string `bson:"contentType" json:"contentType"` // 内容类型
|
||||
ContentRating string `bson:"contentRating" json:"contentRating"` // 内容评级
|
||||
|
||||
// 设备定向
|
||||
DeviceTypes []string `bson:"deviceTypes" json:"deviceTypes"` // 设备类型
|
||||
OS []string `bson:"os" json:"os"` // 操作系统
|
||||
Browsers []string `bson:"browsers" json:"browsers"` // 浏览器
|
||||
Carriers []string `bson:"carriers" json:"carriers"` // 运营商
|
||||
ConnectionTypes []string `bson:"connectionTypes" json:"connectionTypes"` // 连接类型
|
||||
|
||||
// 时间定向
|
||||
TimeSlots []UnifiedTimeSlot `bson:"timeSlots" json:"timeSlots"` // 时间段
|
||||
DaysOfWeek []int `bson:"daysOfWeek" json:"daysOfWeek"` // 星期几
|
||||
Dates []string `bson:"dates" json:"dates"` // 日期范围
|
||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
||||
ExcludeHolidays bool `bson:"excludeHolidays" json:"excludeHolidays"` // 排除节假日
|
||||
|
||||
// 扩展定向条件
|
||||
CustomTargeting map[string]interface{} `bson:"customTargeting" json:"customTargeting"` // 自定义定向
|
||||
}
|
||||
|
||||
// UnifiedAgeRange 统一的年龄范围
|
||||
type UnifiedAgeRange struct {
|
||||
Min int `bson:"min" json:"min"` // 最小年龄
|
||||
Max int `bson:"max" json:"max"` // 最大年龄
|
||||
}
|
||||
|
||||
// UnifiedTimeSlot 统一的时间段
|
||||
type UnifiedTimeSlot struct {
|
||||
DayOfWeek int `bson:"dayOfWeek" json:"dayOfWeek"` // 星期几:0-6,0表示星期日
|
||||
StartTime string `bson:"startTime" json:"startTime"` // 开始时间,格式:HH:mm
|
||||
EndTime string `bson:"endTime" json:"endTime"` // 结束时间,格式:HH:mm
|
||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cid/dao"
|
||||
"cid/model/dto"
|
||||
"cid/model/entity"
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
var AdPosition = new(adPosition)
|
||||
|
||||
type adPosition struct{}
|
||||
|
||||
// Add 添加广告位
|
||||
func (s *adPosition) Add(ctx context.Context, req *dto.AddAdPositionReq) (res *dto.AddAdPositionRes, err error) {
|
||||
ids, err := dao.AdPosition.Insert(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = &dto.AddAdPositionRes{Id: ids[0].(*bson.ObjectID)}
|
||||
return
|
||||
}
|
||||
|
||||
// Update 更新广告位
|
||||
func (s *adPosition) Update(ctx context.Context, req *dto.UpdateAdPositionReq) error {
|
||||
// 转换ID
|
||||
id, err := bson.ObjectIDFromHex(req.Id)
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "无效的ID格式")
|
||||
}
|
||||
|
||||
// 先获取原始广告位信息
|
||||
originalAdPosition, err := dao.AdPosition.GetOne(ctx, &id)
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "获取原始广告位信息失败")
|
||||
}
|
||||
|
||||
// 修改字段
|
||||
if !g.IsEmpty(req.Name) {
|
||||
originalAdPosition.Name = req.Name
|
||||
}
|
||||
if !g.IsEmpty(req.Description) {
|
||||
originalAdPosition.Description = req.Description
|
||||
}
|
||||
if !g.IsEmpty(req.PositionCode) {
|
||||
originalAdPosition.PositionCode = req.PositionCode
|
||||
}
|
||||
if !g.IsEmpty(req.AdFormat) {
|
||||
originalAdPosition.AdFormat = req.AdFormat
|
||||
}
|
||||
if req.Width != nil {
|
||||
originalAdPosition.Width = int64(*req.Width)
|
||||
}
|
||||
if req.Height != nil {
|
||||
originalAdPosition.Height = int64(*req.Height)
|
||||
}
|
||||
if !g.IsEmpty(req.Page) {
|
||||
originalAdPosition.Page = req.Page
|
||||
}
|
||||
if !g.IsEmpty(req.Section) {
|
||||
originalAdPosition.Section = req.Section
|
||||
}
|
||||
if !g.IsEmpty(req.Location) {
|
||||
originalAdPosition.Location = req.Location
|
||||
}
|
||||
if req.MaxAds != nil {
|
||||
originalAdPosition.MaxAds = *req.MaxAds
|
||||
}
|
||||
if req.RefreshInterval != nil {
|
||||
originalAdPosition.RefreshInterval = *req.RefreshInterval
|
||||
}
|
||||
if req.IsLazyLoad != nil {
|
||||
originalAdPosition.IsLazyLoad = *req.IsLazyLoad
|
||||
}
|
||||
if !g.IsEmpty(req.PricingModel) {
|
||||
originalAdPosition.PricingModel = req.PricingModel
|
||||
}
|
||||
if req.BasePrice != nil {
|
||||
originalAdPosition.BasePrice = *req.BasePrice
|
||||
}
|
||||
if req.FloorPrice != nil {
|
||||
originalAdPosition.FloorPrice = *req.FloorPrice
|
||||
}
|
||||
if !g.IsEmpty(req.PriceUnit) {
|
||||
originalAdPosition.PriceUnit = req.PriceUnit
|
||||
}
|
||||
if req.DisplayRules != nil {
|
||||
originalAdPosition.DisplayRules = req.DisplayRules
|
||||
}
|
||||
if req.Status != nil {
|
||||
originalAdPosition.Status = *req.Status
|
||||
}
|
||||
if req.IsExclusive != nil {
|
||||
originalAdPosition.IsExclusive = *req.IsExclusive
|
||||
}
|
||||
|
||||
return dao.AdPosition.Update(ctx, &id, originalAdPosition)
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告位状态
|
||||
func (s *adPosition) UpdateStatus(ctx context.Context, req *dto.UpdateAdPositionStatusReq) error {
|
||||
id, err := bson.ObjectIDFromHex(req.Id)
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "无效的ID格式")
|
||||
}
|
||||
return dao.AdPosition.UpdateStatus(ctx, &id, req.Status)
|
||||
}
|
||||
|
||||
// GetOne 获取广告位详情
|
||||
func (s *adPosition) GetOne(ctx context.Context, req *dto.GetAdPositionReq) (res *dto.GetAdPositionRes, err error) {
|
||||
id, err := bson.ObjectIDFromHex(req.Id)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "无效的ID格式")
|
||||
}
|
||||
|
||||
adPosition, err := dao.AdPosition.GetOne(ctx, &id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = &dto.GetAdPositionRes{
|
||||
AdPosition: adPosition,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取广告位列表
|
||||
func (s *adPosition) List(ctx context.Context, req *dto.ListAdPositionReq) (res *dto.ListAdPositionRes, err error) {
|
||||
list, total, err := dao.AdPosition.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = &dto.ListAdPositionRes{
|
||||
List: list,
|
||||
Total: int(total),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetAvailableAdPositions 获取可用的广告位列表
|
||||
func (s *adPosition) GetAvailableAdPositions(ctx context.Context) (list []*entity.AdPosition, err error) {
|
||||
return dao.AdPosition.GetAvailableAdPositions(ctx)
|
||||
}
|
||||
|
||||
// MatchAd 匹配广告
|
||||
func (s *adPosition) MatchAd(ctx context.Context, positionCode string, userInfo map[string]interface{}) (ad *entity.Advertisement, err error) {
|
||||
// 返回匹配的广告
|
||||
// 这里返回第一个广告作为示例
|
||||
ad = &entity.Advertisement{
|
||||
Title: "示例广告",
|
||||
MaterialUrl: "https://example.com/ad.jpg",
|
||||
TargetUrl: "https://example.com",
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateAdPositionStatistics 更新广告位统计
|
||||
func (s *adPosition) UpdateAdPositionStatistics(ctx context.Context, id string, impressions, clicks, revenue int64) (err error) {
|
||||
return
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cid/dao"
|
||||
"cid/model/config"
|
||||
"cid/model/dto"
|
||||
"cid/model/entity"
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
type adSource struct{}
|
||||
|
||||
// AdSource 广告源服务
|
||||
var AdSource = new(adSource)
|
||||
|
||||
// GetAvailableSources 获取可用的广告源列表
|
||||
func (s *adSource) GetAvailableSources(ctx context.Context) (list []*entity.AdSource, err error) {
|
||||
return dao.AdSource.GetAvailableSources(ctx)
|
||||
}
|
||||
|
||||
// GetSourcesByProvider 根据提供商获取广告源
|
||||
func (s *adSource) GetSourcesByProvider(ctx context.Context, provider string) (list []*entity.AdSource, err error) {
|
||||
return dao.AdSource.GetSourcesByProvider(ctx, provider)
|
||||
}
|
||||
|
||||
// CreateAdSource 创建广告源
|
||||
func (s *adSource) CreateAdSource(ctx context.Context, req *dto.CreateAdSourceReq) (id string, err error) {
|
||||
// 检查广告源名称是否已存在
|
||||
existingSource, err := dao.AdSource.GetByName(ctx, req.Name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if existingSource != nil {
|
||||
return "", gerror.New("广告源名称已存在")
|
||||
}
|
||||
|
||||
adSource := &entity.AdSource{
|
||||
Name: req.Name,
|
||||
Code: req.Code,
|
||||
Provider: req.Provider,
|
||||
Type: req.Type,
|
||||
APIConfig: config.APIConfig{
|
||||
Endpoint: req.APIEndpoint,
|
||||
},
|
||||
}
|
||||
|
||||
// 设置状态
|
||||
adSource.Status = "active" // 默认状态
|
||||
|
||||
return dao.AdSource.Create(ctx, adSource)
|
||||
}
|
||||
|
||||
// UpdateAdSource 更新广告源
|
||||
func (s *adSource) UpdateAdSource(ctx context.Context, id string, req *dto.UpdateAdSourceReq) (affected int64, err error) {
|
||||
|
||||
// 检查广告源是否存在
|
||||
existingSource, err := dao.AdSource.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingSource == nil {
|
||||
return 0, gerror.New("广告源不存在")
|
||||
}
|
||||
|
||||
// 如果更新名称,检查是否与其他广告源冲突
|
||||
if req.Name != "" && req.Name != existingSource.Name {
|
||||
conflictSource, err := dao.AdSource.GetByName(ctx, req.Name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if conflictSource != nil {
|
||||
return 0, gerror.New("广告源名称已存在")
|
||||
}
|
||||
}
|
||||
|
||||
// 构建更新数据
|
||||
updateData := &entity.AdSource{}
|
||||
if req.Name != "" {
|
||||
updateData.Name = req.Name
|
||||
}
|
||||
if req.APIEndpoint != "" {
|
||||
updateData.APIConfig.Endpoint = req.APIEndpoint
|
||||
}
|
||||
|
||||
return dao.AdSource.UpdateFields(ctx, id, updateData)
|
||||
}
|
||||
|
||||
// DeleteAdSource 删除广告源
|
||||
func (s *adSource) DeleteAdSource(ctx context.Context, id string) (affected int64, err error) {
|
||||
// 检查广告源是否存在
|
||||
existingSource, err := dao.AdSource.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingSource == nil {
|
||||
return 0, gerror.New("广告源不存在")
|
||||
}
|
||||
|
||||
return dao.AdSource.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// GetAdSourceByID 根据ID获取广告源
|
||||
func (s *adSource) GetAdSourceByID(ctx context.Context, id string) (adSource *entity.AdSource, err error) {
|
||||
return dao.AdSource.GetByID(ctx, id)
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cid/dao"
|
||||
"cid/model/dto"
|
||||
"cid/model/entity"
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var Advertisement = new(advertisement)
|
||||
|
||||
type advertisement struct{}
|
||||
|
||||
// Add 添加广告
|
||||
func (s *advertisement) Add(ctx context.Context, req *dto.AddAdvertisementReq) (res *dto.AddAdvertisementRes, err error) {
|
||||
advertisement := &entity.Advertisement{}
|
||||
if err = gconv.Struct(req, advertisement); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 设置初始状态
|
||||
advertisement.Status = "待审核"
|
||||
|
||||
// 注意:CreatedAt、UpdatedAt、TenantId、IsDeleted等字段由common/mongo的Insert方法自动设置
|
||||
if err = dao.Advertisement.Insert(ctx, advertisement); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = &dto.AddAdvertisementRes{Id: advertisement.Id.Hex()}
|
||||
return
|
||||
}
|
||||
|
||||
// Update 更新广告
|
||||
func (s *advertisement) Update(ctx context.Context, req *dto.UpdateAdvertisementReq) (err error) {
|
||||
// 更新修改时间(不需要设置,DAO层会处理)
|
||||
return dao.Advertisement.Update(ctx, req)
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告状态
|
||||
func (s *advertisement) UpdateStatus(ctx context.Context, req *dto.UpdateAdStatusReq) (err error) {
|
||||
return dao.Advertisement.UpdateStatus(ctx, req.Id, req.Status)
|
||||
}
|
||||
|
||||
// Audit 审核广告
|
||||
func (s *advertisement) Audit(ctx context.Context, req *dto.AuditAdvertisementReq) (err error) {
|
||||
return dao.Advertisement.Audit(ctx, req.Id, req.AuditStatus, req.AuditReason)
|
||||
}
|
||||
|
||||
// GetOne 获取广告详情
|
||||
func (s *advertisement) GetOne(ctx context.Context, req *dto.GetAdvertisementReq) (res *dto.GetAdvertisementRes, err error) {
|
||||
advertisement, err := dao.Advertisement.GetOne(ctx, req.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = &dto.GetAdvertisementRes{
|
||||
Advertisement: advertisement,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取广告列表
|
||||
func (s *advertisement) List(ctx context.Context, req *dto.ListAdvertisementReq) (res *dto.ListAdvertisementRes, err error) {
|
||||
list, total, err := dao.Advertisement.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = &dto.ListAdvertisementRes{
|
||||
List: list,
|
||||
Total: int(total),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateAdStatistics 更新广告统计
|
||||
func (s *advertisement) UpdateAdStatistics(ctx context.Context, id string, impressions, clicks, conversions int64, cost int64) (err error) {
|
||||
return
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"cid/dao"
|
||||
"cid/model/dto"
|
||||
"cid/model/entity"
|
||||
)
|
||||
|
||||
var Advertiser = new(advertiser)
|
||||
|
||||
type advertiser struct{}
|
||||
|
||||
// Add 添加广告主
|
||||
func (s *advertiser) Add(ctx context.Context, req *dto.AddAdvertiserReq) (res *dto.AddAdvertiserRes, err error) {
|
||||
advertiser := &entity.Advertiser{}
|
||||
if err = gconv.Struct(req, advertiser); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 设置初始状态
|
||||
advertiser.Status = "待审核"
|
||||
|
||||
// 注意:CreatedAt、UpdatedAt、TenantId、IsDeleted等字段由common/mongo的Insert方法自动设置
|
||||
if err = dao.Advertiser.Insert(ctx, advertiser); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = &dto.AddAdvertiserRes{Id: advertiser.Id.Hex()}
|
||||
return
|
||||
}
|
||||
|
||||
// Update 更新广告主
|
||||
func (s *advertiser) Update(ctx context.Context, req *dto.UpdateAdvertiserReq) (err error) {
|
||||
// 更新修改时间(不需要设置,DAO层会处理)
|
||||
return dao.Advertiser.Update(ctx, req)
|
||||
}
|
||||
|
||||
// UpdateStatus 更新广告主状态
|
||||
func (s *advertiser) UpdateStatus(ctx context.Context, req *dto.UpdateAdvertiserStatusReq) (err error) {
|
||||
return dao.Advertiser.UpdateStatus(ctx, req.Id, req.Status)
|
||||
}
|
||||
|
||||
// Audit 审核广告主
|
||||
func (s *advertiser) Audit(ctx context.Context, req *dto.AuditAdvertiserReq) (err error) {
|
||||
return dao.Advertiser.Audit(ctx, req.Id, req.AuditStatus, req.AuditReason)
|
||||
}
|
||||
|
||||
// Recharge 充值
|
||||
func (s *advertiser) Recharge(ctx context.Context, req *dto.RechargeAdvertiserReq) (err error) {
|
||||
// 验证金额
|
||||
if req.Amount <= 0 {
|
||||
return gerror.New("充值金额必须大于0")
|
||||
}
|
||||
|
||||
// 执行充值
|
||||
err = dao.Advertiser.Recharge(ctx, req.Id, req.Amount, req.Remark)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 记录充值流水(实际项目中可能需要创建充值记录表)
|
||||
// 这里简化处理
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateCreditLimit 更新授信额度
|
||||
func (s *advertiser) UpdateCreditLimit(ctx context.Context, req *dto.UpdateCreditLimitReq) (err error) {
|
||||
// 验证授信额度
|
||||
if req.CreditLimit < 0 {
|
||||
return gerror.New("授信额度不能为负数")
|
||||
}
|
||||
|
||||
// 更新授信额度
|
||||
err = dao.Advertiser.UpdateCreditLimit(ctx, req.Id, req.CreditLimit)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取广告主详情
|
||||
func (s *advertiser) GetOne(ctx context.Context, req *dto.GetAdvertiserReq) (res *dto.GetAdvertiserRes, err error) {
|
||||
advertiser, err := dao.Advertiser.GetOne(ctx, req.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = &dto.GetAdvertiserRes{
|
||||
Advertiser: advertiser,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取广告主列表
|
||||
func (s *advertiser) List(ctx context.Context, req *dto.ListAdvertiserReq) (res *dto.ListAdvertiserRes, err error) {
|
||||
list, total, err := dao.Advertiser.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = &dto.ListAdvertiserRes{
|
||||
List: list,
|
||||
Total: int(total),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetBalance 获取广告主余额
|
||||
func (s *advertiser) GetBalance(ctx context.Context, id string) (balance, creditLimit int64, err error) {
|
||||
advertiser, err := dao.Advertiser.GetOne(ctx, id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
balance = advertiser.AccountBalance
|
||||
creditLimit = advertiser.CreditLimit
|
||||
return
|
||||
}
|
||||
|
||||
// CheckBudget 检查广告主预算
|
||||
func (s *advertiser) CheckBudget(ctx context.Context, id string, cost int64) (hasEnoughBudget bool, err error) {
|
||||
advertiser, err := dao.Advertiser.GetOne(ctx, id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 可用金额 = 账户余额 + 授信额度 - 已消耗
|
||||
availableAmount := advertiser.AccountBalance + advertiser.CreditLimit
|
||||
|
||||
// 检查预算是否充足
|
||||
hasEnoughBudget = availableAmount >= cost
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DeductBudget 扣除预算
|
||||
func (s *advertiser) DeductBudget(ctx context.Context, id string, cost int64) (err error) {
|
||||
// 检查预算是否充足
|
||||
hasEnoughBudget, err := s.CheckBudget(ctx, id, cost)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !hasEnoughBudget {
|
||||
return gerror.New("预算不足")
|
||||
}
|
||||
|
||||
// 获取广告主信息
|
||||
advertiser, err := dao.Advertiser.GetOne(ctx, id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 计算新余额
|
||||
newBalance := advertiser.AccountBalance - cost
|
||||
|
||||
// 如果账户余额为负,从授信额度中扣除
|
||||
if newBalance < 0 {
|
||||
newCreditLimit := advertiser.CreditLimit + newBalance
|
||||
newBalance = 0
|
||||
|
||||
// 更新授信额度
|
||||
err = dao.Advertiser.UpdateCreditLimit(ctx, id, newCreditLimit)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 更新账户余额
|
||||
err = dao.Advertiser.Update(ctx, &dto.UpdateAdvertiserReq{
|
||||
Id: id,
|
||||
AccountBalance: &newBalance,
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
consts "cid/consts/app"
|
||||
dao "cid/dao/app"
|
||||
dto "cid/model/dto/app"
|
||||
entity "cid/model/entity/app"
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type applicationService struct{}
|
||||
|
||||
// Application 应用服务
|
||||
var Application = new(applicationService)
|
||||
|
||||
// Create 创建应用
|
||||
func (s *applicationService) Create(ctx context.Context, req *dto.CreateApplicationReq) (res *dto.CreateApplicationRes, err error) {
|
||||
// 检查应用名称是否重复
|
||||
count, err := dao.Application.Count(ctx, &dto.ListApplicationReq{Name: req.Name})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if count > 0 {
|
||||
return nil, errors.New("应用名称已存在")
|
||||
}
|
||||
|
||||
// 检查应用编码是否重复
|
||||
count, err = dao.Application.Count(ctx, &dto.ListApplicationReq{AppCode: req.AppCode})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if count > 0 {
|
||||
return nil, errors.New("应用编码已存在")
|
||||
}
|
||||
|
||||
// 插入数据库
|
||||
id, err := dao.Application.Insert(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.CreateApplicationRes{
|
||||
Id: id,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取应用列表
|
||||
func (s *applicationService) List(ctx context.Context, req *dto.ListApplicationReq) (res *dto.ListApplicationRes, err error) {
|
||||
applicationList, total, err := dao.Application.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 组装响应数据
|
||||
list := make([]dto.ApplicationItem, 0, len(applicationList))
|
||||
for _, item := range applicationList {
|
||||
list = append(list, dto.ApplicationItem{
|
||||
Id: item.Id,
|
||||
Name: item.Name,
|
||||
AppCode: item.AppCode,
|
||||
Type: item.Type,
|
||||
TypeName: s.getTypeName(item.Type),
|
||||
Status: item.Status,
|
||||
StatusName: s.getStatusName(item.Status),
|
||||
Description: item.Description,
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
UpdatedAt: item.UpdatedAt.Unix(),
|
||||
})
|
||||
}
|
||||
|
||||
res = &dto.ListApplicationRes{
|
||||
List: list,
|
||||
Total: total,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取单个应用
|
||||
func (s *applicationService) GetOne(ctx context.Context, req *dto.GetApplicationReq) (res *dto.GetApplicationRes, err error) {
|
||||
application, err := dao.Application.GetOne(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var applicationEntity *entity.Application
|
||||
if err = gconv.Struct(application, &applicationEntity); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return &dto.GetApplicationRes{
|
||||
Application: applicationEntity,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Update 更新应用
|
||||
func (s *applicationService) Update(ctx context.Context, req *dto.UpdateApplicationReq) (err error) {
|
||||
// 检查应用是否存在
|
||||
exist, err := dao.Application.GetOne(ctx, &dto.GetApplicationReq{Id: req.Id})
|
||||
if err != nil || exist == nil {
|
||||
return errors.New("应用不存在")
|
||||
}
|
||||
|
||||
// 如果修改了名称,检查新名称是否重复
|
||||
if req.Name != "" && req.Name != exist.Name {
|
||||
count, err := dao.Application.Count(ctx, &dto.ListApplicationReq{Name: req.Name})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("应用名称已存在")
|
||||
}
|
||||
}
|
||||
|
||||
// 如果修改了应用编码,检查新编码是否重复
|
||||
if req.AppCode != "" && req.AppCode != exist.AppCode {
|
||||
count, err := dao.Application.Count(ctx, &dto.ListApplicationReq{AppCode: req.AppCode})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("应用编码已存在")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = dao.Application.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新应用状态
|
||||
func (s *applicationService) UpdateStatus(ctx context.Context, req *dto.UpdateApplicationStatusReq) (err error) {
|
||||
_, err = dao.Application.UpdateStatus(ctx, req.Id, req.Status.String())
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除应用
|
||||
func (s *applicationService) Delete(ctx context.Context, req *dto.DeleteApplicationReq) (err error) {
|
||||
// TODO: 检查是否存在关联的数据,防止误删
|
||||
// 例如: 检查该应用是否有关联的广告活动等
|
||||
|
||||
_, err = dao.Application.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetByAppCode 根据应用编码获取应用
|
||||
func (s *applicationService) GetByAppCode(ctx context.Context, appCode string) (res *entity.Application, err error) {
|
||||
return dao.Application.GetByAppCode(ctx, appCode)
|
||||
}
|
||||
|
||||
// getTypeName 获取类型名称
|
||||
func (s *applicationService) getTypeName(appType consts.AppType) string {
|
||||
typeNames := map[consts.AppType]string{
|
||||
consts.AppTypeWeb: "Web应用",
|
||||
consts.AppTypeMobile: "移动应用",
|
||||
consts.AppTypeMiniApp: "小程序",
|
||||
consts.AppTypeH5: "H5应用",
|
||||
consts.AppTypeDesktop: "桌面应用",
|
||||
consts.AppTypeThirdParty: "第三方应用",
|
||||
}
|
||||
if name, ok := typeNames[appType]; ok {
|
||||
return name
|
||||
}
|
||||
return string(appType)
|
||||
}
|
||||
|
||||
// getStatusName 获取状态名称
|
||||
func (s *applicationService) getStatusName(status consts.AppStatus) string {
|
||||
statusNames := map[consts.AppStatus]string{
|
||||
consts.AppStatusActive: "启用",
|
||||
consts.AppStatusInactive: "停用",
|
||||
}
|
||||
if name, ok := statusNames[status]; ok {
|
||||
return name
|
||||
}
|
||||
return string(status)
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
|
||||
"cid/dao"
|
||||
"cid/model/dto"
|
||||
"cid/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
type application struct{}
|
||||
|
||||
// Application 应用服务
|
||||
var Application = new(application)
|
||||
|
||||
// CreateApplication 创建应用
|
||||
func (s *application) CreateApplication(ctx context.Context, req *dto.CreateApplicationReq) (id string, err error) {
|
||||
// 检查应用名称是否已存在
|
||||
existingApp, err := dao.Application.GetByName(ctx, req.Name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if existingApp != nil {
|
||||
return "", gerror.New("应用名称已存在")
|
||||
}
|
||||
|
||||
// 生成API密钥
|
||||
appKey, appSecret, err := s.generateAPIKeys()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
application := &entity.Application{
|
||||
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,
|
||||
AppKey: appKey,
|
||||
AppSecret: appSecret,
|
||||
CallbackURL: req.CallbackURL,
|
||||
}
|
||||
|
||||
// 设置状态
|
||||
application.Status = "active"
|
||||
|
||||
return dao.Application.Create(ctx, application)
|
||||
}
|
||||
|
||||
// UpdateApplication 更新应用
|
||||
func (s *application) UpdateApplication(ctx context.Context, id string, 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.Hex() != 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 *application) GetApplicationsByTenant(ctx context.Context, tenantID string, platform, status string, page, size int) (list []*entity.Application, total int64, err error) {
|
||||
// 调用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 *application) GetApplicationByKey(ctx context.Context, appKey string) (application *entity.Application, err error) {
|
||||
return dao.Application.GetByAPIKey(ctx, appKey)
|
||||
}
|
||||
|
||||
// GetApplicationByID 根据ID获取应用
|
||||
func (s *application) GetApplicationByID(ctx context.Context, id string) (application *entity.Application, err error) {
|
||||
return dao.Application.GetByID(ctx, id)
|
||||
}
|
||||
|
||||
// DeleteApplication 删除应用
|
||||
func (s *application) DeleteApplication(ctx context.Context, id string) (affected int64, err error) {
|
||||
err = dao.Application.Delete(ctx, id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
// ValidateApplication 验证应用权限
|
||||
func (s *application) 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 *application) 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 *application) ResetAPIKeys(ctx context.Context, id string) (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,377 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cid/dao"
|
||||
"cid/model/dto"
|
||||
"cid/model/entity"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"gitea.com/red-future/common/utils"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var (
|
||||
CID = cid{}
|
||||
)
|
||||
|
||||
type cid struct{}
|
||||
|
||||
// AdMatchingStrategy 广告匹配策略
|
||||
type AdMatchingStrategy struct {
|
||||
TenantLevel string // 租户级别
|
||||
MinConversion float64 // 最低转化率
|
||||
MaxConversion float64 // 最高转化率
|
||||
SourceWeight map[string]int // 广告源权重
|
||||
MaxAdsPerRequest int // 每次请求最大广告数
|
||||
}
|
||||
|
||||
// getMatchingStrategy 获取匹配策略
|
||||
func (s *cid) getMatchingStrategy(ctx context.Context, tenantLevel string) (*AdMatchingStrategy, error) {
|
||||
// 从数据库获取策略
|
||||
strategyEntity, err := Strategy.GetStrategyByTenantLevel(ctx, tenantLevel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if strategyEntity == nil {
|
||||
// 返回默认策略
|
||||
return &AdMatchingStrategy{
|
||||
TenantLevel: tenantLevel,
|
||||
MinConversion: 0.01,
|
||||
MaxConversion: 0.05,
|
||||
SourceWeight: map[string]int{"self": 100},
|
||||
MaxAdsPerRequest: 3,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 反序列化权重配置
|
||||
var sourceWeights map[string]int
|
||||
if strategyEntity.SourceWeights != "" {
|
||||
err = json.Unmarshal([]byte(strategyEntity.SourceWeights), &sourceWeights)
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "策略权重反序列化失败: %v", err)
|
||||
sourceWeights = map[string]int{"self": 100}
|
||||
}
|
||||
}
|
||||
|
||||
return &AdMatchingStrategy{
|
||||
TenantLevel: tenantLevel, // 使用传入的tenantLevel参数
|
||||
MinConversion: strategyEntity.MinConversion,
|
||||
MaxConversion: strategyEntity.MaxConversion,
|
||||
SourceWeight: sourceWeights,
|
||||
MaxAdsPerRequest: strategyEntity.MaxAdsPerReq,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GenerateCID 生成CID广告
|
||||
func (s *cid) GenerateCID(ctx context.Context, req *dto.GenerateCIDReq) (res *dto.GenerateCIDRes, err error) {
|
||||
// 获取当前用户信息
|
||||
userInfo, err := utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "获取用户信息失败")
|
||||
}
|
||||
|
||||
// 获取租户信息
|
||||
tenant, err := s.getTenantByUser(ctx, gconv.Int64(userInfo.UserName))
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "获取租户信息失败")
|
||||
}
|
||||
|
||||
// 检查租户请求次数限制
|
||||
// 将租户ID转换为int64用于限流检查
|
||||
tenantIdInt := int64(0)
|
||||
if tenant.Id != "" && tenant.Id != "default" {
|
||||
tryInt, _ := strconv.ParseInt(tenant.Id, 10, 64)
|
||||
tenantIdInt = tryInt
|
||||
}
|
||||
|
||||
allowed, err := RateLimit.CheckTenantRequestLimit(ctx, tenantIdInt, 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 {
|
||||
return nil, gerror.Wrap(err, "获取匹配策略失败")
|
||||
}
|
||||
|
||||
// 根据策略获取广告
|
||||
ads, err := s.matchAds(ctx, req, strategy)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "广告匹配失败")
|
||||
}
|
||||
|
||||
// 记录CID请求
|
||||
go s.recordCIDRequest(context.Background(), req, tenant, ads)
|
||||
|
||||
// 生成唯一CID
|
||||
cid := s.generateUniqueCID()
|
||||
|
||||
// 转换租户ID为int64(兼容性处理)
|
||||
// 这里直接使用之前已经声明的tenantIdInt变量,不需要重新声明
|
||||
if tenant.Id != "" && tenant.Id != "default" {
|
||||
// 这里简化处理,实际可能需要更复杂的转换逻辑
|
||||
tryInt, parseErr := strconv.ParseInt(tenant.Id, 10, 64)
|
||||
if parseErr == nil {
|
||||
tenantIdInt = tryInt
|
||||
}
|
||||
}
|
||||
|
||||
return &dto.GenerateCIDRes{
|
||||
CID: cid,
|
||||
Ads: ads,
|
||||
TotalAds: len(ads),
|
||||
TenantId: tenantIdInt,
|
||||
TenantName: tenant.Name,
|
||||
GeneratedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getTenantByUser 根据用户获取租户信息
|
||||
func (s *cid) getTenantByUser(ctx context.Context, userId int64) (*dto.TenantInfo, error) {
|
||||
// 通过common模块获取用户信息,包含租户ID
|
||||
userInfo, err := utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "获取用户信息失败")
|
||||
}
|
||||
|
||||
// 租户ID直接从用户信息中获取
|
||||
tenantId := ""
|
||||
if userInfo.TenantId != nil {
|
||||
if tenantIdStr, ok := userInfo.TenantId.(string); ok && tenantIdStr != "" {
|
||||
tenantId = tenantIdStr
|
||||
}
|
||||
} else {
|
||||
tenantId = "default" // 默认租户ID
|
||||
tenantId = "default" // 默认租户ID
|
||||
}
|
||||
|
||||
// 租户级别和名称可以根据租户ID通过其他方式获取或配置
|
||||
// 这里使用映射配置,实际项目中可能需要调用其他服务
|
||||
tenantName := "默认租户"
|
||||
tenantLevel := "basic"
|
||||
|
||||
// 根据租户ID设置不同的级别(示例逻辑)
|
||||
switch tenantId {
|
||||
case "default":
|
||||
tenantName = "基础租户"
|
||||
tenantLevel = "basic"
|
||||
case "standard":
|
||||
tenantName = "标准租户"
|
||||
tenantLevel = "standard"
|
||||
case "premium":
|
||||
tenantName = "高级租户"
|
||||
tenantLevel = "premium"
|
||||
default:
|
||||
// 如果租户ID不是预设值,使用租户ID作为名称
|
||||
tenantName = tenantId + "租户"
|
||||
tenantLevel = "basic"
|
||||
}
|
||||
|
||||
return &dto.TenantInfo{
|
||||
Id: tenantId,
|
||||
Name: tenantName,
|
||||
Level: tenantLevel,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// matchAds 根据策略匹配广告
|
||||
func (s *cid) matchAds(ctx context.Context, req *dto.GenerateCIDReq, strategy *AdMatchingStrategy) ([]*dto.AdInfo, error) {
|
||||
var matchedAds []*dto.AdInfo
|
||||
|
||||
// 根据策略权重从不同源获取广告
|
||||
for source, weight := range strategy.SourceWeight {
|
||||
if weight <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
sourceAds, err := s.getAdsFromSource(ctx, source, req, strategy, weight)
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "从广告源 %s 获取广告失败: %v", source, err)
|
||||
continue
|
||||
}
|
||||
|
||||
matchedAds = append(matchedAds, sourceAds...)
|
||||
}
|
||||
|
||||
// 过滤符合转化率要求的广告
|
||||
var filteredAds []*dto.AdInfo
|
||||
for _, ad := range matchedAds {
|
||||
if ad.ConversionRate >= strategy.MinConversion && ad.ConversionRate <= strategy.MaxConversion {
|
||||
filteredAds = append(filteredAds, ad)
|
||||
}
|
||||
}
|
||||
|
||||
// 限制广告数量
|
||||
if len(filteredAds) > strategy.MaxAdsPerRequest {
|
||||
rand.Shuffle(len(filteredAds), func(i, j int) {
|
||||
filteredAds[i], filteredAds[j] = filteredAds[j], filteredAds[i]
|
||||
})
|
||||
filteredAds = filteredAds[:strategy.MaxAdsPerRequest]
|
||||
}
|
||||
|
||||
return filteredAds, nil
|
||||
}
|
||||
|
||||
// getAdsFromSource 从指定广告源获取广告
|
||||
func (s *cid) getAdsFromSource(ctx context.Context, source string, req *dto.GenerateCIDReq, strategy *AdMatchingStrategy, weight int) ([]*dto.AdInfo, error) {
|
||||
switch source {
|
||||
case "self":
|
||||
return s.getSelfServiceAds(ctx, req, weight)
|
||||
case "google":
|
||||
return s.getGoogleAds(ctx, req, weight)
|
||||
case "facebook":
|
||||
return s.getFacebookAds(ctx, req, weight)
|
||||
default:
|
||||
return nil, gerror.Newf("不支持的广告源: %s", source)
|
||||
}
|
||||
}
|
||||
|
||||
// getSelfServiceAds 获取自营广告
|
||||
func (s *cid) getSelfServiceAds(ctx context.Context, req *dto.GenerateCIDReq, count int) ([]*dto.AdInfo, error) {
|
||||
// 这里应该从数据库查询自营广告
|
||||
// 暂时返回模拟数据
|
||||
ads := make([]*dto.AdInfo, 0)
|
||||
for i := 0; i < count; i++ {
|
||||
ads = append(ads, &dto.AdInfo{
|
||||
Id: int64(rand.Intn(89999) + 10000),
|
||||
Title: fmt.Sprintf("自营广告 %d", i+1),
|
||||
Description: "这是一个高质量的自营广告",
|
||||
ImageUrl: "https://example.com/ad.jpg",
|
||||
TargetUrl: "https://example.com/landing",
|
||||
ConversionRate: rand.Float64(),
|
||||
Source: "self",
|
||||
Bid: rand.Intn(901) + 100,
|
||||
})
|
||||
}
|
||||
return ads, nil
|
||||
}
|
||||
|
||||
// getGoogleAds 获取Google广告
|
||||
func (s *cid) getGoogleAds(ctx context.Context, req *dto.GenerateCIDReq, count int) ([]*dto.AdInfo, error) {
|
||||
// 这里应该调用Google Ads API
|
||||
// 暂时返回模拟数据
|
||||
ads := make([]*dto.AdInfo, 0)
|
||||
for i := 0; i < count; i++ {
|
||||
ads = append(ads, &dto.AdInfo{
|
||||
Id: int64(rand.Intn(9999) + 20000),
|
||||
Title: fmt.Sprintf("Google广告 %d", i+1),
|
||||
Description: "来自Google的高质量广告",
|
||||
ImageUrl: "https://google.com/ad.jpg",
|
||||
TargetUrl: "https://google.com/landing",
|
||||
ConversionRate: rand.Float64()*0.3 + 0.1,
|
||||
Source: "google",
|
||||
Bid: rand.Intn(1301) + 200,
|
||||
})
|
||||
}
|
||||
return ads, nil
|
||||
}
|
||||
|
||||
// getFacebookAds 获取Facebook广告
|
||||
func (s *cid) getFacebookAds(ctx context.Context, req *dto.GenerateCIDReq, count int) ([]*dto.AdInfo, error) {
|
||||
// 这里应该调用Facebook Ads API
|
||||
// 暂时返回模拟数据
|
||||
ads := make([]*dto.AdInfo, 0)
|
||||
for i := 0; i < count; i++ {
|
||||
ads = append(ads, &dto.AdInfo{
|
||||
Id: int64(rand.Intn(9999) + 30000),
|
||||
Title: fmt.Sprintf("Facebook广告 %d", i+1),
|
||||
Description: "来自Facebook的高质量广告",
|
||||
ImageUrl: "https://facebook.com/ad.jpg",
|
||||
TargetUrl: "https://facebook.com/landing",
|
||||
ConversionRate: rand.Float64()*0.25 + 0.08,
|
||||
Source: "facebook",
|
||||
Bid: rand.Intn(1051) + 150,
|
||||
})
|
||||
}
|
||||
return ads, nil
|
||||
}
|
||||
|
||||
// generateUniqueCID 生成唯一CID
|
||||
func (s *cid) generateUniqueCID() string {
|
||||
timestamp := time.Now().Unix()
|
||||
random := rand.Intn(8999) + 1000
|
||||
return fmt.Sprintf("CID_%d_%d", timestamp, random)
|
||||
}
|
||||
|
||||
// recordCIDRequest 记录CID请求
|
||||
func (s *cid) recordCIDRequest(ctx context.Context, req *dto.GenerateCIDReq, tenant *dto.TenantInfo, ads []*dto.AdInfo) {
|
||||
// 转换dto.AdInfo到entity.Ad
|
||||
var entityAds []entity.Ad
|
||||
for _, ad := range ads {
|
||||
entityAds = append(entityAds, entity.Ad{
|
||||
ID: fmt.Sprintf("%d", ad.Id),
|
||||
AdSource: ad.Source,
|
||||
Title: ad.Title,
|
||||
Description: ad.Description,
|
||||
CreativeURL: ad.ImageUrl,
|
||||
LandingURL: ad.TargetUrl,
|
||||
BidAmount: int64(ad.Bid),
|
||||
})
|
||||
}
|
||||
|
||||
request := &entity.CidRequest{
|
||||
RequestID: fmt.Sprintf("REQ_%d_%d", time.Now().Unix(), rand.Intn(10000)),
|
||||
UserID: fmt.Sprintf("%d", req.UserId),
|
||||
Response: &entity.CidResponse{
|
||||
Ads: entityAds,
|
||||
},
|
||||
ProcessingTime: int64(rand.Intn(401) + 100), // 模拟处理时间
|
||||
}
|
||||
|
||||
_, err := dao.CIDRequest.Create(ctx, request)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "记录CID请求失败: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetCIDHistory 获取CID请求历史
|
||||
func (s *cid) GetCIDHistory(ctx context.Context, userId int64, page, size int) (res *dto.GetCIDHistoryRes, err error) {
|
||||
history, total, err := dao.CIDRequest.GetHistory(ctx, strconv.FormatInt(userId, 10), page, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var historyList []*dto.CIDRequestHistory
|
||||
for _, record := range history {
|
||||
// 解析TenantID
|
||||
tenantId := int64(0)
|
||||
if tenantIdStr, ok := record.TenantId.(string); ok && tenantIdStr != "" {
|
||||
tenantId, _ = strconv.ParseInt(tenantIdStr, 10, 64)
|
||||
}
|
||||
|
||||
// 解析UserID
|
||||
uid := int64(0)
|
||||
if record.UserID != "" {
|
||||
uid, _ = strconv.ParseInt(record.UserID, 10, 64)
|
||||
}
|
||||
|
||||
historyList = append(historyList, &dto.CIDRequestHistory{
|
||||
Id: 0, // 使用默认值,因为entity使用的是ObjectID
|
||||
TenantId: tenantId,
|
||||
UserId: uid,
|
||||
RequestType: "CID", // 默认值
|
||||
Status: "completed", // 从response状态获取
|
||||
ProcessTime: int(record.ProcessingTime),
|
||||
CreatedAt: record.CreatedAt.String(),
|
||||
})
|
||||
}
|
||||
|
||||
return &dto.GetCIDHistoryRes{
|
||||
List: historyList,
|
||||
Total: total,
|
||||
Page: page,
|
||||
Size: size,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
consts "cid/consts/data"
|
||||
dao "cid/dao/data"
|
||||
dto "cid/model/dto/data"
|
||||
entity "cid/model/entity/data"
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type apiInterfaceService struct{}
|
||||
|
||||
// ApiInterface 接口服务
|
||||
var ApiInterface = new(apiInterfaceService)
|
||||
|
||||
// Create 创建接口
|
||||
func (s *apiInterfaceService) Create(ctx context.Context, req *dto.CreateApiInterfaceReq) (res *dto.CreateApiInterfaceRes, err error) {
|
||||
// 检查平台是否存在
|
||||
_, err = dao.Platform.GetOne(ctx, &dto.GetPlatformReq{Id: req.PlatformId})
|
||||
if err != nil {
|
||||
return nil, errors.New("平台不存在")
|
||||
}
|
||||
|
||||
// 检查接口编码在同一平台下是否重复
|
||||
interfaces, _, err := dao.ApiInterface.List(ctx, &dto.ListApiInterfaceReq{
|
||||
PlatformId: req.PlatformId,
|
||||
Code: req.Code,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(interfaces) > 0 {
|
||||
return nil, errors.New("接口编码在该平台下已存在")
|
||||
}
|
||||
|
||||
// 插入数据库
|
||||
id, err := dao.ApiInterface.Insert(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.CreateApiInterfaceRes{
|
||||
Id: id,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取接口列表
|
||||
func (s *apiInterfaceService) List(ctx context.Context, req *dto.ListApiInterfaceReq) (res *dto.ListApiInterfaceRes, err error) {
|
||||
apiList, total, err := dao.ApiInterface.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取平台ID列表用于批量查询
|
||||
platformIds := make([]int64, 0)
|
||||
for _, item := range apiList {
|
||||
if item.PlatformId > 0 {
|
||||
platformIds = append(platformIds, item.PlatformId)
|
||||
}
|
||||
}
|
||||
|
||||
// 批量获取平台信息
|
||||
platformMap := make(map[int64]string)
|
||||
if len(platformIds) > 0 {
|
||||
platforms, _, err := dao.Platform.List(ctx, &dto.ListPlatformReq{})
|
||||
if err == nil {
|
||||
for _, p := range platforms {
|
||||
platformMap[p.Id] = p.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 组装响应数据
|
||||
list := make([]dto.ApiInterfaceItem, 0, len(apiList))
|
||||
for _, item := range apiList {
|
||||
platformName := ""
|
||||
if name, ok := platformMap[item.PlatformId]; ok {
|
||||
platformName = name
|
||||
}
|
||||
|
||||
list = append(list, dto.ApiInterfaceItem{
|
||||
Id: item.Id,
|
||||
PlatformId: item.PlatformId,
|
||||
PlatformName: platformName,
|
||||
Name: item.Name,
|
||||
Code: item.Code,
|
||||
Url: item.Url,
|
||||
Method: item.Method,
|
||||
Status: item.Status,
|
||||
StatusName: s.getStatusName(item.Status),
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
UpdatedAt: item.UpdatedAt.Unix(),
|
||||
})
|
||||
}
|
||||
|
||||
res = &dto.ListApiInterfaceRes{
|
||||
List: list,
|
||||
Total: total,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取单个接口
|
||||
func (s *apiInterfaceService) GetOne(ctx context.Context, req *dto.GetApiInterfaceReq) (res *dto.GetApiInterfaceRes, err error) {
|
||||
apiInterface, err := dao.ApiInterface.GetOne(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取平台名称
|
||||
var platformName string
|
||||
if apiInterface.PlatformId > 0 {
|
||||
platform, _ := dao.Platform.GetOne(ctx, &dto.GetPlatformReq{Id: apiInterface.PlatformId})
|
||||
if platform != nil {
|
||||
platformName = platform.Name
|
||||
}
|
||||
}
|
||||
|
||||
return &dto.GetApiInterfaceRes{
|
||||
ApiInterface: apiInterface,
|
||||
PlatformName: platformName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Update 更新接口
|
||||
func (s *apiInterfaceService) Update(ctx context.Context, req *dto.UpdateApiInterfaceReq) (err error) {
|
||||
// 检查接口是否存在
|
||||
exist, err := dao.ApiInterface.GetOne(ctx, &dto.GetApiInterfaceReq{Id: req.Id})
|
||||
if err != nil || exist == nil {
|
||||
return errors.New("接口不存在")
|
||||
}
|
||||
|
||||
// 如果修改了平台,检查平台是否存在
|
||||
if req.PlatformId > 0 && req.PlatformId != exist.PlatformId {
|
||||
_, err := dao.Platform.GetOne(ctx, &dto.GetPlatformReq{Id: req.PlatformId})
|
||||
if err != nil {
|
||||
return errors.New("平台不存在")
|
||||
}
|
||||
}
|
||||
|
||||
// 如果修改了编码,检查编码是否重复
|
||||
if req.Code != "" && req.Code != exist.Code {
|
||||
platformId := req.PlatformId
|
||||
if platformId == 0 {
|
||||
platformId = exist.PlatformId
|
||||
}
|
||||
interfaces, _, err := dao.ApiInterface.List(ctx, &dto.ListApiInterfaceReq{
|
||||
PlatformId: platformId,
|
||||
Code: req.Code,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(interfaces) > 0 {
|
||||
return errors.New("接口编码在该平台下已存在")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = dao.ApiInterface.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新接口状态
|
||||
func (s *apiInterfaceService) UpdateStatus(ctx context.Context, req *dto.UpdateApiInterfaceStatusReq) (err error) {
|
||||
_, err = dao.ApiInterface.UpdateStatus(ctx, req.Id, req.Status.String())
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除接口
|
||||
func (s *apiInterfaceService) Delete(ctx context.Context, req *dto.DeleteApiInterfaceReq) (err error) {
|
||||
_, err = dao.ApiInterface.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetByIds 根据ID列表获取接口
|
||||
func (s *apiInterfaceService) GetByIds(ctx context.Context, ids []int64) (res []entity.ApiInterface, err error) {
|
||||
return dao.ApiInterface.GetByIds(ctx, ids)
|
||||
}
|
||||
|
||||
// getStatusName 获取状态名称
|
||||
func (s *apiInterfaceService) getStatusName(status consts.PlatformStatus) string {
|
||||
statusNames := map[consts.PlatformStatus]string{
|
||||
consts.PlatformStatusActive: "启用",
|
||||
consts.PlatformStatusInactive: "停用",
|
||||
}
|
||||
if name, ok := statusNames[status]; ok {
|
||||
return name
|
||||
}
|
||||
return string(status)
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
consts "cid/consts/data"
|
||||
dao "cid/dao/data"
|
||||
dto "cid/model/dto/data"
|
||||
entity "cid/model/entity/data"
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/grpool"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
)
|
||||
|
||||
type dataFetchService struct{}
|
||||
|
||||
// DataFetch 数据获取服务
|
||||
var DataFetch = new(dataFetchService)
|
||||
|
||||
// FetchPool 数据获取协程池,限制并发数避免goroutine爆炸
|
||||
var FetchPool = grpool.New(10)
|
||||
|
||||
// Execute 执行数据获取
|
||||
func (s *dataFetchService) Execute(ctx context.Context, req *dto.ExecuteDataFetchReq) (res *dto.ExecuteDataFetchRes, err error) {
|
||||
// 检查接口是否存在
|
||||
apiInterface, err := dao.ApiInterface.GetOne(ctx, &dto.GetApiInterfaceReq{Id: req.InterfaceId})
|
||||
if err != nil || apiInterface == nil {
|
||||
return nil, fmt.Errorf("接口不存在")
|
||||
}
|
||||
|
||||
// 检查接口状态
|
||||
if apiInterface.Status != consts.PlatformStatusActive {
|
||||
return nil, fmt.Errorf("接口未启用")
|
||||
}
|
||||
|
||||
// 检查平台是否存在
|
||||
platform, err := dao.Platform.GetOne(ctx, &dto.GetPlatformReq{Id: apiInterface.PlatformId})
|
||||
if err != nil || platform == nil {
|
||||
return nil, fmt.Errorf("平台不存在")
|
||||
}
|
||||
|
||||
// 检查平台状态
|
||||
if platform.Status != consts.PlatformStatusActive {
|
||||
return nil, fmt.Errorf("平台未启用")
|
||||
}
|
||||
|
||||
// 生成请求ID
|
||||
requestId := guid.S()
|
||||
startTime := time.Now().UnixMilli()
|
||||
|
||||
// 创建数据获取日志
|
||||
fetchLog := &entity.DataFetchLog{
|
||||
PlatformId: req.PlatformId,
|
||||
InterfaceId: req.InterfaceId,
|
||||
RequestId: requestId,
|
||||
Status: consts.FetchStatusPending,
|
||||
StartTime: startTime,
|
||||
RequestConfig: req.RequestParams,
|
||||
RetryCount: 0,
|
||||
}
|
||||
|
||||
logId, err := dao.DataFetchLog.Insert(ctx, fetchLog)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建日志失败: %v", err)
|
||||
}
|
||||
|
||||
// 使用协程池异步执行数据获取
|
||||
asyncCtx := context.WithoutCancel(ctx)
|
||||
FetchPool.Add(asyncCtx, func(ctx context.Context) {
|
||||
s.executeFetch(ctx, logId, requestId, platform, apiInterface, req.RequestParams, startTime)
|
||||
})
|
||||
|
||||
return &dto.ExecuteDataFetchRes{
|
||||
RequestId: requestId,
|
||||
Status: string(consts.FetchStatusPending),
|
||||
Message: "任务已提交",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BatchExecute 批量执行数据获取
|
||||
func (s *dataFetchService) BatchExecute(ctx context.Context, req *dto.BatchExecuteDataFetchReq) (res *dto.BatchExecuteDataFetchRes, err error) {
|
||||
var requestIds []string
|
||||
successCount := 0
|
||||
failedCount := 0
|
||||
|
||||
for _, interfaceId := range req.InterfaceIds {
|
||||
executeReq := &dto.ExecuteDataFetchReq{
|
||||
PlatformId: 0, // 接口服务会自动获取
|
||||
InterfaceId: interfaceId,
|
||||
RequestParams: req.RequestParams,
|
||||
}
|
||||
|
||||
executeRes, err := s.Execute(ctx, executeReq)
|
||||
if err != nil {
|
||||
failedCount++
|
||||
g.Log().Error(ctx, "批量执行失败", g.Map{
|
||||
"interfaceId": interfaceId,
|
||||
"error": err.Error(),
|
||||
})
|
||||
} else {
|
||||
successCount++
|
||||
requestIds = append(requestIds, executeRes.RequestId)
|
||||
}
|
||||
}
|
||||
|
||||
return &dto.BatchExecuteDataFetchRes{
|
||||
SuccessCount: successCount,
|
||||
FailedCount: failedCount,
|
||||
RequestIds: requestIds,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// List 获取数据获取日志列表
|
||||
func (s *dataFetchService) List(ctx context.Context, req *dto.ListDataFetchLogReq) (res *dto.ListDataFetchLogRes, err error) {
|
||||
logList, total, err := dao.DataFetchLog.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取平台和接口ID列表
|
||||
platformIds := make([]int64, 0)
|
||||
interfaceIds := make([]int64, 0)
|
||||
for _, item := range logList {
|
||||
if item.PlatformId > 0 {
|
||||
platformIds = append(platformIds, item.PlatformId)
|
||||
}
|
||||
if item.InterfaceId > 0 {
|
||||
interfaceIds = append(interfaceIds, item.InterfaceId)
|
||||
}
|
||||
}
|
||||
|
||||
// 批量获取平台和接口信息
|
||||
platformMap := make(map[int64]string)
|
||||
interfaceMap := make(map[int64]string)
|
||||
if len(platformIds) > 0 {
|
||||
platforms, _, err := dao.Platform.List(ctx, &dto.ListPlatformReq{})
|
||||
if err == nil {
|
||||
for _, p := range platforms {
|
||||
platformMap[p.Id] = p.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(interfaceIds) > 0 {
|
||||
interfaces, _, err := dao.ApiInterface.List(ctx, &dto.ListApiInterfaceReq{})
|
||||
if err == nil {
|
||||
for _, i := range interfaces {
|
||||
interfaceMap[i.Id] = i.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 组装响应数据
|
||||
list := make([]dto.DataFetchLogItem, 0, len(logList))
|
||||
for _, item := range logList {
|
||||
platformName := ""
|
||||
if name, ok := platformMap[item.PlatformId]; ok {
|
||||
platformName = name
|
||||
}
|
||||
interfaceName := ""
|
||||
if name, ok := interfaceMap[item.InterfaceId]; ok {
|
||||
interfaceName = name
|
||||
}
|
||||
|
||||
list = append(list, dto.DataFetchLogItem{
|
||||
Id: item.Id,
|
||||
PlatformId: item.PlatformId,
|
||||
PlatformName: platformName,
|
||||
InterfaceId: item.InterfaceId,
|
||||
InterfaceName: interfaceName,
|
||||
RequestId: item.RequestId,
|
||||
Status: item.Status,
|
||||
StatusName: s.getStatusName(item.Status),
|
||||
StartTime: item.StartTime,
|
||||
EndTime: item.EndTime,
|
||||
Duration: item.Duration,
|
||||
ErrorMessage: item.ErrorMessage,
|
||||
RetryCount: item.RetryCount,
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
})
|
||||
}
|
||||
|
||||
res = &dto.ListDataFetchLogRes{
|
||||
List: list,
|
||||
Total: total,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取单个数据获取日志
|
||||
func (s *dataFetchService) GetOne(ctx context.Context, req *dto.GetDataFetchLogReq) (res *dto.GetDataFetchLogRes, err error) {
|
||||
fetchLog, err := dao.DataFetchLog.GetOne(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取平台和接口名称
|
||||
var platformName, interfaceName string
|
||||
if fetchLog.PlatformId > 0 {
|
||||
platform, _ := dao.Platform.GetOne(ctx, &dto.GetPlatformReq{Id: fetchLog.PlatformId})
|
||||
if platform != nil {
|
||||
platformName = platform.Name
|
||||
}
|
||||
}
|
||||
if fetchLog.InterfaceId > 0 {
|
||||
apiInterface, _ := dao.ApiInterface.GetOne(ctx, &dto.GetApiInterfaceReq{Id: fetchLog.InterfaceId})
|
||||
if apiInterface != nil {
|
||||
interfaceName = apiInterface.Name
|
||||
}
|
||||
}
|
||||
|
||||
return &dto.GetDataFetchLogRes{
|
||||
DataFetchLog: fetchLog,
|
||||
PlatformName: platformName,
|
||||
InterfaceName: interfaceName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ReExecute 重新执行数据获取
|
||||
func (s *dataFetchService) ReExecute(ctx context.Context, req *dto.ReExecuteDataFetchReq) (res *dto.ReExecuteDataFetchRes, err error) {
|
||||
// 获取原日志
|
||||
oldLog, err := dao.DataFetchLog.GetOne(ctx, &dto.GetDataFetchLogReq{Id: req.LogId})
|
||||
if err != nil || oldLog == nil {
|
||||
return nil, fmt.Errorf("日志不存在")
|
||||
}
|
||||
|
||||
// 检查接口是否存在
|
||||
apiInterface, err := dao.ApiInterface.GetOne(ctx, &dto.GetApiInterfaceReq{Id: oldLog.InterfaceId})
|
||||
if err != nil || apiInterface == nil {
|
||||
return nil, fmt.Errorf("接口不存在")
|
||||
}
|
||||
|
||||
// 检查平台是否存在
|
||||
platform, err := dao.Platform.GetOne(ctx, &dto.GetPlatformReq{Id: apiInterface.PlatformId})
|
||||
if err != nil || platform == nil {
|
||||
return nil, fmt.Errorf("平台不存在")
|
||||
}
|
||||
|
||||
// 生成新的请求ID
|
||||
requestId := guid.S()
|
||||
startTime := time.Now().UnixMilli()
|
||||
|
||||
// 创建新的数据获取日志
|
||||
fetchLog := &entity.DataFetchLog{
|
||||
PlatformId: oldLog.PlatformId,
|
||||
InterfaceId: oldLog.InterfaceId,
|
||||
RequestId: requestId,
|
||||
Status: consts.FetchStatusPending,
|
||||
StartTime: startTime,
|
||||
RequestConfig: oldLog.RequestConfig,
|
||||
RetryCount: oldLog.RetryCount + 1,
|
||||
}
|
||||
|
||||
logId, err := dao.DataFetchLog.Insert(ctx, fetchLog)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建日志失败: %v", err)
|
||||
}
|
||||
|
||||
// 使用协程池异步执行数据获取
|
||||
asyncCtx := context.WithoutCancel(ctx)
|
||||
FetchPool.Add(asyncCtx, func(ctx context.Context) {
|
||||
s.executeFetch(ctx, logId, requestId, platform, apiInterface, oldLog.RequestConfig, startTime)
|
||||
})
|
||||
|
||||
return &dto.ReExecuteDataFetchRes{
|
||||
RequestId: requestId,
|
||||
Status: string(consts.FetchStatusPending),
|
||||
Message: "任务已重新提交",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// executeFetch 执行实际的数据获取(在协程池中运行)
|
||||
func (s *dataFetchService) executeFetch(ctx context.Context, logId int64, requestId string, platform *entity.Platform, apiInterface *entity.ApiInterface, requestParams map[string]interface{}, startTime int64) {
|
||||
// 更新状态为执行中
|
||||
dao.DataFetchLog.UpdateStatus(ctx, logId, string(consts.FetchStatusRunning), 0, 0, "", "")
|
||||
|
||||
// TODO: 根据平台和接口配置执行HTTP请求
|
||||
// 这里需要根据平台的限流配置进行限流控制
|
||||
// 根据接口的请求配置组装请求参数
|
||||
// 调用接口获取数据
|
||||
|
||||
// 模拟接口调用
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
// 模拟成功响应
|
||||
responseData := `{"code": 0, "message": "success", "data": {"items": []}}`
|
||||
endTime := time.Now().UnixMilli()
|
||||
duration := int(endTime - startTime)
|
||||
|
||||
// 更新状态为成功
|
||||
dao.DataFetchLog.UpdateStatus(ctx, logId, string(consts.FetchStatusSuccess), endTime, duration, responseData, "")
|
||||
|
||||
g.Log().Info(ctx, "数据获取成功", g.Map{
|
||||
"logId": logId,
|
||||
"requestId": requestId,
|
||||
"platform": platform.Name,
|
||||
"interface": apiInterface.Name,
|
||||
"duration": duration,
|
||||
})
|
||||
}
|
||||
|
||||
// getStatusName 获取状态名称
|
||||
func (s *dataFetchService) getStatusName(status consts.FetchStatus) string {
|
||||
statusNames := map[consts.FetchStatus]string{
|
||||
consts.FetchStatusPending: "待执行",
|
||||
consts.FetchStatusRunning: "执行中",
|
||||
consts.FetchStatusSuccess: "成功",
|
||||
consts.FetchStatusFailed: "失败",
|
||||
consts.FetchStatusRateLimit: "触发限流",
|
||||
}
|
||||
if name, ok := statusNames[status]; ok {
|
||||
return name
|
||||
}
|
||||
return string(status)
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
consts "cid/consts/data"
|
||||
dao "cid/dao/data"
|
||||
dto "cid/model/dto/data"
|
||||
entity "cid/model/entity/data"
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type platformService struct{}
|
||||
|
||||
// Platform 平台服务
|
||||
var Platform = new(platformService)
|
||||
|
||||
// Create 创建平台
|
||||
func (s *platformService) Create(ctx context.Context, req *dto.CreatePlatformReq) (res *dto.CreatePlatformRes, err error) {
|
||||
// 检查平台名称是否重复
|
||||
count, err := dao.Platform.Count(ctx, &dto.ListPlatformReq{Name: req.Name})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if count > 0 {
|
||||
return nil, errors.New("平台名称已存在")
|
||||
}
|
||||
|
||||
// 检查平台类型是否重复
|
||||
count, err = dao.Platform.Count(ctx, &dto.ListPlatformReq{Type: req.Type})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if count > 0 {
|
||||
return nil, errors.New("该类型平台已存在")
|
||||
}
|
||||
|
||||
// 插入数据库
|
||||
id, err := dao.Platform.Insert(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.CreatePlatformRes{
|
||||
Id: id,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取平台列表
|
||||
func (s *platformService) List(ctx context.Context, req *dto.ListPlatformReq) (res *dto.ListPlatformRes, err error) {
|
||||
platformList, total, err := dao.Platform.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 组装响应数据
|
||||
list := make([]dto.PlatformItem, 0, len(platformList))
|
||||
for _, item := range platformList {
|
||||
list = append(list, dto.PlatformItem{
|
||||
Id: item.Id,
|
||||
Name: item.Name,
|
||||
Type: item.Type,
|
||||
TypeName: s.getTypeName(item.Type),
|
||||
Status: item.Status,
|
||||
StatusName: s.getStatusName(item.Status),
|
||||
Description: item.Description,
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
UpdatedAt: item.UpdatedAt.Unix(),
|
||||
})
|
||||
}
|
||||
|
||||
res = &dto.ListPlatformRes{
|
||||
List: list,
|
||||
Total: total,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取单个平台
|
||||
func (s *platformService) GetOne(ctx context.Context, req *dto.GetPlatformReq) (res *dto.GetPlatformRes, err error) {
|
||||
platform, err := dao.Platform.GetOne(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var platformEntity *entity.Platform
|
||||
if err = gconv.Struct(platform, &platformEntity); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return &dto.GetPlatformRes{
|
||||
Platform: platformEntity,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Update 更新平台
|
||||
func (s *platformService) Update(ctx context.Context, req *dto.UpdatePlatformReq) (err error) {
|
||||
// 检查平台是否存在
|
||||
exist, err := dao.Platform.GetOne(ctx, &dto.GetPlatformReq{Id: req.Id})
|
||||
if err != nil || exist == nil {
|
||||
return errors.New("平台不存在")
|
||||
}
|
||||
|
||||
// 如果修改了名称,检查新名称是否重复
|
||||
if req.Name != "" && req.Name != exist.Name {
|
||||
count, err := dao.Platform.Count(ctx, &dto.ListPlatformReq{Name: req.Name})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("平台名称已存在")
|
||||
}
|
||||
}
|
||||
|
||||
// 如果修改了类型,检查新类型是否重复
|
||||
if req.Type != "" && req.Type != exist.Type {
|
||||
count, err := dao.Platform.Count(ctx, &dto.ListPlatformReq{Type: req.Type})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.New("该类型平台已存在")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = dao.Platform.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus 更新平台状态
|
||||
func (s *platformService) UpdateStatus(ctx context.Context, req *dto.UpdatePlatformStatusReq) (err error) {
|
||||
_, err = dao.Platform.UpdateStatus(ctx, req.Id, req.Status.String())
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除平台
|
||||
func (s *platformService) Delete(ctx context.Context, req *dto.DeletePlatformReq) (err error) {
|
||||
// 检查是否存在关联的接口
|
||||
interfaces, _, err := dao.ApiInterface.List(ctx, &dto.ListApiInterfaceReq{
|
||||
PlatformId: req.Id,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(interfaces) > 0 {
|
||||
return errors.New("该平台下存在接口,无法删除")
|
||||
}
|
||||
|
||||
_, err = dao.Platform.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetByType 根据类型获取平台
|
||||
func (s *platformService) GetByType(ctx context.Context, platformType consts.SyncPlatform) (res *entity.Platform, err error) {
|
||||
return dao.Platform.GetByType(ctx, platformType.String())
|
||||
}
|
||||
|
||||
// getTypeName 获取类型名称
|
||||
func (s *platformService) getTypeName(platformType consts.SyncPlatform) string {
|
||||
typeNames := map[consts.SyncPlatform]string{
|
||||
consts.PlatformTaobao: "淘宝",
|
||||
consts.PlatformJD: "京东",
|
||||
consts.PlatformKuaishou: "快手",
|
||||
consts.PlatformDouyin: "抖音",
|
||||
consts.PlatformXhs: "小红书",
|
||||
consts.PlatformPdd: "拼多多",
|
||||
consts.PlatformXianyu: "闲鱼",
|
||||
consts.PlatformTmall: "天猫",
|
||||
consts.PlatformWechat: "微信",
|
||||
consts.PlatformCustom: "自定义",
|
||||
}
|
||||
if name, ok := typeNames[platformType]; ok {
|
||||
return name
|
||||
}
|
||||
return string(platformType)
|
||||
}
|
||||
|
||||
// getStatusName 获取状态名称
|
||||
func (s *platformService) getStatusName(status consts.PlatformStatus) string {
|
||||
statusNames := map[consts.PlatformStatus]string{
|
||||
consts.PlatformStatusActive: "启用",
|
||||
consts.PlatformStatusInactive: "停用",
|
||||
}
|
||||
if name, ok := statusNames[status]; ok {
|
||||
return name
|
||||
}
|
||||
return string(status)
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
package mapping
|
||||
|
||||
import (
|
||||
consts "cid/consts/mapping"
|
||||
dao "cid/dao/mapping"
|
||||
dto "cid/model/dto/mapping"
|
||||
entity "cid/model/entity/mapping"
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type dataMappingService struct{}
|
||||
|
||||
// DataMapping 数据映射服务
|
||||
var DataMapping = new(dataMappingService)
|
||||
|
||||
// Create 创建数据映射
|
||||
func (s *dataMappingService) Create(ctx context.Context, req *dto.CreateDataMappingReq) (res *dto.CreateDataMappingRes, err error) {
|
||||
// 检查接口是否存在
|
||||
// TODO: 这里需要调用data层的ApiInterface服务,暂时跳过
|
||||
|
||||
// 检查同一接口下目标字段是否重复
|
||||
existing, err := dao.DataMapping.GetByInterfaceIdAndTargetField(ctx, req.InterfaceId, req.TargetField)
|
||||
if err == nil && existing != nil {
|
||||
return nil, errors.New("该接口下目标字段已存在")
|
||||
}
|
||||
|
||||
// 插入数据库
|
||||
id, err := dao.DataMapping.Insert(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.CreateDataMappingRes{
|
||||
Id: id,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// BatchCreate 批量创建数据映射
|
||||
func (s *dataMappingService) BatchCreate(ctx context.Context, req *dto.BatchCreateDataMappingReq) (res *dto.BatchCreateDataMappingRes, err error) {
|
||||
var ids []int64
|
||||
successCount := 0
|
||||
failedCount := 0
|
||||
|
||||
for _, mappingReq := range req.Mappings {
|
||||
// 设置平台和接口ID
|
||||
mappingReq.PlatformId = req.PlatformId
|
||||
mappingReq.InterfaceId = req.InterfaceId
|
||||
|
||||
createRes, err := s.Create(ctx, &mappingReq)
|
||||
if err != nil {
|
||||
failedCount++
|
||||
g.Log().Error(ctx, "批量创建映射失败", g.Map{
|
||||
"sourceField": mappingReq.SourceField,
|
||||
"targetField": mappingReq.TargetField,
|
||||
"error": err.Error(),
|
||||
})
|
||||
} else {
|
||||
successCount++
|
||||
ids = append(ids, createRes.Id)
|
||||
}
|
||||
}
|
||||
|
||||
return &dto.BatchCreateDataMappingRes{
|
||||
SuccessCount: successCount,
|
||||
FailedCount: failedCount,
|
||||
Ids: ids,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// List 获取数据映射列表
|
||||
func (s *dataMappingService) List(ctx context.Context, req *dto.ListDataMappingReq) (res *dto.ListDataMappingRes, err error) {
|
||||
mappingList, total, err := dao.DataMapping.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取平台和接口ID列表
|
||||
platformIds := make([]int64, 0)
|
||||
interfaceIds := make([]int64, 0)
|
||||
for _, item := range mappingList {
|
||||
if item.PlatformId > 0 {
|
||||
platformIds = append(platformIds, item.PlatformId)
|
||||
}
|
||||
if item.InterfaceId > 0 {
|
||||
interfaceIds = append(interfaceIds, item.InterfaceId)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 批量获取平台和接口信息(需要调用data层服务)
|
||||
platformMap := make(map[int64]string)
|
||||
interfaceMap := make(map[int64]string)
|
||||
|
||||
// 组装响应数据
|
||||
list := make([]dto.DataMappingItem, 0, len(mappingList))
|
||||
for _, item := range mappingList {
|
||||
platformName := ""
|
||||
if name, ok := platformMap[item.PlatformId]; ok {
|
||||
platformName = name
|
||||
}
|
||||
interfaceName := ""
|
||||
if name, ok := interfaceMap[item.InterfaceId]; ok {
|
||||
interfaceName = name
|
||||
}
|
||||
|
||||
list = append(list, dto.DataMappingItem{
|
||||
Id: item.Id,
|
||||
PlatformId: item.PlatformId,
|
||||
PlatformName: platformName,
|
||||
InterfaceId: item.InterfaceId,
|
||||
InterfaceName: interfaceName,
|
||||
SourceField: item.SourceField,
|
||||
TargetField: item.TargetField,
|
||||
FieldType: item.FieldType,
|
||||
DefaultValue: item.DefaultValue,
|
||||
TransformRule: item.TransformRule,
|
||||
Priority: item.Priority,
|
||||
Status: item.Status,
|
||||
StatusName: s.getStatusName(item.Status),
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
UpdatedAt: item.UpdatedAt.Unix(),
|
||||
})
|
||||
}
|
||||
|
||||
res = &dto.ListDataMappingRes{
|
||||
List: list,
|
||||
Total: total,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOne 获取单个数据映射
|
||||
func (s *dataMappingService) GetOne(ctx context.Context, req *dto.GetDataMappingReq) (res *dto.GetDataMappingRes, err error) {
|
||||
mapping, err := dao.DataMapping.GetOne(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: 获取平台和接口名称
|
||||
platformName := ""
|
||||
interfaceName := ""
|
||||
|
||||
return &dto.GetDataMappingRes{
|
||||
DataMapping: mapping,
|
||||
PlatformName: platformName,
|
||||
InterfaceName: interfaceName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Update 更新数据映射
|
||||
func (s *dataMappingService) Update(ctx context.Context, req *dto.UpdateDataMappingReq) (err error) {
|
||||
// 检查映射是否存在
|
||||
exist, err := dao.DataMapping.GetOne(ctx, &dto.GetDataMappingReq{Id: req.Id})
|
||||
if err != nil || exist == nil {
|
||||
return errors.New("映射不存在")
|
||||
}
|
||||
|
||||
// 如果修改了目标字段,检查是否重复
|
||||
if req.TargetField != "" && req.TargetField != exist.TargetField {
|
||||
interfaceId := req.InterfaceId
|
||||
if interfaceId == 0 {
|
||||
interfaceId = exist.InterfaceId
|
||||
}
|
||||
existing, err := dao.DataMapping.GetByInterfaceIdAndTargetField(ctx, interfaceId, req.TargetField)
|
||||
if err == nil && existing != nil && existing.Id != req.Id {
|
||||
return errors.New("该接口下目标字段已存在")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = dao.DataMapping.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除数据映射
|
||||
func (s *dataMappingService) Delete(ctx context.Context, req *dto.DeleteDataMappingReq) (err error) {
|
||||
_, err = dao.DataMapping.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// Execute 执行数据映射
|
||||
func (s *dataMappingService) Execute(ctx context.Context, req *dto.ExecuteDataMappingReq) (res *dto.ExecuteDataMappingRes, err error) {
|
||||
// 获取接口的所有映射规则
|
||||
mappings, err := dao.DataMapping.GetByInterfaceId(ctx, req.InterfaceId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(mappings) == 0 {
|
||||
return &dto.ExecuteDataMappingRes{
|
||||
TargetData: map[string]interface{}{},
|
||||
AppliedRules: []string{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 初始化目标数据
|
||||
targetData := make(map[string]interface{})
|
||||
appliedRules := make([]string, 0)
|
||||
|
||||
// 遍历映射规则进行转换
|
||||
for _, mapping := range mappings {
|
||||
if mapping.Status != consts.MappingStatusActive {
|
||||
continue
|
||||
}
|
||||
|
||||
// 获取源数据值
|
||||
sourceValue, exists := req.SourceData[mapping.SourceField]
|
||||
|
||||
// 应用转换规则
|
||||
targetValue := s.applyTransformRule(ctx, sourceValue, exists, mapping)
|
||||
|
||||
// 设置目标数据
|
||||
targetData[mapping.TargetField] = targetValue
|
||||
|
||||
appliedRules = append(appliedRules, gconv.String(mapping.SourceField)+" -> "+gconv.String(mapping.TargetField))
|
||||
}
|
||||
|
||||
return &dto.ExecuteDataMappingRes{
|
||||
TargetData: targetData,
|
||||
AppliedRules: appliedRules,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// applyTransformRule 应用转换规则
|
||||
func (s *dataMappingService) applyTransformRule(ctx context.Context, sourceValue interface{}, exists bool, mapping entity.DataMapping) interface{} {
|
||||
// 如果源字段不存在,使用默认值
|
||||
if !exists {
|
||||
if mapping.DefaultValue != "" {
|
||||
return mapping.DefaultValue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 如果没有转换规则,直接返回源值
|
||||
if mapping.TransformRule == nil || len(mapping.TransformRule) == 0 {
|
||||
return sourceValue
|
||||
}
|
||||
|
||||
// 获取转换类型
|
||||
transformType := ""
|
||||
if t, ok := mapping.TransformRule["type"].(string); ok {
|
||||
transformType = t
|
||||
}
|
||||
|
||||
// 根据转换类型应用不同的转换逻辑
|
||||
switch consts.TransformType(transformType) {
|
||||
case consts.TransformTypeFixed:
|
||||
// 固定值
|
||||
if v, ok := mapping.TransformRule["rule"].(string); ok {
|
||||
return v
|
||||
}
|
||||
case consts.TransformTypeMapping:
|
||||
// 值映射
|
||||
if mappingMap, ok := mapping.TransformRule["mappingMap"].(map[string]interface{}); ok {
|
||||
if sourceKey := gconv.String(sourceValue); sourceKey != "" {
|
||||
if v, ok := mappingMap[sourceKey]; ok {
|
||||
return v
|
||||
}
|
||||
}
|
||||
}
|
||||
case consts.TransformTypeRegex:
|
||||
// 正则转换
|
||||
if regex, ok := mapping.TransformRule["regex"].(string); ok {
|
||||
// TODO: 实现正则替换逻辑
|
||||
g.Log().Warning(ctx, "正则转换暂未实现", g.Map{
|
||||
"regex": regex,
|
||||
"sourceValue": sourceValue,
|
||||
})
|
||||
}
|
||||
case consts.TransformTypeFunction:
|
||||
// 函数转换
|
||||
if functionName, ok := mapping.TransformRule["functionName"].(string); ok {
|
||||
// TODO: 实现函数调用逻辑
|
||||
g.Log().Warning(ctx, "函数转换暂未实现", g.Map{
|
||||
"function": functionName,
|
||||
"sourceValue": sourceValue,
|
||||
})
|
||||
}
|
||||
case consts.TransformTypeScript:
|
||||
// 脚本转换
|
||||
if script, ok := mapping.TransformRule["script"].(string); ok {
|
||||
// TODO: 实现脚本执行逻辑
|
||||
g.Log().Warning(ctx, "脚本转换暂未实现", g.Map{
|
||||
"script": script,
|
||||
"sourceValue": sourceValue,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 默认返回源值
|
||||
return sourceValue
|
||||
}
|
||||
|
||||
// getStatusName 获取状态名称
|
||||
func (s *dataMappingService) getStatusName(status consts.MappingStatus) string {
|
||||
statusNames := map[consts.MappingStatus]string{
|
||||
consts.MappingStatusActive: "启用",
|
||||
consts.MappingStatusInactive: "停用",
|
||||
}
|
||||
if name, ok := statusNames[status]; ok {
|
||||
return name
|
||||
}
|
||||
return string(status)
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"cid/consts"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type rateLimit struct{}
|
||||
|
||||
// RateLimit 限流服务
|
||||
var RateLimit = new(rateLimit)
|
||||
|
||||
// TenantRateLimitConfig 租户限流配置
|
||||
type TenantRateLimitConfig struct {
|
||||
TenantID int64 // 租户ID
|
||||
RequestsPerSecond float64 // 每秒请求数
|
||||
Burst int // 突发请求数
|
||||
Window time.Duration // 时间窗口
|
||||
}
|
||||
|
||||
// CheckTenantRequestLimit 检查租户请求次数限制
|
||||
func (s *rateLimit) 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 *rateLimit) 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 *rateLimit) SetTenantRateLimitConfig(ctx context.Context, config *TenantRateLimitConfig) error {
|
||||
// 注意:实际使用的是config.yml中的全局配置,此方法仅用于兼容旧API
|
||||
// 实际限流参数请修改config.yml中的tenantRateLimit部分
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTenantCurrentUsage 获取租户当前请求使用情况
|
||||
func (s *rateLimit) 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
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cid/dao"
|
||||
"cid/model/dto"
|
||||
"cid/model/entity"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type strategy struct{}
|
||||
|
||||
// Strategy 策略服务
|
||||
var Strategy = new(strategy)
|
||||
|
||||
// CreateStrategy 创建策略
|
||||
func (s *strategy) CreateStrategy(ctx context.Context, req *dto.CreateStrategyReq) (id int64, err error) {
|
||||
// 检查策略名称是否已存在
|
||||
existingStrategy, err := dao.Strategy.GetByName(ctx, req.Name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingStrategy != nil {
|
||||
return 0, gerror.New("策略名称已存在")
|
||||
}
|
||||
|
||||
// 验证转化率范围
|
||||
if req.MaxConversion <= req.MinConversion {
|
||||
return 0, gerror.New("最高转化率必须大于最低转化率")
|
||||
}
|
||||
|
||||
// 序列化权重配置
|
||||
weightsJson, err := json.Marshal(req.SourceWeights)
|
||||
if err != nil {
|
||||
return 0, gerror.Wrap(err, "权重配置序列化失败")
|
||||
}
|
||||
|
||||
strategy := &entity.Strategy{
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
MinConversion: req.MinConversion,
|
||||
MaxConversion: req.MaxConversion,
|
||||
SourceWeights: string(weightsJson),
|
||||
MaxAdsPerReq: req.MaxAdsPerReq,
|
||||
Priority: req.Priority,
|
||||
}
|
||||
|
||||
// 设置状态
|
||||
strategy.Status = req.Status
|
||||
|
||||
_, err = dao.Strategy.Create(ctx, strategy)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// MongoDB使用ObjectId,创建成功后返回成功状态
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
// UpdateStrategy 更新策略
|
||||
func (s *strategy) UpdateStrategy(ctx context.Context, req *dto.UpdateStrategyReq) (affected int64, err error) {
|
||||
// 检查策略是否存在
|
||||
existingStrategy, err := dao.Strategy.GetByID(ctx, strconv.FormatInt(req.Id, 10))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingStrategy == nil {
|
||||
return 0, gerror.New("策略不存在")
|
||||
}
|
||||
|
||||
// 如果更新名称,检查是否与其他策略冲突
|
||||
if req.Name != "" && req.Name != existingStrategy.Name {
|
||||
conflictStrategy, err := dao.Strategy.GetByName(ctx, req.Name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if conflictStrategy != nil {
|
||||
return 0, gerror.New("策略名称已存在")
|
||||
}
|
||||
}
|
||||
|
||||
// 验证转化率范围
|
||||
if req.MaxConversion <= req.MinConversion {
|
||||
return 0, gerror.New("最高转化率必须大于最低转化率")
|
||||
}
|
||||
|
||||
// 序列化权重配置
|
||||
weightsJson, err := json.Marshal(req.SourceWeights)
|
||||
if err != nil {
|
||||
return 0, gerror.Wrap(err, "权重配置序列化失败")
|
||||
}
|
||||
|
||||
strategy := &entity.Strategy{
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
MinConversion: req.MinConversion,
|
||||
MaxConversion: req.MaxConversion,
|
||||
SourceWeights: string(weightsJson),
|
||||
MaxAdsPerReq: req.MaxAdsPerReq,
|
||||
Priority: req.Priority,
|
||||
}
|
||||
|
||||
// 设置状态
|
||||
strategy.Status = req.Status
|
||||
|
||||
return dao.Strategy.Update(ctx, strategy)
|
||||
}
|
||||
|
||||
// DeleteStrategy 删除策略
|
||||
func (s *strategy) DeleteStrategy(ctx context.Context, id int64) (affected int64, err error) {
|
||||
// 检查策略是否存在
|
||||
existingStrategy, err := dao.Strategy.GetByID(ctx, strconv.FormatInt(id, 10))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if existingStrategy == nil {
|
||||
return 0, gerror.New("策略不存在")
|
||||
}
|
||||
|
||||
return dao.Strategy.Delete(ctx, strconv.FormatInt(id, 10))
|
||||
}
|
||||
|
||||
// GetStrategyByID 根据ID获取策略
|
||||
func (s *strategy) GetStrategyByID(ctx context.Context, id int64) (strategy *dto.StrategyRes, err error) {
|
||||
entity, err := dao.Strategy.GetByID(ctx, strconv.FormatInt(id, 10))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if entity == nil {
|
||||
return nil, gerror.New("策略不存在")
|
||||
}
|
||||
|
||||
// 反序列化权重配置
|
||||
var weights map[string]int
|
||||
if entity.SourceWeights != "" {
|
||||
err = json.Unmarshal([]byte(entity.SourceWeights), &weights)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "权重配置反序列化失败")
|
||||
}
|
||||
}
|
||||
|
||||
// 将ObjectId的十六进制字符串转换为int64,如果失败则使用0
|
||||
var idInt64 int64
|
||||
if id, err := strconv.ParseInt(entity.Id.Hex(), 16, 64); err == nil {
|
||||
idInt64 = id
|
||||
}
|
||||
|
||||
return &dto.StrategyRes{
|
||||
Id: idInt64,
|
||||
Name: entity.Name,
|
||||
Description: entity.Description,
|
||||
TenantLevel: "", // Strategy实体中没有TenantLevel字段,暂时设为空字符串
|
||||
MinConversion: entity.MinConversion,
|
||||
MaxConversion: entity.MaxConversion,
|
||||
SourceWeights: weights,
|
||||
MaxAdsPerReq: entity.MaxAdsPerReq,
|
||||
Priority: entity.Priority,
|
||||
Status: entity.Status,
|
||||
CreatedAt: entity.CreatedAt.String(),
|
||||
UpdatedAt: entity.UpdatedAt.String(),
|
||||
CreatedBy: 0, // 这些字段在MongoBaseDO中不存在,暂时设为0
|
||||
UpdatedBy: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetStrategyList 获取策略列表
|
||||
func (s *strategy) GetStrategyList(ctx context.Context, req *dto.GetStrategyListReq) (res *dto.GetStrategyListRes, err error) {
|
||||
list, total, err := dao.Strategy.GetList(ctx, req.Page, req.Size, req.TenantLevel, req.Status)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var strategyList []*dto.StrategyRes
|
||||
for _, entity := range list {
|
||||
// 反序列化权重配置
|
||||
var weights map[string]int
|
||||
if entity.SourceWeights != "" {
|
||||
err = json.Unmarshal([]byte(entity.SourceWeights), &weights)
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "策略 %d 权重配置反序列化失败: %v", entity.Id, err)
|
||||
weights = make(map[string]int)
|
||||
}
|
||||
}
|
||||
|
||||
// 将ObjectId的十六进制字符串转换为int64,如果失败则使用0
|
||||
var idInt64 int64
|
||||
if id, err := strconv.ParseInt(entity.Id.Hex(), 16, 64); err == nil {
|
||||
idInt64 = id
|
||||
}
|
||||
|
||||
strategyList = append(strategyList, &dto.StrategyRes{
|
||||
Id: idInt64,
|
||||
Name: entity.Name,
|
||||
Description: entity.Description,
|
||||
TenantLevel: "", // Strategy实体中没有TenantLevel字段,暂时设为空字符串
|
||||
MinConversion: entity.MinConversion,
|
||||
MaxConversion: entity.MaxConversion,
|
||||
SourceWeights: weights,
|
||||
MaxAdsPerReq: entity.MaxAdsPerReq,
|
||||
Priority: entity.Priority,
|
||||
Status: entity.Status,
|
||||
CreatedAt: entity.CreatedAt.String(),
|
||||
UpdatedAt: entity.UpdatedAt.String(),
|
||||
CreatedBy: 0, // 这些字段在MongoBaseDO中不存在,暂时设为0
|
||||
UpdatedBy: 0,
|
||||
})
|
||||
}
|
||||
|
||||
return &dto.GetStrategyListRes{
|
||||
List: strategyList,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetStrategyByTenantLevel 根据租户级别获取策略
|
||||
func (s *strategy) GetStrategyByTenantLevel(ctx context.Context, tenantLevel string) (strategy *entity.Strategy, err error) {
|
||||
return dao.Strategy.GetByTenantLevel(ctx, tenantLevel)
|
||||
}
|
||||
+129
-1
@@ -1 +1,129 @@
|
||||
-----------张斌2025-06-16 15:00:00--------------
|
||||
-- CID数据库表结构
|
||||
|
||||
-- 应用管理表
|
||||
CREATE TABLE IF NOT EXISTS cid_application (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id VARCHAR(64) DEFAULT '',
|
||||
name VARCHAR(255) NOT NULL COMMENT '应用名称',
|
||||
app_code VARCHAR(100) NOT NULL COMMENT '应用编码(唯一标识)',
|
||||
type VARCHAR(50) NOT NULL COMMENT '应用类型',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '应用状态:active启用/inactive停用',
|
||||
description TEXT COMMENT '应用描述',
|
||||
access_config JSONB COMMENT '接入配置',
|
||||
limit_config JSONB COMMENT '限流配置',
|
||||
callback_config JSONB COMMENT '回调配置',
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
deleted_at BIGINT DEFAULT 0,
|
||||
CONSTRAINT uk_cid_application_app_code UNIQUE (app_code, deleted_at)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_cid_application_tenant ON cid_application(tenant_id);
|
||||
CREATE INDEX idx_cid_application_type ON cid_application(type);
|
||||
CREATE INDEX idx_cid_application_status ON cid_application(status);
|
||||
CREATE INDEX idx_cid_application_name ON cid_application(name);
|
||||
CREATE INDEX idx_cid_application_app_code ON cid_application(app_code);
|
||||
|
||||
-- 平台管理表
|
||||
CREATE TABLE IF NOT EXISTS cid_platform (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id VARCHAR(64) DEFAULT '',
|
||||
name VARCHAR(255) NOT NULL COMMENT '平台名称',
|
||||
type VARCHAR(50) NOT NULL COMMENT '平台类型',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '平台状态:active启用/inactive停用',
|
||||
description TEXT COMMENT '平台描述',
|
||||
auth_config JSONB COMMENT '认证配置',
|
||||
limit_config JSONB COMMENT '限流配置',
|
||||
platform_config JSONB COMMENT '平台专用配置',
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
deleted_at BIGINT DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX idx_cid_platform_tenant ON cid_platform(tenant_id);
|
||||
CREATE INDEX idx_cid_platform_type ON cid_platform(type);
|
||||
CREATE INDEX idx_cid_platform_status ON cid_platform(status);
|
||||
CREATE INDEX idx_cid_platform_name ON cid_platform(name);
|
||||
|
||||
-- 接口管理表
|
||||
CREATE TABLE IF NOT EXISTS cid_api_interface (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id VARCHAR(64) DEFAULT '',
|
||||
platform_id BIGINT NOT NULL COMMENT '所属平台ID',
|
||||
name VARCHAR(255) NOT NULL COMMENT '接口名称',
|
||||
code VARCHAR(100) NOT NULL COMMENT '接口编码',
|
||||
url VARCHAR(500) NOT NULL COMMENT '接口地址',
|
||||
method VARCHAR(10) NOT NULL COMMENT '请求方法:GET/POST/PUT/DELETE等',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '接口状态:active启用/inactive停用',
|
||||
auth_type VARCHAR(50) COMMENT '认证类型:oauth2/apikey/basic等',
|
||||
request_config JSONB COMMENT '请求配置',
|
||||
response_config JSONB COMMENT '响应配置',
|
||||
limit_config JSONB COMMENT '接口独立限流配置(可选,覆盖平台配置)',
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
deleted_at BIGINT DEFAULT 0,
|
||||
CONSTRAINT fk_cid_api_interface_platform FOREIGN KEY (platform_id) REFERENCES cid_platform(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_cid_api_interface_tenant ON cid_api_interface(tenant_id);
|
||||
CREATE INDEX idx_cid_api_interface_platform ON cid_api_interface(platform_id);
|
||||
CREATE INDEX idx_cid_api_interface_code ON cid_api_interface(code);
|
||||
CREATE INDEX idx_cid_api_interface_status ON cid_api_interface(status);
|
||||
CREATE INDEX idx_cid_api_interface_name ON cid_api_interface(name);
|
||||
|
||||
-- 数据获取日志表
|
||||
CREATE TABLE IF NOT EXISTS cid_data_fetch_log (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id VARCHAR(64) DEFAULT '',
|
||||
platform_id BIGINT NOT NULL COMMENT '平台ID',
|
||||
interface_id BIGINT NOT NULL COMMENT '接口ID',
|
||||
request_id VARCHAR(100) NOT NULL COMMENT '请求ID',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '执行状态:pending/running/success/failed/rate_limit',
|
||||
start_time BIGINT NOT NULL COMMENT '开始时间(时间戳)',
|
||||
end_time BIGINT DEFAULT 0 COMMENT '结束时间(时间戳)',
|
||||
duration INT DEFAULT 0 COMMENT '执行时长(毫秒)',
|
||||
request_config JSONB COMMENT '请求配置参数',
|
||||
response_data TEXT COMMENT '响应数据(JSON)',
|
||||
error_message TEXT COMMENT '错误信息',
|
||||
retry_count INT DEFAULT 0 COMMENT '重试次数',
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
deleted_at BIGINT DEFAULT 0,
|
||||
CONSTRAINT fk_cid_data_fetch_log_platform FOREIGN KEY (platform_id) REFERENCES cid_platform(id),
|
||||
CONSTRAINT fk_cid_data_fetch_log_interface FOREIGN KEY (interface_id) REFERENCES cid_api_interface(id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_cid_data_fetch_log_tenant ON cid_data_fetch_log(tenant_id);
|
||||
CREATE INDEX idx_cid_data_fetch_log_platform ON cid_data_fetch_log(platform_id);
|
||||
CREATE INDEX idx_cid_data_fetch_log_interface ON cid_data_fetch_log(interface_id);
|
||||
CREATE INDEX idx_cid_data_fetch_log_request_id ON cid_data_fetch_log(request_id);
|
||||
CREATE INDEX idx_cid_data_fetch_log_status ON cid_data_fetch_log(status);
|
||||
CREATE INDEX idx_cid_data_fetch_log_start_time ON cid_data_fetch_log(start_time);
|
||||
|
||||
-- 数据映射表
|
||||
CREATE TABLE IF NOT EXISTS cid_data_mapping (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id VARCHAR(64) DEFAULT '',
|
||||
platform_id BIGINT NOT NULL COMMENT '平台ID',
|
||||
interface_id BIGINT NOT NULL COMMENT '接口ID',
|
||||
source_field VARCHAR(255) NOT NULL COMMENT '源字段(接口返回字段)',
|
||||
target_field VARCHAR(255) NOT NULL COMMENT '目标字段(本地表字段)',
|
||||
field_type VARCHAR(50) NOT NULL COMMENT '字段类型:string/int/float/bool/array/object',
|
||||
default_value VARCHAR(500) COMMENT '默认值',
|
||||
transform_rule JSONB COMMENT '转换规则',
|
||||
priority INT DEFAULT 0 COMMENT '优先级(数字越小优先级越高)',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '状态:active启用/inactive停用',
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
deleted_at BIGINT DEFAULT 0,
|
||||
CONSTRAINT fk_cid_data_mapping_platform FOREIGN KEY (platform_id) REFERENCES cid_platform(id),
|
||||
CONSTRAINT fk_cid_data_mapping_interface FOREIGN KEY (interface_id) REFERENCES cid_api_interface(id),
|
||||
CONSTRAINT uk_cid_data_mapping_interface_target UNIQUE (interface_id, target_field, deleted_at)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_cid_data_mapping_tenant ON cid_data_mapping(tenant_id);
|
||||
CREATE INDEX idx_cid_data_mapping_platform ON cid_data_mapping(platform_id);
|
||||
CREATE INDEX idx_cid_data_mapping_interface ON cid_data_mapping(interface_id);
|
||||
CREATE INDEX idx_cid_data_mapping_source_field ON cid_data_mapping(source_field);
|
||||
CREATE INDEX idx_cid_data_mapping_status ON cid_data_mapping(status);
|
||||
CREATE INDEX idx_cid_data_mapping_priority ON cid_data_mapping(priority);
|
||||
|
||||
Reference in New Issue
Block a user