diff --git a/config.yml b/config.yml index 2415936..15448e8 100644 --- a/config.yml +++ b/config.yml @@ -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: diff --git a/consts/ad_format_type.go b/consts/ad_format_type.go deleted file mode 100644 index b9ed0f9..0000000 --- a/consts/ad_format_type.go +++ /dev/null @@ -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 -} diff --git a/consts/ad_source_health.go b/consts/ad_source_health.go deleted file mode 100644 index 34a374c..0000000 --- a/consts/ad_source_health.go +++ /dev/null @@ -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 -} diff --git a/consts/ad_source_provider.go b/consts/ad_source_provider.go deleted file mode 100644 index 0d45641..0000000 --- a/consts/ad_source_provider.go +++ /dev/null @@ -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 -} diff --git a/consts/ad_source_status.go b/consts/ad_source_status.go deleted file mode 100644 index fc755b1..0000000 --- a/consts/ad_source_status.go +++ /dev/null @@ -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 -} diff --git a/consts/ad_source_type.go b/consts/ad_source_type.go deleted file mode 100644 index 6fb78a0..0000000 --- a/consts/ad_source_type.go +++ /dev/null @@ -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 -} diff --git a/consts/app/application_status.go b/consts/app/application_status.go new file mode 100644 index 0000000..44f1384 --- /dev/null +++ b/consts/app/application_status.go @@ -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) +} diff --git a/consts/app/application_type.go b/consts/app/application_type.go new file mode 100644 index 0000000..aab6888 --- /dev/null +++ b/consts/app/application_type.go @@ -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) +} diff --git a/consts/auth_type.go b/consts/auth_type.go deleted file mode 100644 index 11bf0c4..0000000 --- a/consts/auth_type.go +++ /dev/null @@ -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 -} diff --git a/consts/bidding_type.go b/consts/bidding_type.go deleted file mode 100644 index cf08554..0000000 --- a/consts/bidding_type.go +++ /dev/null @@ -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 -} diff --git a/consts/billing_model.go b/consts/billing_model.go deleted file mode 100644 index 32cd3d0..0000000 --- a/consts/billing_model.go +++ /dev/null @@ -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 -} diff --git a/consts/collections.go b/consts/collections.go deleted file mode 100644 index d0f4deb..0000000 --- a/consts/collections.go +++ /dev/null @@ -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" // 定向规则集合 -) diff --git a/consts/config.go b/consts/config.go deleted file mode 100644 index c7f9e6b..0000000 --- a/consts/config.go +++ /dev/null @@ -1,19 +0,0 @@ -package consts - -// 默认配置值 -const ( - DefaultTimeout = 5000 // 默认超时时间(毫秒) - DefaultRetryCount = 3 // 默认重试次数 - DefaultPriority = 1 // 默认优先级 -) - -// 错误消息 -const ( - ErrAdSourceNotFound = "广告源不存在" - ErrAdSourceNameExists = "广告源名称已存在" - ErrAdSourceCodeExists = "广告源编码已存在" - ErrAdSourceInactive = "广告源非活跃状态" - ErrAdSourceUnhealthy = "广告源健康状态异常" - ErrRateLimitExceeded = "请求频率超限" - ErrInvalidConfiguration = "配置参数无效" -) diff --git a/consts/consts.go b/consts/consts.go deleted file mode 100644 index 81a70e2..0000000 --- a/consts/consts.go +++ /dev/null @@ -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 文件中 diff --git a/consts/data/api_method.go b/consts/data/api_method.go new file mode 100644 index 0000000..e3a0125 --- /dev/null +++ b/consts/data/api_method.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) +} diff --git a/consts/data/fetch_status.go b/consts/data/fetch_status.go new file mode 100644 index 0000000..79fc657 --- /dev/null +++ b/consts/data/fetch_status.go @@ -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) +} diff --git a/consts/data/limit_type.go b/consts/data/limit_type.go new file mode 100644 index 0000000..b666690 --- /dev/null +++ b/consts/data/limit_type.go @@ -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) +} diff --git a/consts/data/platform_status.go b/consts/data/platform_status.go new file mode 100644 index 0000000..0edc02a --- /dev/null +++ b/consts/data/platform_status.go @@ -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) +} diff --git a/consts/data/platform_type.go b/consts/data/platform_type.go new file mode 100644 index 0000000..82ed3a5 --- /dev/null +++ b/consts/data/platform_type.go @@ -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) +} diff --git a/consts/errors.go b/consts/errors.go deleted file mode 100644 index a56a011..0000000 --- a/consts/errors.go +++ /dev/null @@ -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("频次限制必须为非负数") -) diff --git a/consts/mapping/mapping_status.go b/consts/mapping/mapping_status.go new file mode 100644 index 0000000..f6cd94a --- /dev/null +++ b/consts/mapping/mapping_status.go @@ -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) +} diff --git a/consts/mapping/transform_type.go b/consts/mapping/transform_type.go new file mode 100644 index 0000000..3847f9a --- /dev/null +++ b/consts/mapping/transform_type.go @@ -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) +} diff --git a/consts/payment_terms.go b/consts/payment_terms.go deleted file mode 100644 index 6ea37eb..0000000 --- a/consts/payment_terms.go +++ /dev/null @@ -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 -} diff --git a/consts/public/collections.go b/consts/public/collections.go new file mode 100644 index 0000000..7c988f4 --- /dev/null +++ b/consts/public/collections.go @@ -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" // 应用管理表 +) diff --git a/consts/redis_key.go b/consts/redis_key.go deleted file mode 100644 index ddb7202..0000000 --- a/consts/redis_key.go +++ /dev/null @@ -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" // 用户行为流 -) diff --git a/controller/ad_position_controller.go b/controller/ad_position_controller.go deleted file mode 100644 index 5261d5e..0000000 --- a/controller/ad_position_controller.go +++ /dev/null @@ -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 -} diff --git a/controller/ad_source_controller.go b/controller/ad_source_controller.go deleted file mode 100644 index a2cd7ac..0000000 --- a/controller/ad_source_controller.go +++ /dev/null @@ -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 -} diff --git a/controller/advertisement_controller.go b/controller/advertisement_controller.go deleted file mode 100644 index f9b8156..0000000 --- a/controller/advertisement_controller.go +++ /dev/null @@ -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) -} diff --git a/controller/advertiser_controller.go b/controller/advertiser_controller.go deleted file mode 100644 index 127eba5..0000000 --- a/controller/advertiser_controller.go +++ /dev/null @@ -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 -} diff --git a/controller/app/application_controller.go b/controller/app/application_controller.go new file mode 100644 index 0000000..e960b44 --- /dev/null +++ b/controller/app/application_controller.go @@ -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 +} diff --git a/controller/application_controller.go b/controller/application_controller.go deleted file mode 100644 index 0a714cd..0000000 --- a/controller/application_controller.go +++ /dev/null @@ -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 -} diff --git a/controller/cid_controller.go b/controller/cid_controller.go deleted file mode 100644 index 045f8c0..0000000 --- a/controller/cid_controller.go +++ /dev/null @@ -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 -} diff --git a/controller/data/api_interface_controller.go b/controller/data/api_interface_controller.go new file mode 100644 index 0000000..96b92e7 --- /dev/null +++ b/controller/data/api_interface_controller.go @@ -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 +} diff --git a/controller/data/data_fetch_controller.go b/controller/data/data_fetch_controller.go new file mode 100644 index 0000000..d09d41c --- /dev/null +++ b/controller/data/data_fetch_controller.go @@ -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) +} diff --git a/controller/data/platform_controller.go b/controller/data/platform_controller.go new file mode 100644 index 0000000..2a58427 --- /dev/null +++ b/controller/data/platform_controller.go @@ -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 +} diff --git a/controller/mapping/data_mapping_controller.go b/controller/mapping/data_mapping_controller.go new file mode 100644 index 0000000..345d812 --- /dev/null +++ b/controller/mapping/data_mapping_controller.go @@ -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) +} diff --git a/controller/rate_limit_controller.go b/controller/rate_limit_controller.go deleted file mode 100644 index 5c8a4a1..0000000 --- a/controller/rate_limit_controller.go +++ /dev/null @@ -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 -} diff --git a/controller/strategy_controller.go b/controller/strategy_controller.go deleted file mode 100644 index 22c4378..0000000 --- a/controller/strategy_controller.go +++ /dev/null @@ -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) -} diff --git a/dao/ad_position_dao.go b/dao/ad_position_dao.go deleted file mode 100644 index e5ee9b4..0000000 --- a/dao/ad_position_dao.go +++ /dev/null @@ -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 -} diff --git a/dao/ad_source_dao.go b/dao/ad_source_dao.go deleted file mode 100644 index 5a5ec07..0000000 --- a/dao/ad_source_dao.go +++ /dev/null @@ -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 -} diff --git a/dao/advertisement_dao.go b/dao/advertisement_dao.go deleted file mode 100644 index 6fcd256..0000000 --- a/dao/advertisement_dao.go +++ /dev/null @@ -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 -} diff --git a/dao/advertiser_dao.go b/dao/advertiser_dao.go deleted file mode 100644 index 18e4d19..0000000 --- a/dao/advertiser_dao.go +++ /dev/null @@ -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 -} diff --git a/dao/app/application_dao.go b/dao/app/application_dao.go new file mode 100644 index 0000000..494fae6 --- /dev/null +++ b/dao/app/application_dao.go @@ -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 +} diff --git a/dao/application_dao.go b/dao/application_dao.go deleted file mode 100644 index 5a415de..0000000 --- a/dao/application_dao.go +++ /dev/null @@ -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 -} diff --git a/dao/cid_request_dao.go b/dao/cid_request_dao.go deleted file mode 100644 index 21aed68..0000000 --- a/dao/cid_request_dao.go +++ /dev/null @@ -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 -} diff --git a/dao/data/api_interface_dao.go b/dao/data/api_interface_dao.go new file mode 100644 index 0000000..65ea0bd --- /dev/null +++ b/dao/data/api_interface_dao.go @@ -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 +} diff --git a/dao/data/data_fetch_log_dao.go b/dao/data/data_fetch_log_dao.go new file mode 100644 index 0000000..bdc3075 --- /dev/null +++ b/dao/data/data_fetch_log_dao.go @@ -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() +} diff --git a/dao/data/platform_dao.go b/dao/data/platform_dao.go new file mode 100644 index 0000000..7718107 --- /dev/null +++ b/dao/data/platform_dao.go @@ -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 +} diff --git a/dao/mapping/data_mapping_dao.go b/dao/mapping/data_mapping_dao.go new file mode 100644 index 0000000..11b4bab --- /dev/null +++ b/dao/mapping/data_mapping_dao.go @@ -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() +} diff --git a/dao/strategy_dao.go b/dao/strategy_dao.go deleted file mode 100644 index dd6e2f7..0000000 --- a/dao/strategy_dao.go +++ /dev/null @@ -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 -} diff --git a/go.mod b/go.mod index 1f09917..590cbe4 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 4257feb..9f8abdd 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/main.go b/main.go index 18e7077..e52459a 100644 --- a/main.go +++ b/main.go @@ -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 {} } diff --git a/model/config/config.go b/model/config/config.go deleted file mode 100644 index ee67a0f..0000000 --- a/model/config/config.go +++ /dev/null @@ -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"` // 排除的关键词 -} diff --git a/model/dto/ad_position_dto.go b/model/dto/ad_position_dto.go deleted file mode 100644 index 454c6d3..0000000 --- a/model/dto/ad_position_dto.go +++ /dev/null @@ -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"` -} diff --git a/model/dto/ad_source_dto.go b/model/dto/ad_source_dto.go deleted file mode 100644 index 4894d90..0000000 --- a/model/dto/ad_source_dto.go +++ /dev/null @@ -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"` // 删除是否成功 -} diff --git a/model/dto/ad_source_statistics_dto.go b/model/dto/ad_source_statistics_dto.go deleted file mode 100644 index 774565e..0000000 --- a/model/dto/ad_source_statistics_dto.go +++ /dev/null @@ -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"` // 点击率 -} diff --git a/model/dto/advertisement_dto.go b/model/dto/advertisement_dto.go deleted file mode 100644 index 5c4a261..0000000 --- a/model/dto/advertisement_dto.go +++ /dev/null @@ -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"` // 广告状态:启用、禁用 -} diff --git a/model/dto/advertiser_dto.go b/model/dto/advertiser_dto.go deleted file mode 100644 index ff90a78..0000000 --- a/model/dto/advertiser_dto.go +++ /dev/null @@ -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"` // 授信额度(分) -} diff --git a/model/dto/app/application_dto.go b/model/dto/app/application_dto.go new file mode 100644 index 0000000..9356d61 --- /dev/null +++ b/model/dto/app/application_dto.go @@ -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停用"` +} diff --git a/model/dto/application_dto.go b/model/dto/application_dto.go deleted file mode 100644 index 67cbd2a..0000000 --- a/model/dto/application_dto.go +++ /dev/null @@ -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"` -} diff --git a/model/dto/cid_dto.go b/model/dto/cid_dto.go deleted file mode 100644 index 6ca55e2..0000000 --- a/model/dto/cid_dto.go +++ /dev/null @@ -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"` // 租户级别 -} diff --git a/model/dto/data/api_interface_dto.go b/model/dto/data/api_interface_dto.go new file mode 100644 index 0000000..e040366 --- /dev/null +++ b/model/dto/data/api_interface_dto.go @@ -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停用"` +} diff --git a/model/dto/data/data_fetch_dto.go b/model/dto/data/data_fetch_dto.go new file mode 100644 index 0000000..ea268d5 --- /dev/null +++ b/model/dto/data/data_fetch_dto.go @@ -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:"消息"` +} diff --git a/model/dto/data/platform_dto.go b/model/dto/data/platform_dto.go new file mode 100644 index 0000000..3d77fc7 --- /dev/null +++ b/model/dto/data/platform_dto.go @@ -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停用"` +} diff --git a/model/dto/mapping/data_mapping_dto.go b/model/dto/mapping/data_mapping_dto.go new file mode 100644 index 0000000..c8022ba --- /dev/null +++ b/model/dto/mapping/data_mapping_dto.go @@ -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:"应用的映射规则"` +} diff --git a/model/dto/rate_limit_dto.go b/model/dto/rate_limit_dto.go deleted file mode 100644 index 82540e5..0000000 --- a/model/dto/rate_limit_dto.go +++ /dev/null @@ -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"` // 使用率百分比 -} diff --git a/model/dto/strategy_dto.go b/model/dto/strategy_dto.go deleted file mode 100644 index 619a2fc..0000000 --- a/model/dto/strategy_dto.go +++ /dev/null @@ -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"` // 是否成功 -} diff --git a/model/entity/ad_creative.go b/model/entity/ad_creative.go deleted file mode 100644 index d037cb9..0000000 --- a/model/entity/ad_creative.go +++ /dev/null @@ -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 -} diff --git a/model/entity/ad_platform.go b/model/entity/ad_platform.go deleted file mode 100644 index 91205a1..0000000 --- a/model/entity/ad_platform.go +++ /dev/null @@ -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 -} diff --git a/model/entity/ad_position.go b/model/entity/ad_position.go deleted file mode 100644 index 8320b8b..0000000 --- a/model/entity/ad_position.go +++ /dev/null @@ -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 -} diff --git a/model/entity/ad_source.go b/model/entity/ad_source.go deleted file mode 100644 index 3ac8df2..0000000 --- a/model/entity/ad_source.go +++ /dev/null @@ -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 -} diff --git a/model/entity/ad_type.go b/model/entity/ad_type.go deleted file mode 100644 index c7c6da1..0000000 --- a/model/entity/ad_type.go +++ /dev/null @@ -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"` // 备注 -} diff --git a/model/entity/advertisement.go b/model/entity/advertisement.go deleted file mode 100644 index fabab89..0000000 --- a/model/entity/advertisement.go +++ /dev/null @@ -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 -} diff --git a/model/entity/advertiser.go b/model/entity/advertiser.go deleted file mode 100644 index 70fad06..0000000 --- a/model/entity/advertiser.go +++ /dev/null @@ -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 -} diff --git a/model/entity/app/application.go b/model/entity/app/application.go new file mode 100644 index 0000000..0fb2ff6 --- /dev/null +++ b/model/entity/app/application.go @@ -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", +} diff --git a/model/entity/app_platform_config.go b/model/entity/app_platform_config.go deleted file mode 100644 index 29ea477..0000000 --- a/model/entity/app_platform_config.go +++ /dev/null @@ -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 -} diff --git a/model/entity/application.go b/model/entity/application.go deleted file mode 100644 index 60ceab3..0000000 --- a/model/entity/application.go +++ /dev/null @@ -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 -} diff --git a/model/entity/cid_request.go b/model/entity/cid_request.go deleted file mode 100644 index 7e63a34..0000000 --- a/model/entity/cid_request.go +++ /dev/null @@ -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"` // 平均出价(分) -} diff --git a/model/entity/data/api_interface.go b/model/entity/data/api_interface.go new file mode 100644 index 0000000..ea35de6 --- /dev/null +++ b/model/entity/data/api_interface.go @@ -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", +} diff --git a/model/entity/data/data_fetch_log.go b/model/entity/data/data_fetch_log.go new file mode 100644 index 0000000..16227ba --- /dev/null +++ b/model/entity/data/data_fetch_log.go @@ -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", +} diff --git a/model/entity/data/platform.go b/model/entity/data/platform.go new file mode 100644 index 0000000..cedb058 --- /dev/null +++ b/model/entity/data/platform.go @@ -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", +} diff --git a/model/entity/mapping/data_mapping.go b/model/entity/mapping/data_mapping.go new file mode 100644 index 0000000..542b6f3 --- /dev/null +++ b/model/entity/mapping/data_mapping.go @@ -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", +} diff --git a/model/entity/platform_delivery_rule.go b/model/entity/platform_delivery_rule.go deleted file mode 100644 index 3788a4a..0000000 --- a/model/entity/platform_delivery_rule.go +++ /dev/null @@ -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 -} diff --git a/model/entity/strategy.go b/model/entity/strategy.go deleted file mode 100644 index d9980b0..0000000 --- a/model/entity/strategy.go +++ /dev/null @@ -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 -} diff --git a/model/entity/targeting.go b/model/entity/targeting.go deleted file mode 100644 index 7313664..0000000 --- a/model/entity/targeting.go +++ /dev/null @@ -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"` // 时区 -} diff --git a/service/ad_position_service.go b/service/ad_position_service.go deleted file mode 100644 index a9502e0..0000000 --- a/service/ad_position_service.go +++ /dev/null @@ -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 -} diff --git a/service/ad_source_service.go b/service/ad_source_service.go deleted file mode 100644 index 59b0b68..0000000 --- a/service/ad_source_service.go +++ /dev/null @@ -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) -} diff --git a/service/advertisement_service.go b/service/advertisement_service.go deleted file mode 100644 index 39d83e9..0000000 --- a/service/advertisement_service.go +++ /dev/null @@ -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 -} diff --git a/service/advertiser_service.go b/service/advertiser_service.go deleted file mode 100644 index c68d84b..0000000 --- a/service/advertiser_service.go +++ /dev/null @@ -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 -} diff --git a/service/app/application_service.go b/service/app/application_service.go new file mode 100644 index 0000000..4b057c1 --- /dev/null +++ b/service/app/application_service.go @@ -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) +} diff --git a/service/application_service.go b/service/application_service.go deleted file mode 100644 index 55de12c..0000000 --- a/service/application_service.go +++ /dev/null @@ -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 -} diff --git a/service/cid_service.go b/service/cid_service.go deleted file mode 100644 index fce11aa..0000000 --- a/service/cid_service.go +++ /dev/null @@ -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 -} diff --git a/service/data/api_interface_service.go b/service/data/api_interface_service.go new file mode 100644 index 0000000..dddc3c3 --- /dev/null +++ b/service/data/api_interface_service.go @@ -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) +} diff --git a/service/data/data_fetch_service.go b/service/data/data_fetch_service.go new file mode 100644 index 0000000..da08fea --- /dev/null +++ b/service/data/data_fetch_service.go @@ -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) +} diff --git a/service/data/platform_service.go b/service/data/platform_service.go new file mode 100644 index 0000000..9ab10af --- /dev/null +++ b/service/data/platform_service.go @@ -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) +} diff --git a/service/mapping/data_mapping_service.go b/service/mapping/data_mapping_service.go new file mode 100644 index 0000000..2cb5910 --- /dev/null +++ b/service/mapping/data_mapping_service.go @@ -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) +} diff --git a/service/rate_limit_service.go b/service/rate_limit_service.go deleted file mode 100644 index b8d0f40..0000000 --- a/service/rate_limit_service.go +++ /dev/null @@ -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 -} diff --git a/service/strategy_service.go b/service/strategy_service.go deleted file mode 100644 index bba6240..0000000 --- a/service/strategy_service.go +++ /dev/null @@ -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) -} diff --git a/update.sql b/update.sql index 807d512..ea23b19 100644 --- a/update.sql +++ b/update.sql @@ -1 +1,129 @@ ------------张斌2025-06-16 15:00:00-------------- \ No newline at end of file +-- 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);