Dockerfile

This commit is contained in:
2026-03-23 14:08:11 +08:00
parent c7a2f5bd0c
commit 827d55dbee
100 changed files with 3139 additions and 5992 deletions
+26 -5
View File
@@ -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:
-57
View File
@@ -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
}
-52
View File
@@ -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
}
-57
View File
@@ -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
}
-52
View File
@@ -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
}
-52
View File
@@ -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
}
+13
View File
@@ -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)
}
+17
View File
@@ -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)
}
-52
View File
@@ -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
}
-57
View File
@@ -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
}
-57
View File
@@ -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
}
-18
View File
@@ -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" // 定向规则集合
)
-19
View File
@@ -1,19 +0,0 @@
package consts
// 默认配置值
const (
DefaultTimeout = 5000 // 默认超时时间(毫秒)
DefaultRetryCount = 3 // 默认重试次数
DefaultPriority = 1 // 默认优先级
)
// 错误消息
const (
ErrAdSourceNotFound = "广告源不存在"
ErrAdSourceNameExists = "广告源名称已存在"
ErrAdSourceCodeExists = "广告源编码已存在"
ErrAdSourceInactive = "广告源非活跃状态"
ErrAdSourceUnhealthy = "广告源健康状态异常"
ErrRateLimitExceeded = "请求频率超限"
ErrInvalidConfiguration = "配置参数无效"
)
-16
View File
@@ -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 文件中
+18
View File
@@ -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)
}
+16
View File
@@ -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)
}
+14
View File
@@ -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)
}
+13
View File
@@ -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)
}
+21
View File
@@ -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)
}
-56
View File
@@ -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("频次限制必须为非负数")
)
+13
View File
@@ -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)
}
+16
View File
@@ -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)
}
-52
View File
@@ -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
}
+10
View File
@@ -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" // 应用管理表
)
-31
View File
@@ -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" // 用户行为流
)
-65
View File
@@ -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
}
-94
View File
@@ -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
}
-46
View File
@@ -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)
}
-71
View File
@@ -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
}
+47
View File
@@ -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
}
-159
View File
@@ -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
}
-47
View File
@@ -1,47 +0,0 @@
package controller
import (
"context"
"cid/model/dto"
"cid/service"
"github.com/gogf/gf/v2/errors/gerror"
)
var CID = new(cid)
type cid struct{}
// GenerateCID 生成CID广告
func (c *cid) GenerateCID(ctx context.Context, req *dto.GenerateCIDReq) (res *dto.GenerateCIDRes, err error) {
if req == nil {
return nil, gerror.New("请求参数不能为空")
}
if req.RequestType == "" {
req.RequestType = "default" // 默认请求类型
}
result, err := service.CID.GenerateCID(ctx, req)
if err != nil {
return nil, err
}
return result, nil
}
// GetCIDHistory 获取CID历史记录
func (c *cid) GetCIDHistory(ctx context.Context, req *dto.GetCIDHistoryReq) (res *dto.GetCIDHistoryRes, err error) {
if req == nil {
return nil, gerror.New("请求参数不能为空")
}
// 查询历史记录
history, err := service.CID.GetCIDHistory(ctx, 1, req.Page, req.Size) // 临时使用固定用户ID
if err != nil {
return nil, err
}
return history, nil
}
@@ -0,0 +1,47 @@
package data
import (
dto "cid/model/dto/data"
service "cid/service/data"
"context"
"gitea.com/red-future/common/beans"
)
type apiInterfaceController struct{}
// ApiInterface 接口控制器
var ApiInterface = new(apiInterfaceController)
// CreateApiInterface 创建接口
func (c *apiInterfaceController) CreateApiInterface(ctx context.Context, req *dto.CreateApiInterfaceReq) (res *dto.CreateApiInterfaceRes, err error) {
return service.ApiInterface.Create(ctx, req)
}
// ListApiInterface 获取接口列表
func (c *apiInterfaceController) ListApiInterface(ctx context.Context, req *dto.ListApiInterfaceReq) (res *dto.ListApiInterfaceRes, err error) {
return service.ApiInterface.List(ctx, req)
}
// GetApiInterface 获取接口详情
func (c *apiInterfaceController) GetApiInterface(ctx context.Context, req *dto.GetApiInterfaceReq) (res *dto.GetApiInterfaceRes, err error) {
return service.ApiInterface.GetOne(ctx, req)
}
// UpdateApiInterface 更新接口
func (c *apiInterfaceController) UpdateApiInterface(ctx context.Context, req *dto.UpdateApiInterfaceReq) (res *beans.ResponseEmpty, err error) {
err = service.ApiInterface.Update(ctx, req)
return
}
// UpdateApiInterfaceStatus 更新接口状态
func (c *apiInterfaceController) UpdateApiInterfaceStatus(ctx context.Context, req *dto.UpdateApiInterfaceStatusReq) (res *beans.ResponseEmpty, err error) {
err = service.ApiInterface.UpdateStatus(ctx, req)
return
}
// DeleteApiInterface 删除接口
func (c *apiInterfaceController) DeleteApiInterface(ctx context.Context, req *dto.DeleteApiInterfaceReq) (res *beans.ResponseEmpty, err error) {
err = service.ApiInterface.Delete(ctx, req)
return
}
+37
View File
@@ -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)
}
+47
View File
@@ -0,0 +1,47 @@
package data
import (
dto "cid/model/dto/data"
service "cid/service/data"
"context"
"gitea.com/red-future/common/beans"
)
type platformController struct{}
// Platform 平台控制器
var Platform = new(platformController)
// CreatePlatform 创建平台
func (c *platformController) CreatePlatform(ctx context.Context, req *dto.CreatePlatformReq) (res *dto.CreatePlatformRes, err error) {
return service.Platform.Create(ctx, req)
}
// ListPlatform 获取平台列表
func (c *platformController) ListPlatform(ctx context.Context, req *dto.ListPlatformReq) (res *dto.ListPlatformRes, err error) {
return service.Platform.List(ctx, req)
}
// GetPlatform 获取平台详情
func (c *platformController) GetPlatform(ctx context.Context, req *dto.GetPlatformReq) (res *dto.GetPlatformRes, err error) {
return service.Platform.GetOne(ctx, req)
}
// UpdatePlatform 更新平台
func (c *platformController) UpdatePlatform(ctx context.Context, req *dto.UpdatePlatformReq) (res *beans.ResponseEmpty, err error) {
err = service.Platform.Update(ctx, req)
return
}
// UpdatePlatformStatus 更新平台状态
func (c *platformController) UpdatePlatformStatus(ctx context.Context, req *dto.UpdatePlatformStatusReq) (res *beans.ResponseEmpty, err error) {
err = service.Platform.UpdateStatus(ctx, req)
return
}
// DeletePlatform 删除平台
func (c *platformController) DeletePlatform(ctx context.Context, req *dto.DeletePlatformReq) (res *beans.ResponseEmpty, err error) {
err = service.Platform.Delete(ctx, req)
return
}
@@ -0,0 +1,51 @@
package mapping
import (
dto "cid/model/dto/mapping"
service "cid/service/mapping"
"context"
"gitea.com/red-future/common/beans"
)
type dataMappingController struct{}
// DataMapping 数据映射控制器
var DataMapping = new(dataMappingController)
// CreateDataMapping 创建数据映射
func (c *dataMappingController) CreateDataMapping(ctx context.Context, req *dto.CreateDataMappingReq) (res *dto.CreateDataMappingRes, err error) {
return service.DataMapping.Create(ctx, req)
}
// BatchCreateDataMappings 批量创建数据映射
func (c *dataMappingController) BatchCreateDataMappings(ctx context.Context, req *dto.BatchCreateDataMappingReq) (res *dto.BatchCreateDataMappingRes, err error) {
return service.DataMapping.BatchCreate(ctx, req)
}
// ListDataMapping 获取数据映射列表
func (c *dataMappingController) ListDataMapping(ctx context.Context, req *dto.ListDataMappingReq) (res *dto.ListDataMappingRes, err error) {
return service.DataMapping.List(ctx, req)
}
// GetDataMapping 获取数据映射详情
func (c *dataMappingController) GetDataMapping(ctx context.Context, req *dto.GetDataMappingReq) (res *dto.GetDataMappingRes, err error) {
return service.DataMapping.GetOne(ctx, req)
}
// UpdateDataMapping 更新数据映射
func (c *dataMappingController) UpdateDataMapping(ctx context.Context, req *dto.UpdateDataMappingReq) (res *beans.ResponseEmpty, err error) {
err = service.DataMapping.Update(ctx, req)
return
}
// DeleteDataMapping 删除数据映射
func (c *dataMappingController) DeleteDataMapping(ctx context.Context, req *dto.DeleteDataMappingReq) (res *beans.ResponseEmpty, err error) {
err = service.DataMapping.Delete(ctx, req)
return
}
// ExecuteDataMapping 执行数据映射
func (c *dataMappingController) ExecuteDataMapping(ctx context.Context, req *dto.ExecuteDataMappingReq) (res *dto.ExecuteDataMappingRes, err error) {
return service.DataMapping.Execute(ctx, req)
}
-37
View File
@@ -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
}
-77
View File
@@ -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)
}
-126
View File
@@ -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
}
-84
View File
@@ -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
}
-235
View File
@@ -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
}
-280
View File
@@ -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
}
+117
View File
@@ -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
}
-102
View File
@@ -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
}
-63
View File
@@ -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
}
+118
View File
@@ -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
}
+135
View File
@@ -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()
}
+115
View File
@@ -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
}
+138
View File
@@ -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()
}
-88
View File
@@ -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
}
+2 -1
View File
@@ -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
+13 -10
View File
@@ -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=
+13 -10
View File
@@ -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 {}
}
-231
View File
@@ -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"` // 排除的关键词
}
-149
View File
@@ -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"`
}
-185
View File
@@ -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"` // 删除是否成功
}
-117
View File
@@ -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"` // 点击率
}
-117
View File
@@ -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"` // 广告状态:启用、禁用
}
-167
View File
@@ -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"` // 授信额度(分)
}
+95
View File
@@ -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停用"`
}
-157
View File
@@ -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"`
}
-70
View File
@@ -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"` // 租户级别
}
+102
View File
@@ -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停用"`
}
+99
View File
@@ -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:"消息"`
}
+91
View File
@@ -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停用"`
}
+125
View File
@@ -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:"应用的映射规则"`
}
-35
View File
@@ -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"` // 使用率百分比
}
-89
View File
@@ -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"` // 是否成功
}
-68
View File
@@ -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
}
-57
View File
@@ -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
}
-85
View File
@@ -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
}
-74
View File
@@ -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
}
-44
View File
@@ -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"` // 备注
}
-55
View File
@@ -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
}
-53
View File
@@ -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
}
+49
View File
@@ -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",
}
-32
View File
@@ -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
}
-54
View File
@@ -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 IDiOS应用)
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
}
-251
View File
@@ -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"` // 平均出价(分)
}
+56
View File
@@ -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",
}
+58
View File
@@ -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",
}
+46
View File
@@ -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",
}
+52
View File
@@ -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",
}
-71
View File
@@ -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
}
-28
View File
@@ -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
}
-68
View File
@@ -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-60表示星期日
StartTime string `bson:"startTime" json:"startTime"` // 开始时间,格式:HH:mm
EndTime string `bson:"endTime" json:"endTime"` // 结束时间,格式:HH:mm
Timezone string `bson:"timezone" json:"timezone"` // 时区
}
-167
View File
@@ -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
}
-107
View File
@@ -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)
}
-81
View File
@@ -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
}
-178
View File
@@ -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
}
+178
View File
@@ -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)
}
-236
View File
@@ -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
}
-377
View File
@@ -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
}
+191
View File
@@ -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)
}
+316
View File
@@ -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)
}
+189
View File
@@ -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)
}
+306
View File
@@ -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)
}
-136
View File
@@ -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
}
-224
View File
@@ -1,224 +0,0 @@
package service
import (
"cid/dao"
"cid/model/dto"
"cid/model/entity"
"context"
"encoding/json"
"strconv"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
)
type strategy struct{}
// Strategy 策略服务
var Strategy = new(strategy)
// CreateStrategy 创建策略
func (s *strategy) CreateStrategy(ctx context.Context, req *dto.CreateStrategyReq) (id int64, err error) {
// 检查策略名称是否已存在
existingStrategy, err := dao.Strategy.GetByName(ctx, req.Name)
if err != nil {
return 0, err
}
if existingStrategy != nil {
return 0, gerror.New("策略名称已存在")
}
// 验证转化率范围
if req.MaxConversion <= req.MinConversion {
return 0, gerror.New("最高转化率必须大于最低转化率")
}
// 序列化权重配置
weightsJson, err := json.Marshal(req.SourceWeights)
if err != nil {
return 0, gerror.Wrap(err, "权重配置序列化失败")
}
strategy := &entity.Strategy{
Name: req.Name,
Description: req.Description,
MinConversion: req.MinConversion,
MaxConversion: req.MaxConversion,
SourceWeights: string(weightsJson),
MaxAdsPerReq: req.MaxAdsPerReq,
Priority: req.Priority,
}
// 设置状态
strategy.Status = req.Status
_, err = dao.Strategy.Create(ctx, strategy)
if err != nil {
return 0, err
}
// MongoDB使用ObjectId,创建成功后返回成功状态
return 1, nil
}
// UpdateStrategy 更新策略
func (s *strategy) UpdateStrategy(ctx context.Context, req *dto.UpdateStrategyReq) (affected int64, err error) {
// 检查策略是否存在
existingStrategy, err := dao.Strategy.GetByID(ctx, strconv.FormatInt(req.Id, 10))
if err != nil {
return 0, err
}
if existingStrategy == nil {
return 0, gerror.New("策略不存在")
}
// 如果更新名称,检查是否与其他策略冲突
if req.Name != "" && req.Name != existingStrategy.Name {
conflictStrategy, err := dao.Strategy.GetByName(ctx, req.Name)
if err != nil {
return 0, err
}
if conflictStrategy != nil {
return 0, gerror.New("策略名称已存在")
}
}
// 验证转化率范围
if req.MaxConversion <= req.MinConversion {
return 0, gerror.New("最高转化率必须大于最低转化率")
}
// 序列化权重配置
weightsJson, err := json.Marshal(req.SourceWeights)
if err != nil {
return 0, gerror.Wrap(err, "权重配置序列化失败")
}
strategy := &entity.Strategy{
Name: req.Name,
Description: req.Description,
MinConversion: req.MinConversion,
MaxConversion: req.MaxConversion,
SourceWeights: string(weightsJson),
MaxAdsPerReq: req.MaxAdsPerReq,
Priority: req.Priority,
}
// 设置状态
strategy.Status = req.Status
return dao.Strategy.Update(ctx, strategy)
}
// DeleteStrategy 删除策略
func (s *strategy) DeleteStrategy(ctx context.Context, id int64) (affected int64, err error) {
// 检查策略是否存在
existingStrategy, err := dao.Strategy.GetByID(ctx, strconv.FormatInt(id, 10))
if err != nil {
return 0, err
}
if existingStrategy == nil {
return 0, gerror.New("策略不存在")
}
return dao.Strategy.Delete(ctx, strconv.FormatInt(id, 10))
}
// GetStrategyByID 根据ID获取策略
func (s *strategy) GetStrategyByID(ctx context.Context, id int64) (strategy *dto.StrategyRes, err error) {
entity, err := dao.Strategy.GetByID(ctx, strconv.FormatInt(id, 10))
if err != nil {
return nil, err
}
if entity == nil {
return nil, gerror.New("策略不存在")
}
// 反序列化权重配置
var weights map[string]int
if entity.SourceWeights != "" {
err = json.Unmarshal([]byte(entity.SourceWeights), &weights)
if err != nil {
return nil, gerror.Wrap(err, "权重配置反序列化失败")
}
}
// 将ObjectId的十六进制字符串转换为int64,如果失败则使用0
var idInt64 int64
if id, err := strconv.ParseInt(entity.Id.Hex(), 16, 64); err == nil {
idInt64 = id
}
return &dto.StrategyRes{
Id: idInt64,
Name: entity.Name,
Description: entity.Description,
TenantLevel: "", // Strategy实体中没有TenantLevel字段,暂时设为空字符串
MinConversion: entity.MinConversion,
MaxConversion: entity.MaxConversion,
SourceWeights: weights,
MaxAdsPerReq: entity.MaxAdsPerReq,
Priority: entity.Priority,
Status: entity.Status,
CreatedAt: entity.CreatedAt.String(),
UpdatedAt: entity.UpdatedAt.String(),
CreatedBy: 0, // 这些字段在MongoBaseDO中不存在,暂时设为0
UpdatedBy: 0,
}, nil
}
// GetStrategyList 获取策略列表
func (s *strategy) GetStrategyList(ctx context.Context, req *dto.GetStrategyListReq) (res *dto.GetStrategyListRes, err error) {
list, total, err := dao.Strategy.GetList(ctx, req.Page, req.Size, req.TenantLevel, req.Status)
if err != nil {
return nil, err
}
var strategyList []*dto.StrategyRes
for _, entity := range list {
// 反序列化权重配置
var weights map[string]int
if entity.SourceWeights != "" {
err = json.Unmarshal([]byte(entity.SourceWeights), &weights)
if err != nil {
g.Log().Warningf(ctx, "策略 %d 权重配置反序列化失败: %v", entity.Id, err)
weights = make(map[string]int)
}
}
// 将ObjectId的十六进制字符串转换为int64,如果失败则使用0
var idInt64 int64
if id, err := strconv.ParseInt(entity.Id.Hex(), 16, 64); err == nil {
idInt64 = id
}
strategyList = append(strategyList, &dto.StrategyRes{
Id: idInt64,
Name: entity.Name,
Description: entity.Description,
TenantLevel: "", // Strategy实体中没有TenantLevel字段,暂时设为空字符串
MinConversion: entity.MinConversion,
MaxConversion: entity.MaxConversion,
SourceWeights: weights,
MaxAdsPerReq: entity.MaxAdsPerReq,
Priority: entity.Priority,
Status: entity.Status,
CreatedAt: entity.CreatedAt.String(),
UpdatedAt: entity.UpdatedAt.String(),
CreatedBy: 0, // 这些字段在MongoBaseDO中不存在,暂时设为0
UpdatedBy: 0,
})
}
return &dto.GetStrategyListRes{
List: strategyList,
Total: total,
Page: req.Page,
Size: req.Size,
}, nil
}
// GetStrategyByTenantLevel 根据租户级别获取策略
func (s *strategy) GetStrategyByTenantLevel(ctx context.Context, tenantLevel string) (strategy *entity.Strategy, err error) {
return dao.Strategy.GetByTenantLevel(ctx, tenantLevel)
}
+129 -1
View File
@@ -1 +1,129 @@
-----------张斌2025-06-16 15:00:00--------------
-- CID数据库表结构
-- 应用管理表
CREATE TABLE IF NOT EXISTS cid_application (
id BIGSERIAL PRIMARY KEY,
tenant_id VARCHAR(64) DEFAULT '',
name VARCHAR(255) NOT NULL COMMENT '应用名称',
app_code VARCHAR(100) NOT NULL COMMENT '应用编码(唯一标识)',
type VARCHAR(50) NOT NULL COMMENT '应用类型',
status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '应用状态:active启用/inactive停用',
description TEXT COMMENT '应用描述',
access_config JSONB COMMENT '接入配置',
limit_config JSONB COMMENT '限流配置',
callback_config JSONB COMMENT '回调配置',
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
deleted_at BIGINT DEFAULT 0,
CONSTRAINT uk_cid_application_app_code UNIQUE (app_code, deleted_at)
);
CREATE INDEX idx_cid_application_tenant ON cid_application(tenant_id);
CREATE INDEX idx_cid_application_type ON cid_application(type);
CREATE INDEX idx_cid_application_status ON cid_application(status);
CREATE INDEX idx_cid_application_name ON cid_application(name);
CREATE INDEX idx_cid_application_app_code ON cid_application(app_code);
-- 平台管理表
CREATE TABLE IF NOT EXISTS cid_platform (
id BIGSERIAL PRIMARY KEY,
tenant_id VARCHAR(64) DEFAULT '',
name VARCHAR(255) NOT NULL COMMENT '平台名称',
type VARCHAR(50) NOT NULL COMMENT '平台类型',
status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '平台状态:active启用/inactive停用',
description TEXT COMMENT '平台描述',
auth_config JSONB COMMENT '认证配置',
limit_config JSONB COMMENT '限流配置',
platform_config JSONB COMMENT '平台专用配置',
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
deleted_at BIGINT DEFAULT 0
);
CREATE INDEX idx_cid_platform_tenant ON cid_platform(tenant_id);
CREATE INDEX idx_cid_platform_type ON cid_platform(type);
CREATE INDEX idx_cid_platform_status ON cid_platform(status);
CREATE INDEX idx_cid_platform_name ON cid_platform(name);
-- 接口管理表
CREATE TABLE IF NOT EXISTS cid_api_interface (
id BIGSERIAL PRIMARY KEY,
tenant_id VARCHAR(64) DEFAULT '',
platform_id BIGINT NOT NULL COMMENT '所属平台ID',
name VARCHAR(255) NOT NULL COMMENT '接口名称',
code VARCHAR(100) NOT NULL COMMENT '接口编码',
url VARCHAR(500) NOT NULL COMMENT '接口地址',
method VARCHAR(10) NOT NULL COMMENT '请求方法:GET/POST/PUT/DELETE等',
status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '接口状态:active启用/inactive停用',
auth_type VARCHAR(50) COMMENT '认证类型:oauth2/apikey/basic等',
request_config JSONB COMMENT '请求配置',
response_config JSONB COMMENT '响应配置',
limit_config JSONB COMMENT '接口独立限流配置(可选,覆盖平台配置)',
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
deleted_at BIGINT DEFAULT 0,
CONSTRAINT fk_cid_api_interface_platform FOREIGN KEY (platform_id) REFERENCES cid_platform(id)
);
CREATE INDEX idx_cid_api_interface_tenant ON cid_api_interface(tenant_id);
CREATE INDEX idx_cid_api_interface_platform ON cid_api_interface(platform_id);
CREATE INDEX idx_cid_api_interface_code ON cid_api_interface(code);
CREATE INDEX idx_cid_api_interface_status ON cid_api_interface(status);
CREATE INDEX idx_cid_api_interface_name ON cid_api_interface(name);
-- 数据获取日志表
CREATE TABLE IF NOT EXISTS cid_data_fetch_log (
id BIGSERIAL PRIMARY KEY,
tenant_id VARCHAR(64) DEFAULT '',
platform_id BIGINT NOT NULL COMMENT '平台ID',
interface_id BIGINT NOT NULL COMMENT '接口ID',
request_id VARCHAR(100) NOT NULL COMMENT '请求ID',
status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '执行状态:pending/running/success/failed/rate_limit',
start_time BIGINT NOT NULL COMMENT '开始时间(时间戳)',
end_time BIGINT DEFAULT 0 COMMENT '结束时间(时间戳)',
duration INT DEFAULT 0 COMMENT '执行时长(毫秒)',
request_config JSONB COMMENT '请求配置参数',
response_data TEXT COMMENT '响应数据(JSON',
error_message TEXT COMMENT '错误信息',
retry_count INT DEFAULT 0 COMMENT '重试次数',
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
deleted_at BIGINT DEFAULT 0,
CONSTRAINT fk_cid_data_fetch_log_platform FOREIGN KEY (platform_id) REFERENCES cid_platform(id),
CONSTRAINT fk_cid_data_fetch_log_interface FOREIGN KEY (interface_id) REFERENCES cid_api_interface(id)
);
CREATE INDEX idx_cid_data_fetch_log_tenant ON cid_data_fetch_log(tenant_id);
CREATE INDEX idx_cid_data_fetch_log_platform ON cid_data_fetch_log(platform_id);
CREATE INDEX idx_cid_data_fetch_log_interface ON cid_data_fetch_log(interface_id);
CREATE INDEX idx_cid_data_fetch_log_request_id ON cid_data_fetch_log(request_id);
CREATE INDEX idx_cid_data_fetch_log_status ON cid_data_fetch_log(status);
CREATE INDEX idx_cid_data_fetch_log_start_time ON cid_data_fetch_log(start_time);
-- 数据映射表
CREATE TABLE IF NOT EXISTS cid_data_mapping (
id BIGSERIAL PRIMARY KEY,
tenant_id VARCHAR(64) DEFAULT '',
platform_id BIGINT NOT NULL COMMENT '平台ID',
interface_id BIGINT NOT NULL COMMENT '接口ID',
source_field VARCHAR(255) NOT NULL COMMENT '源字段(接口返回字段)',
target_field VARCHAR(255) NOT NULL COMMENT '目标字段(本地表字段)',
field_type VARCHAR(50) NOT NULL COMMENT '字段类型:string/int/float/bool/array/object',
default_value VARCHAR(500) COMMENT '默认值',
transform_rule JSONB COMMENT '转换规则',
priority INT DEFAULT 0 COMMENT '优先级(数字越小优先级越高)',
status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '状态:active启用/inactive停用',
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
deleted_at BIGINT DEFAULT 0,
CONSTRAINT fk_cid_data_mapping_platform FOREIGN KEY (platform_id) REFERENCES cid_platform(id),
CONSTRAINT fk_cid_data_mapping_interface FOREIGN KEY (interface_id) REFERENCES cid_api_interface(id),
CONSTRAINT uk_cid_data_mapping_interface_target UNIQUE (interface_id, target_field, deleted_at)
);
CREATE INDEX idx_cid_data_mapping_tenant ON cid_data_mapping(tenant_id);
CREATE INDEX idx_cid_data_mapping_platform ON cid_data_mapping(platform_id);
CREATE INDEX idx_cid_data_mapping_interface ON cid_data_mapping(interface_id);
CREATE INDEX idx_cid_data_mapping_source_field ON cid_data_mapping(source_field);
CREATE INDEX idx_cid_data_mapping_status ON cid_data_mapping(status);
CREATE INDEX idx_cid_data_mapping_priority ON cid_data_mapping(priority);