Compare commits

...

18 Commits

Author SHA1 Message Date
lmk
e1c0981bf9 Merge remote-tracking branch 'origin/dev' into dev 2026-04-10 10:28:43 +08:00
lmk
9e2167d843 bug修复 2026-04-10 10:28:30 +08:00
b6f9a832c0 增加dockerfile配置 2026-04-09 16:14:31 +08:00
lmk
ee713c5c0f 补偿机制任务协程处理 2026-04-09 15:16:43 +08:00
lmk
eb5e0af308 修复补偿机制的日志表缺失的问题 2026-04-09 13:43:15 +08:00
lmk
5797fbb43e 修改包名 2026-04-09 10:48:30 +08:00
lmk
556ec5075e 补偿数据逻辑调整 2026-04-09 09:48:22 +08:00
lmk
5d72dd3aff 抽取数据添加协程逻辑调整 2026-04-08 17:26:00 +08:00
lmk
000ea03420 抽取数据添加协程 2026-04-08 16:00:54 +08:00
lmk
073a098317 补偿逻辑修改 2026-04-08 14:30:09 +08:00
lmk
a25bba717f 抽取数据逻辑修复+ 2026-04-08 14:05:15 +08:00
lmk
5f2c9c3855 抽取数据添加补偿机制 2026-04-08 09:03:20 +08:00
lmk
14db0dd2fe Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	go.sum
2026-04-07 09:57:31 +08:00
lmk
5b8a4c103d 定时任务抽取数据 2026-04-07 09:57:11 +08:00
lmk
4f3ad39eeb 定时任务抽取数据 2026-04-07 09:51:32 +08:00
c8162b1bfe golang版本升级1.26.0 2026-04-03 11:30:12 +08:00
2c6a8490b8 golang版本升级1.26.0 2026-04-03 11:15:09 +08:00
lmk
41089cca2d 批量新增 获取广告计划数据 2026-04-02 17:02:47 +08:00
34 changed files with 5491 additions and 26 deletions

View File

@@ -1,4 +1,4 @@
FROM golang:1.25.3
FROM golang:1.26.0
RUN go env -w GO111MODULE=on
RUN go env -w GOPROXY=https://goproxy.cn,direct
ENV WORKDIR /usr/local/bin/app

View File

@@ -14,6 +14,9 @@ const (
StorewideReportDetailTable = "storewide_report_detail" // 全站数据detail表
CreativeReportSumTable = "creative_report_sum" // 广告创意数据sum表
CreativeReportDetailTable = "creative_report_detail" // 广告创意数据detail表
UnitReportSumTable = "unit_report_sum" // 广告创意数据detail表
UnitReportDetailTable = "unit_report_detail" // 广告创意数据detail表
UnitReportSumTable = "unit_report_sum" // 广告单元数据detail表
UnitReportDetailTable = "unit_report_detail" // 广告单元数据detail表
CampaignReportSumTable = "campaign_report_sum" // 广告计划数据detail表
CampaignReportDetailTable = "campaign_report_detail" // 广告计划数据detail表
SyncTaskLogTable = "sync_task_log" // 广告计划数据detail表
)

View File

@@ -0,0 +1,35 @@
package copydata
import (
dto "cid/model/dto/copydata"
service "cid/service/copydata"
"context"
"gitea.com/red-future/common/beans"
)
type campaignReport struct{}
var CampaignReport = new(campaignReport)
// CreateCampaignReportSum 创建广告计划效果指标表
func (c *campaignReport) CreateCampaignReportSum(ctx context.Context, req *dto.CreateCampaignReportSumReq) (res *dto.CreateCampaignReportSumRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
return service.CampaignReportSum.Create(ctx, req.CampaignReportSumItem)
}
// BatchCreateCampaignReportSum 批量创建广告计划效果指标表
func (c *campaignReport) BatchCreateCampaignReportSum(ctx context.Context, req *dto.BatchCreateCampaignReportSumReq) (res *dto.BatchCreateCampaignReportSumRes, err error) {
return service.CampaignReportSum.BatchCreate(ctx, req)
}
// CreateCampaignReportDetail 创建广告效果指标表
func (c *campaignReport) CreateCampaignReportDetail(ctx context.Context, req *dto.CreateCampaignReportDetailReq) (res *dto.CreateCampaignReportDetailRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
return service.CampaignReportSum.CreateDetail(ctx, req.CampaignReportDetailItem)
}
// BatchCreateCampaignReportDetail 批量创建广告效果指标表
func (c *campaignReport) BatchCreateCampaignReportDetail(ctx context.Context, req *dto.BatchCreateCampaignReportDetailReq) (res *dto.BatchCreateCampaignReportDetailRes, err error) {
return service.CampaignReportSum.BatchCreateDetail(ctx, req)
}

View File

@@ -9,6 +9,7 @@ import (
"gitea.com/red-future/common/db/gfdb"
"github.com/gogf/gf/v2/util/gconv"
"github.com/sirupsen/logrus"
)
var CidAccountReportDetail = new(cidAccountReportDetailDao)
@@ -29,7 +30,7 @@ func (d *cidAccountReportDetailDao) Insert(ctx context.Context, req *dto.CidAcco
return r.LastInsertId()
}
// BatchInsert 批量插入广告数据报表详情
// BatchInsert 批量插入广告数据报表详情(使用 OnConflict 实现幂等性)
func (d *cidAccountReportDetailDao) BatchInsert(ctx context.Context, reqs []*dto.CidAccountReportDetailItem) (successCount int64, failCount int64, failedIndexes []int64, err error) {
if len(reqs) == 0 {
return 0, 0, nil, errors.New("批量插入数据不能为空")
@@ -64,9 +65,19 @@ func (d *cidAccountReportDetailDao) BatchInsert(ctx context.Context, reqs []*dto
continue
}
// 执行批量插入
_, err = gfdb.DB(ctx).Model(ctx, consts.CidAccountReportDetailTable).Data(entityList).Insert()
// 执行批量插入,使用 OnConflict 实现幂等性
_, err = gfdb.DB(ctx).Model(ctx, consts.CidAccountReportDetailTable).
Data(entityList).
OnConflict(
"report_date_str",
"page_number",
"campaign_id",
"creative_id",
).
Save()
if err != nil {
logrus.Warnf("批量插入失败,尝试逐条插入: %v", err)
// 批量插入失败,尝试逐条插入
for k := range batch {
_, singleErr := d.Insert(ctx, batch[k])
@@ -84,3 +95,66 @@ func (d *cidAccountReportDetailDao) BatchInsert(ctx context.Context, reqs []*dto
return successCount, failCount, failedIndexes, nil
}
// DeleteByDateRange 按日期范围删除数据(用于补偿前去重)
func (d *cidAccountReportDetailDao) DeleteByDateRange(ctx context.Context, advertiserID int64, startDateStr, endDateStr string) (int64, error) {
cols := (&entity.CidAccountReportDetail{}).GetCols()
result, err := gfdb.DB(ctx).Model(ctx, consts.CidAccountReportDetailTable).
Where(cols.ReportDateStr+" >= ? AND "+cols.ReportDateStr+" <= ?", startDateStr, endDateStr).
Delete()
if err != nil {
return 0, err
}
affected, _ := result.RowsAffected()
return affected, nil
}
// BatchInsertInTx 在事务中批量插入
func (d *cidAccountReportDetailDao) BatchInsertInTx(ctx context.Context, tx interface{}, reqs []*dto.CidAccountReportDetailItem) (successCount int64, failCount int64, err error) {
if len(reqs) == 0 {
return 0, 0, errors.New("批量插入数据不能为空")
}
batchSize := 100
successCount = 0
failCount = 0
for i := 0; i < len(reqs); i += batchSize {
end := i + batchSize
if end > len(reqs) {
end = len(reqs)
}
batch := reqs[i:end]
entityList := make([]*entity.CidAccountReportDetail, 0, len(batch))
for _, req := range batch {
var entityData entity.CidAccountReportDetail
if err = gconv.Struct(req, &entityData); err != nil {
failCount++
logrus.Errorf("数据转换失败: %v", err)
continue
}
entityList = append(entityList, &entityData)
}
if len(entityList) == 0 {
continue
}
_, txErr := gfdb.DB(ctx).Model(ctx, consts.CidAccountReportDetailTable).Data(entityList).Insert()
if txErr != nil {
logrus.Errorf("批量插入失败 batch[%d:%d]: %v", i, end, txErr)
failCount += int64(len(entityList))
err = txErr
continue
}
successCount += int64(len(entityList))
}
return successCount, failCount, err
}

View File

@@ -9,13 +9,14 @@ import (
"gitea.com/red-future/common/db/gfdb"
"github.com/gogf/gf/v2/util/gconv"
"github.com/sirupsen/logrus"
)
var CidAccountReportSum = new(CidAccountReportSumDao)
type CidAccountReportSumDao struct{}
// Insert 插入广告数据报表详情
// Insert 插入广告数据报表汇总
func (d *CidAccountReportSumDao) Insert(ctx context.Context, req *dto.CidAccountReportSumItem) (id int64, err error) {
var entityData *entity.CidAccountReportSum
if err = gconv.Struct(req, &entityData); err != nil {
@@ -29,7 +30,7 @@ func (d *CidAccountReportSumDao) Insert(ctx context.Context, req *dto.CidAccount
return r.LastInsertId()
}
// BatchInsert 批量插入广告数据报表详情
// BatchInsert 批量插入广告数据报表汇总(使用 OnConflict 实现幂等性)
func (d *CidAccountReportSumDao) BatchInsert(ctx context.Context, reqs []*dto.CidAccountReportSumItem) (successCount int64, failCount int64, failedIndexes []int64, err error) {
if len(reqs) == 0 {
return 0, 0, nil, errors.New("批量插入数据不能为空")
@@ -64,9 +65,19 @@ func (d *CidAccountReportSumDao) BatchInsert(ctx context.Context, reqs []*dto.Ci
continue
}
// 执行批量插入
_, err = gfdb.DB(ctx).Model(ctx, consts.CidAccountReportSumTable).Data(entityList).Insert()
// 执行批量插入,使用 OnConflict 实现幂等性
_, err = gfdb.DB(ctx).Model(ctx, consts.CidAccountReportSumTable).
Data(entityList).
OnConflict(
"report_date_str",
"page_number",
"campaign_id",
"creative_id",
).
Save()
if err != nil {
logrus.Warnf("批量插入失败,尝试逐条插入: %v", err)
// 批量插入失败,尝试逐条插入
for k := range batch {
_, singleErr := d.Insert(ctx, batch[k])
@@ -84,3 +95,19 @@ func (d *CidAccountReportSumDao) BatchInsert(ctx context.Context, reqs []*dto.Ci
return successCount, failCount, failedIndexes, nil
}
// DeleteByDateRange 按日期范围删除数据(用于补偿前去重)
func (d *CidAccountReportSumDao) DeleteByDateRange(ctx context.Context, advertiserID int64, startDateStr, endDateStr string) (int64, error) {
cols := (&entity.CidAccountReportSum{}).GetCols()
result, err := gfdb.DB(ctx).Model(ctx, consts.CidAccountReportSumTable).
Where(cols.ReportDateStr+" >= ? AND "+cols.ReportDateStr+" <= ?", startDateStr, endDateStr).
Delete()
if err != nil {
return 0, err
}
affected, _ := result.RowsAffected()
return affected, nil
}

View File

@@ -0,0 +1,81 @@
package copydata
import (
consts "cid/consts/public"
dto "cid/model/dto/copydata"
entity "cid/model/entity/copydata"
"context"
"errors"
"gitea.com/red-future/common/db/gfdb"
"github.com/gogf/gf/v2/util/gconv"
)
var CampaignReportDetail = new(CampaignReportDetailDao)
type CampaignReportDetailDao struct{}
func (d *CampaignReportDetailDao) Insert(ctx context.Context, req *dto.CampaignReportDetailItem) (id int64, err error) {
var entityData *entity.CampaignReportDetail
if err = gconv.Struct(req, &entityData); err != nil {
return
}
r, err := gfdb.DB(ctx).Model(ctx, consts.CampaignReportDetailTable).Data(&entityData).Insert()
if err != nil {
return
}
return r.LastInsertId()
}
func (d *CampaignReportDetailDao) BatchInsert(ctx context.Context, reqs []*dto.CampaignReportDetailItem) (successCount int64, failCount int64, failedIndexes []int64, err error) {
if len(reqs) == 0 {
return 0, 0, nil, errors.New("批量插入数据不能为空")
}
batchSize := 100
successCount = 0
failCount = 0
failedIndexes = make([]int64, 0)
for i := 0; i < len(reqs); i += batchSize {
end := i + batchSize
if end > len(reqs) {
end = len(reqs)
}
batch := reqs[i:end]
entityList := make([]*entity.CampaignReportDetail, len(batch))
for j, req := range batch {
var entityData entity.CampaignReportDetail
if err = gconv.Struct(req, &entityData); err != nil {
failCount++
failedIndexes = append(failedIndexes, int64(i+j))
continue
}
entityList[j] = &entityData
}
if len(entityList) == 0 {
continue
}
_, err = gfdb.DB(ctx).Model(ctx, consts.CampaignReportDetailTable).Data(entityList).Insert()
if err != nil {
for k := range batch {
_, singleErr := d.Insert(ctx, batch[k])
if singleErr != nil {
failCount++
failedIndexes = append(failedIndexes, int64(i+k))
} else {
successCount++
}
}
} else {
successCount += int64(len(entityList))
}
}
return successCount, failCount, failedIndexes, nil
}

View File

@@ -0,0 +1,86 @@
package copydata
import (
consts "cid/consts/public"
dto "cid/model/dto/copydata"
entity "cid/model/entity/copydata"
"context"
"errors"
"gitea.com/red-future/common/db/gfdb"
"github.com/gogf/gf/v2/util/gconv"
)
var CampaignReportSum = new(CampaignReportSumDao)
type CampaignReportSumDao struct{}
// Insert 插入广告计划效果指标表
func (d *CampaignReportSumDao) Insert(ctx context.Context, req *dto.CampaignReportSumItem) (id int64, err error) {
var entityData *entity.CampaignReportSum
if err = gconv.Struct(req, &entityData); err != nil {
return
}
r, err := gfdb.DB(ctx).Model(ctx, consts.CampaignReportSumTable).Data(&entityData).Insert()
if err != nil {
return
}
return r.LastInsertId()
}
// BatchInsert 批量插入广告计划效果指标表
func (d *CampaignReportSumDao) BatchInsert(ctx context.Context, reqs []*dto.CampaignReportSumItem) (successCount int64, failCount int64, failedIndexes []int64, err error) {
if len(reqs) == 0 {
return 0, 0, nil, errors.New("批量插入数据不能为空")
}
// 分批处理,每批 100 条
batchSize := 100
successCount = 0
failCount = 0
failedIndexes = make([]int64, 0)
for i := 0; i < len(reqs); i += batchSize {
end := i + batchSize
if end > len(reqs) {
end = len(reqs)
}
batch := reqs[i:end]
entityList := make([]*entity.CampaignReportSum, len(batch))
for j, req := range batch {
var entityData entity.CampaignReportSum
if err = gconv.Struct(req, &entityData); err != nil {
failCount++
failedIndexes = append(failedIndexes, int64(i+j))
continue
}
entityList[j] = &entityData
}
if len(entityList) == 0 {
continue
}
// 执行批量插入
_, err = gfdb.DB(ctx).Model(ctx, consts.CampaignReportSumTable).Data(entityList).Insert()
if err != nil {
// 批量插入失败,尝试逐条插入
for k := range batch {
_, singleErr := d.Insert(ctx, batch[k])
if singleErr != nil {
failCount++
failedIndexes = append(failedIndexes, int64(i+k))
} else {
successCount++
}
}
} else {
successCount += int64(len(entityList))
}
}
return successCount, failCount, failedIndexes, nil
}

View File

@@ -0,0 +1,168 @@
package copydata
import (
consts "cid/consts/public"
dto "cid/model/dto/copydata"
entity "cid/model/entity/copydata"
"context"
"time"
"gitea.com/red-future/common/db/gfdb"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/util/gconv"
"github.com/sirupsen/logrus"
)
var SyncTaskLog = new(SyncTaskLogDao)
type SyncTaskLogDao struct{}
// Create 创建任务日志如果task_id已存在则返回现有ID
func (d *SyncTaskLogDao) Create(ctx context.Context, req *dto.CreateSyncTaskLogReq) (int64, error) {
existingTask, err := d.GetByTaskID(ctx, req.TaskID, req.TaskType)
if err == nil && existingTask != nil {
logrus.Debugf("任务日志已存在task_id=%s, task_type=%s, id=%d", req.TaskID, req.TaskType, existingTask.Id)
return existingTask.Id, nil
}
data := map[string]interface{}{
"task_id": req.TaskID,
"task_type": req.TaskType,
"advertiser_id": req.AdvertiserID,
"start_time": req.StartTime,
"end_time": req.EndTime,
"status": req.Status,
"max_retry": req.MaxRetry,
"page_info": req.PageInfo,
"request_params": req.RequestParams,
"retry_count": 0,
"duration_ms": 0,
}
r, err := gfdb.DB(ctx).Model(ctx, consts.SyncTaskLogTable).Data(data).Insert()
if err != nil {
return 0, err
}
return r.LastInsertId()
}
// Update 更新任务日志
func (d *SyncTaskLogDao) Update(ctx context.Context, req *dto.UpdateSyncTaskLogReq) error {
data := make(gdb.Map)
if req.Status != "" {
data["status"] = req.Status
}
if req.RetryCount != nil {
data["retry_count"] = *req.RetryCount
}
if req.ErrorMessage != "" {
data["error_message"] = req.ErrorMessage
}
if req.ErrorCode != "" {
data["error_code"] = req.ErrorCode
}
if req.ResultSummary != nil {
data["result_summary"] = req.ResultSummary
}
if req.NextRetryTime != nil {
data["next_retry_time"] = req.NextRetryTime
}
if req.CompletedAt != nil {
data["completed_at"] = req.CompletedAt
}
if req.DurationMs != nil {
data["duration_ms"] = *req.DurationMs
}
data["updated_at"] = time.Now()
_, err := gfdb.DB(ctx).Model(ctx, consts.SyncTaskLogTable).
Data(data).
Where("id", req.ID).
Update()
return err
}
// QueryFailedTasks 查询需要补偿的失败任务
func (d *SyncTaskLogDao) QueryFailedTasks(ctx context.Context, req *dto.QueryFailedTasksReq) ([]*dto.SyncTaskLogItem, error) {
model := gfdb.DB(ctx).Model(ctx, consts.SyncTaskLogTable).Model
// 状态过滤
if len(req.Status) > 0 {
model = model.WhereIn("status", req.Status)
}
// 任务类型过滤
if req.TaskType != "" {
model = model.Where("task_type", req.TaskType)
}
// 只查询到达重试时间的任务(或从未设置过重试时间)
model = model.Where(
"(next_retry_time <= ? OR next_retry_time IS NULL)",
time.Now(),
)
// 限制数量
limit := req.Limit
if limit <= 0 {
limit = 100
}
model = model.Limit(limit)
var results []*entity.SyncTaskLog
if err := model.Scan(&results); err != nil {
return nil, err
}
items := make([]*dto.SyncTaskLogItem, len(results))
for i, r := range results {
item := &dto.SyncTaskLogItem{}
gconv.Struct(r, item)
items[i] = item
}
return items, nil
}
// GetByTaskID 根据任务ID获取日志
func (d *SyncTaskLogDao) GetByTaskID(ctx context.Context, taskID, taskType string) (*entity.SyncTaskLog, error) {
var result *entity.SyncTaskLog
err := gfdb.DB(ctx).Model(ctx, consts.SyncTaskLogTable).
Where("task_id", taskID).
Where("task_type", taskType).
Scan(&result)
if err != nil {
return nil, err
}
return result, nil
}
// QueryAllPageTasksByParentID 根据主任务ID查询所有分页任务
func (d *SyncTaskLogDao) QueryAllPageTasksByParentID(ctx context.Context, parentTaskID string, limit int) ([]*dto.SyncTaskLogItem, error) {
if limit <= 0 {
limit = 1000
}
model := gfdb.DB(ctx).Model(ctx, consts.SyncTaskLogTable).Model
model = model.Where("task_type", "account_report_page")
model = model.WhereLike("task_id", parentTaskID+"_page_%")
model = model.Limit(limit)
var results []*entity.SyncTaskLog
if err := model.Scan(&results); err != nil {
return nil, err
}
items := make([]*dto.SyncTaskLogItem, len(results))
for i, r := range results {
item := &dto.SyncTaskLogItem{}
gconv.Struct(r, item)
items[i] = item
}
return items, nil
}

7
go.mod
View File

@@ -1,6 +1,6 @@
module cid
go 1.25.5
go 1.26.0
require (
gitea.com/red-future/common v0.0.4
@@ -8,10 +8,11 @@ require (
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.5
github.com/gogf/gf/v2 v2.10.0
github.com/olekukonko/errors v1.1.0
github.com/sirupsen/logrus v1.9.3
golang.org/x/net v0.47.0
)
//replace gitea.com/red-future/common => ../common
replace gitea.com/red-future/common => ../common
require (
github.com/BurntSushi/toml v1.5.0 // indirect
@@ -80,7 +81,7 @@ require (
go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
golang.org/x/crypto v0.44.0 // indirect
golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae // indirect
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/text v0.31.0 // indirect

473
go.sum Normal file
View File

@@ -0,0 +1,473 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
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=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
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=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs=
github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak=
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=
github.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0 h1:39+jbTenm7KBj4hO2C8ANAxVHpX/7OuRDs1VcGC9ylA=
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0/go.mod h1:B0s0fVzn0W220E8UTpSGzrrGKsop5KcB90twBeLCiz0=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.5 h1:Ku7p3CvGchxC7zPSgArf/tZs2w9Yb8tS/gH5ADN+p9g=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.5/go.mod h1:cjy18NsSLZQf5zaLAzuo7B2gr8GGjCTWDTEPY7T+6FI=
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 h1:eUqwJ/qNH8lJ6yssiqskazgp1ACQuNU6zXlLOZVuXTQ=
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5/go.mod h1:sjQyMry9+0POYZCA6lHXBxO77WoNKkruJpRB4xKqk5k=
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 h1:tHUEZYB5GTqEYYVDYnlGobf1xISARKDE4KHVlgjwTec=
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5/go.mod h1:cfzTn2HS9RDX8f5pUVkbGxUWcSosouqfNQ1G6cY0V88=
github.com/gogf/gf/v2 v2.10.0 h1:rzDROlyqGMe/eM6dCalSR8dZOuMIdLhmxKSH1DGhbFs=
github.com/gogf/gf/v2 v2.10.0/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I=
github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
github.com/hashicorp/consul/api v1.26.1 h1:5oSXOO5fboPZeW5SN+TdGFP/BILDgBm19OrPZ/pICIM=
github.com/hashicorp/consul/api v1.26.1/go.mod h1:B4sQTeaSO16NtynqrAdwOlahJ7IUDZM9cj2420xYL8A=
github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU=
github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
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 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=
github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
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/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=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg=
github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tiger1103/gfast-token v1.0.10 h1:fNiBE/Dq5iTHvTGlCx3DmXa2o4hr0NtumFpffZ39k6s=
github.com/tiger1103/gfast-token v1.0.10/go.mod h1:a/21mxmj7zFeNvjhZSC0XpEAFHfb1aT2k6DXnufFU1s=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
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.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=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
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-20250128144449-3edf0e91c1ae h1:COZdc9Ut6wLq7MO9GIYxfZl4n4ScmgqQLoHocKXrxco=
golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
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=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
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=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
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=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -4,6 +4,7 @@ import (
"cid/controller/copydata"
"cid/controller/dict"
_ "gitea.com/red-future/common/config"
"gitea.com/red-future/common/http"
"gitea.com/red-future/common/jaeger"
_ "gitea.com/red-future/common/ragflow" // RAGFlow 客户端自动初始化
@@ -28,6 +29,7 @@ func main() {
copydata.StorewideReport,
copydata.CreativeReport,
copydata.UnitReport,
copydata.CampaignReport,
})
select {}
}

View File

@@ -282,6 +282,9 @@ type CidAccountReportDetailItem struct {
// 时间字段
ReportDateStr string `json:"reportDateStr" v:"required" dc:"时间"`
// 分页字段
PageNumber int `json:"pageNumber" dc:"页码"`
// 广告结构字段
CampaignId *int64 `json:"campaignId" dc:"计划ID"`
CampaignName string `json:"campaignName" dc:"计划名称"`

View File

@@ -282,6 +282,9 @@ type CidAccountReportSumItem struct {
// 时间字段
ReportDateStr string `json:"reportDateStr" v:"required" dc:"时间"`
// 分页字段
PageNumber int `json:"pageNumber" dc:"页码"`
// 广告结构字段
CampaignId *int64 `json:"campaignId" dc:"计划ID"`
CampaignName string `json:"campaignName" dc:"计划名称"`

View File

@@ -0,0 +1,230 @@
package copydata
import (
"gitea.com/red-future/common/beans"
"github.com/gogf/gf/v2/frame/g"
)
type CreateCampaignReportDetailReq struct {
g.Meta `path:"/createCampaignReportDetail" method:"post" tags:"广告效果明细报表" summary:"创建广告效果指标明细表" dc:"创建新的广告效果指标明细表"`
*CampaignReportDetailItem
}
type CreateCampaignReportDetailRes struct {
Id int64 `json:"id" dc:"广告效果明细 ID"`
}
type BatchCreateCampaignReportDetailReq struct {
g.Meta `path:"/batchCreateCampaignReportDetail" method:"post" tags:"广告效果明细报表" summary:"批量创建广告效果指标明细表" dc:"批量创建广告效果指标明细表"`
Items []*CampaignReportDetailItem `json:"items" v:"required" dc:"广告效果明细列表"`
}
type BatchCreateCampaignReportDetailRes struct {
SuccessCount int64 `json:"successCount" dc:"成功数量"`
FailCount int64 `json:"failCount" dc:"失败数量"`
FailedItems []int64 `json:"failedItems" dc:"失败项索引"`
}
type CampaignReportDetailItem struct {
T0OrderPaymentAmt *float64 `json:"t0OrderPaymentAmt" dc:"当日总成交订单金额"`
CreativeMaterialType string `json:"creativeMaterialType" dc:"视频素材类型"`
LiveName string `json:"liveName" dc:"直播间名称"`
AuthorId string `json:"authorId" dc:"直播用户快手 Id"`
PicUrl string `json:"picUrl" dc:"图片 URL"`
PicName string `json:"picName" dc:"图片名称"`
PicId string `json:"picId" dc:"图片 Id"`
CoverUrl string `json:"coverUrl" dc:"封面 URL"`
CoverId *int64 `json:"coverId" dc:"封面 Id"`
ItemOrderConversionRatio *float64 `json:"itemOrderConversionRatio" dc:"转化率"`
ItemCardClickRatio *float64 `json:"itemCardClickRatio" dc:"点击率"`
ItemCardClkCnt *int64 `json:"itemCardClkCnt" dc:"商品卡点击数"`
LivePlayCntCost *float64 `json:"livePlayCntCost" dc:"直播间观看成本"`
AdMerchantFollowCost *float64 `json:"adMerchantFollowCost" dc:"涨粉成本"`
AdMerchantFollow *int64 `json:"adMerchantFollow" dc:"涨粉数"`
NetT0OrderCnt *int64 `json:"netT0OrderCnt" dc:"当日累计净成交订单数"`
NetT0Roi *float64 `json:"netT0Roi" dc:"净成交 ROI"`
NetT0Gmv *float64 `json:"netT0Gmv" dc:"净成交 GMV"`
PhotoName string `json:"photoName" dc:"视频名称"`
PhotoIdStr string `json:"photoIdStr" dc:"视频 id"`
PhotoId string `json:"photoId" dc:"视频 id"`
ModPriceSegment string `json:"modPriceSegment" dc:"设备价格区间"`
AgeSegment string `json:"ageSegment" dc:"年龄段"`
Province string `json:"province" dc:"省份名称"`
Gender string `json:"gender" dc:"性别"`
AdPhotoPlayedFiveRatio *float64 `json:"adPhotoPlayedFiveRatio" dc:"作品 5 秒播放率"`
AdPhotoPlayedThreeRatio *float64 `json:"adPhotoPlayedThreeRatio" dc:"作品 3 秒播放率"`
OrderSubmitRoi *float64 `json:"orderSubmitRoi" dc:"订单提交 ROI"`
OrderSubmitAmt *int64 `json:"orderSubmitAmt" dc:"外部订单金额"`
EventOrderSubmitCost *float64 `json:"eventOrderSubmitCost" dc:"订单提交成本"`
EventOrderSubmit *int64 `json:"eventOrderSubmit" dc:"订单提交数"`
EventOrderPaidRoi *float64 `json:"eventOrderPaidRoi" dc:"订单支付率"`
EventAppInvoked *int64 `json:"eventAppInvoked" dc:"唤起应用数"`
EventAddShoppingCart *int64 `json:"eventAddShoppingCart" dc:"添加购物车次数"`
ConversionNumCost *float64 `json:"conversionNumCost" dc:"转化成本(回传时间)"`
AdEffectivePlayNum *int64 `json:"adEffectivePlayNum" dc:"有效播放数"`
AdItemClick *int64 `json:"adItemClick" dc:"行为数"`
MerchantProductId string `json:"merchantProductId" dc:"商品 ID"`
CostTotal *float64 `json:"costTotal" dc:"花费"`
AdShow *int64 `json:"adShow" dc:"曝光数"`
AdShow1kCost *float64 `json:"adShow1kCost" dc:"平均千次广告曝光花费"`
Impression *int64 `json:"impression" dc:"封面曝光数"`
PhotoClick *int64 `json:"photoClick" dc:"封面点击数"`
PhotoClickRatio *float64 `json:"photoClickRatio" dc:"封面点击率"`
Click *int64 `json:"click" dc:"素材曝光数"`
ActionbarClick *int64 `json:"actionbarClick" dc:"行为数"`
ActionbarClickCost *float64 `json:"actionbarClickCost" dc:"行为成本"`
EspClickRatio *float64 `json:"espClickRatio" dc:"行为率"`
ActionRatio *float64 `json:"actionRatio" dc:"素材点击率"`
AdItemClickCount *int64 `json:"adItemClickCount" dc:"预约组件点击数"`
EspLivePlayedSeconds *int64 `json:"espLivePlayedSeconds" dc:"直播平均观看时长"`
PlayedThreeSeconds *int64 `json:"playedThreeSeconds" dc:"作品 3 秒播放数"`
Play3sRatio *float64 `json:"play3sRatio" dc:"作品 3 秒播放率"`
PlayedFiveSeconds *int64 `json:"playedFiveSeconds" dc:"作品 5 秒播放数"`
Play5sRatio *float64 `json:"play5sRatio" dc:"作品 5 秒播放率"`
PlayedEnd *int64 `json:"playedEnd" dc:"作品完播数"`
PlayEndRatio *float64 `json:"playEndRatio" dc:"作品完播率"`
Share *int64 `json:"share" dc:"作品分享数"`
Comment *int64 `json:"comment" dc:"作品评论数"`
Likes *int64 `json:"likes" dc:"作品点赞数"`
Report *int64 `json:"report" dc:"作品举报数"`
Block *int64 `json:"block" dc:"作品拉黑数"`
ItemNegative *int64 `json:"itemNegative" dc:"详情页减少此类作品数"`
LiveShare *int64 `json:"liveShare" dc:"直播送礼数"`
LiveComment *int64 `json:"liveComment" dc:"直播评论数"`
LiveReward *int64 `json:"liveReward" dc:"直播送礼数"`
EffectivePlayCount *int64 `json:"effectivePlayCount" dc:"有效播放数"`
EffectivePlayRatio *float64 `json:"effectivePlayRatio" dc:"有效播放率"`
ConversionNum *int64 `json:"conversionNum" dc:"转化数"`
ConversionCostEsp *float64 `json:"conversionCostEsp" dc:"转化成本"`
Roi *float64 `json:"roi" dc:"直接 ROI"`
Gmv *float64 `json:"gmv" dc:"直接 GMV"`
T0Gmv *float64 `json:"t0Gmv" dc:"当日累计 GMV"`
T1Gmv *float64 `json:"t1Gmv" dc:"次日累计 GMV"`
T7Gmv *float64 `json:"t7Gmv" dc:"7 日累计 GMV"`
T15Gmv *float64 `json:"t15Gmv" dc:"15 日累计 GMV"`
T30Gmv *float64 `json:"t30Gmv" dc:"30 日累计 GMV"`
T0Roi *float64 `json:"t0Roi" dc:"当日累计 ROI"`
T1Roi *float64 `json:"t1Roi" dc:"次日累计 ROI"`
T7Roi *float64 `json:"t7Roi" dc:"7 日累计 ROI"`
T15Roi *float64 `json:"t15Roi" dc:"15 日累计 ROI"`
T30Roi *float64 `json:"t30Roi" dc:"30 日累计 ROI"`
PaiedOrder *int64 `json:"paiedOrder" dc:"直接订单数"`
OrderRatio *float64 `json:"orderRatio" dc:"直接下单率"`
T0OrderCnt *int64 `json:"t0OrderCnt" dc:"当日累计订单数"`
T0OrderCntCost *float64 `json:"t0OrderCntCost" dc:"当日累计订单成本"`
T0OrderCntRatio *float64 `json:"t0OrderCntRatio" dc:"累计订单下单率"`
T1OrderCnt *int64 `json:"t1OrderCnt" dc:"次日累计订单数"`
T7OrderCnt *int64 `json:"t7OrderCnt" dc:"7 日累计订单数"`
T15OrderCnt *int64 `json:"t15OrderCnt" dc:"15 日累计订单数"`
T30OrderCnt *int64 `json:"t30OrderCnt" dc:"30 日累计订单数"`
MerchantRecoFans *int64 `json:"merchantRecoFans" dc:"涨粉数"`
T1Retention *float64 `json:"t1Retention" dc:"次日涨粉留存数"`
T7Retention *float64 `json:"t7Retention" dc:"7 日涨粉留存数"`
T15Retention *float64 `json:"t15Retention" dc:"15 日涨粉留存数"`
T30Retention *float64 `json:"t30Retention" dc:"30 日涨粉留存数"`
T1RetentionRatio *float64 `json:"t1RetentionRatio" dc:"次日涨粉留存率"`
T7RetentionRatio *float64 `json:"t7RetentionRatio" dc:"7 日涨粉留存率"`
T15RetentionRatio *float64 `json:"t15RetentionRatio" dc:"15 日涨粉留存率"`
T30RetentionRatio *float64 `json:"t30RetentionRatio" dc:"30 日涨粉留存率"`
ReservationSuccess *int64 `json:"reservationSuccess" dc:"直播预约成功数"`
ReservationCost *float64 `json:"reservationCost" dc:"直播预约成功成本"`
StandardLivePlayedStarted *int64 `json:"standardLivePlayedStarted" dc:"直播观看数"`
AdLivePlayCnt *int64 `json:"adLivePlayCnt" dc:"直播间人气数"`
AdLivePlayCntCost *float64 `json:"adLivePlayCntCost" dc:"直播间人气成本"`
LiveAudienceCost *float64 `json:"liveAudienceCost" dc:"直播观看成本"`
LiveEventGoodsView *int64 `json:"liveEventGoodsView" dc:"直播间商品点击数"`
GoodsClickRatio *float64 `json:"goodsClickRatio" dc:"直播间商品点击率"`
DirectAttrPlatNewBuyerCnt *int64 `json:"directAttrPlatNewBuyerCnt" dc:"直接平台新客"`
T30AttrPlatTotalBuyerCnt *int64 `json:"t30AttrPlatTotalBuyerCnt" dc:"30 日累计平台新客"`
DirectAttrSellerNewBuyerCnt *int64 `json:"directAttrSellerNewBuyerCnt" dc:"直接店铺新客"`
T30AttrSellerTotalBuyerCnt *int64 `json:"t30AttrSellerTotalBuyerCnt" dc:"30 日累计店铺新客"`
T3Gmv *float64 `json:"t3Gmv" dc:"3 日累计 GMV"`
T3OrderCnt *int64 `json:"t3OrderCnt" dc:"3 日累计订单数"`
T3Roi *float64 `json:"t3Roi" dc:"3 日累计 ROI"`
T7IndirectOrderAmt *float64 `json:"t7IndirectOrderAmt" dc:"7 日间接订单金额"`
T7IndirectOrderCnt *int64 `json:"t7IndirectOrderCnt" dc:"7 日间接订单数"`
FansT0GmvPerFans *float64 `json:"fansT0GmvPerFans" dc:"新增粉丝人均销售额"`
FansT3GmvPerFans *float64 `json:"fansT3GmvPerFans" dc:"3 日新增粉丝人均销售额"`
FansT7GmvPerFans *float64 `json:"fansT7GmvPerFans" dc:"7 日新增粉丝人均销售额"`
FansT15GmvPerFans *float64 `json:"fansT15GmvPerFans" dc:"15 日新增粉丝人均销售额"`
FansT30GmvPerFans *float64 `json:"fansT30GmvPerFans" dc:"30 日新增粉丝人均销售额"`
RecoFansCost *float64 `json:"recoFansCost" dc:"涨粉成本"`
QcpxWhiteboxDirectOrderPaymentAmt *float64 `json:"qcpxWhiteboxDirectOrderPaymentAmt" dc:"智能优惠券订单 GMV"`
QcpxWhiteboxDirectOrderCnt *int64 `json:"qcpxWhiteboxDirectOrderCnt" dc:"智能优惠券订单数"`
FansT0Gmv *float64 `json:"fansT0Gmv" dc:"涨粉当日 GMV"`
FansT1Gmv *float64 `json:"fansT1Gmv" dc:"涨粉次日 GMV"`
FansT7Gmv *float64 `json:"fansT7Gmv" dc:"涨粉 7 日 GMV"`
FansT15Gmv *float64 `json:"fansT15Gmv" dc:"涨粉 15 日 GMV"`
FansT30Gmv *float64 `json:"fansT30Gmv" dc:"涨粉 30 日 GMV"`
FansT0Roi *float64 `json:"fansT0Roi" dc:"涨粉当日 ROI"`
FansT1Roi *float64 `json:"fansT1Roi" dc:"涨粉次日 ROI"`
FansT7Roi *float64 `json:"fansT7Roi" dc:"涨粉 7 日 ROI"`
FansT15Roi *float64 `json:"fansT15Roi" dc:"涨粉 15 日 ROI"`
FansT30Roi *float64 `json:"fansT30Roi" dc:"涨粉 30 日 ROI"`
T0ShopNewBuyerOrderPaymentAmt *float64 `json:"t0ShopNewBuyerOrderPaymentAmt" dc:"当日新客 GMV"`
T1ShopNewBuyerOrderPaymentAmt *float64 `json:"t1ShopNewBuyerOrderPaymentAmt" dc:"投后 1 日新客 GMV"`
T3ShopNewBuyerOrderPaymentAmt *float64 `json:"t3ShopNewBuyerOrderPaymentAmt" dc:"投后 3 日新客 GMV"`
T7ShopNewBuyerOrderPaymentAmt *float64 `json:"t7ShopNewBuyerOrderPaymentAmt" dc:"投后 7 日新客 GMV"`
T15ShopNewBuyerOrderPaymentAmt *float64 `json:"t15ShopNewBuyerOrderPaymentAmt" dc:"投后 15 日新客 GMV"`
T30ShopNewBuyerOrderPaymentAmt *float64 `json:"t30ShopNewBuyerOrderPaymentAmt" dc:"投后 30 日新客 GMV"`
T0ShopNewBuyerOrderCnt *int64 `json:"t0ShopNewBuyerOrderCnt" dc:"当日新客成交订单量"`
T1ShopNewBuyerOrderCnt *int64 `json:"t1ShopNewBuyerOrderCnt" dc:"投后 1 日新客成交订单量"`
T3ShopNewBuyerOrderCnt *int64 `json:"t3ShopNewBuyerOrderCnt" dc:"投后 3 日新客成交订单量"`
T7ShopNewBuyerOrderCnt *int64 `json:"t7ShopNewBuyerOrderCnt" dc:"投后 7 日新客成交订单量"`
T15ShopNewBuyerOrderCnt *int64 `json:"t15ShopNewBuyerOrderCnt" dc:"投后 15 日新客成交订单量"`
T30ShopNewBuyerOrderCnt *int64 `json:"t30ShopNewBuyerOrderCnt" dc:"投后 30 日新客成交订单量"`
T1NewBuyerRepurchaseRatio *float64 `json:"t1NewBuyerRepurchaseRatio" dc:"投后 1 日新客复购率"`
T3NewBuyerRepurchaseRatio *float64 `json:"t3NewBuyerRepurchaseRatio" dc:"投后 3 日新客复购率"`
T7NewBuyerRepurchaseRatio *float64 `json:"t7NewBuyerRepurchaseRatio" dc:"投后 7 日新客复购率"`
T15NewBuyerRepurchaseRatio *float64 `json:"t15NewBuyerRepurchaseRatio" dc:"投后 15 日新客复购率"`
T30NewBuyerRepurchaseRatio *float64 `json:"t30NewBuyerRepurchaseRatio" dc:"投后 30 日新客复购率"`
T0ShopNewBuyerRoi *float64 `json:"t0ShopNewBuyerRoi" dc:"投后当日新客 ROI"`
T1ShopNewBuyerRoi *float64 `json:"t1ShopNewBuyerRoi" dc:"投后 1 日新客 ROI"`
T3ShopNewBuyerRoi *float64 `json:"t3ShopNewBuyerRoi" dc:"投后 3 日新客 ROI"`
T7ShopNewBuyerRoi *float64 `json:"t7ShopNewBuyerRoi" dc:"投后 7 日新客 ROI"`
T15ShopNewBuyerRoi *float64 `json:"t15ShopNewBuyerRoi" dc:"投后 15 日新客 ROI"`
T30ShopNewBuyerRoi *float64 `json:"t30ShopNewBuyerRoi" dc:"投后 30 日新客 ROI"`
CreateCardOrderCnt *int64 `json:"createCardOrderCnt" dc:"有效制卡订单数(回传时间)"`
ForwardTsCreateCardOrderCnt *int64 `json:"forwardTsCreateCardOrderCnt" dc:"有效制卡订单数(计费时间)"`
CreateCardOrderCost *float64 `json:"createCardOrderCost" dc:"有效制卡订单成本(回传时间)"`
ForwardTsCreateCardOrderCost *float64 `json:"forwardTsCreateCardOrderCost" dc:"有效制卡订单成本(计费时间)"`
ActivateCardOrderCnt *int64 `json:"activateCardOrderCnt" dc:"电话卡激活订单数(回传时间)"`
ForwardTsActivateCardOrderCnt *int64 `json:"forwardTsActivateCardOrderCnt" dc:"电话卡激活订单数(计费时间)"`
ActivateCardOrderCost *float64 `json:"activateCardOrderCost" dc:"电话卡激活订单成本(回传时间)"`
ForwardTsActivateCardOrderCost *float64 `json:"forwardTsActivateCardOrderCost" dc:"电话卡激活订单成本(计费时间)"`
CreateCardOrderRatio *float64 `json:"createCardOrderRatio" dc:"有效制卡订单率(回传时间)"`
ForwardTsCreateCardOrderRatio *float64 `json:"forwardTsCreateCardOrderRatio" dc:"有效制卡订单率(计费时间)"`
ActivateCardOrderCntRatio *float64 `json:"activateCardOrderCntRatio" dc:"电话卡激活率(回传时间)"`
ForwardTsActivateCardOrderRatio *float64 `json:"forwardTsActivateCardOrderRatio" dc:"电话卡激活率(计费时间)"`
LivePlayCnt *int64 `json:"livePlayCnt" dc:"全站直播观看数"`
ItemEntranceClkCnt *int64 `json:"itemEntranceClkCnt" dc:"小黄车点击数"`
ShowCnt *int64 `json:"showCnt" dc:"全站曝光"`
ReportDateStr string `json:"reportDateStr" v:"required" dc:"时间"`
CampaignId *int64 `json:"campaignId" dc:"计划 ID"`
CampaignName string `json:"campaignName" dc:"计划名称"`
UnitId *int64 `json:"unitId" dc:"单元 ID"`
UnitName string `json:"unitName" dc:"单元名称"`
CreativeId *int64 `json:"creativeId" dc:"创意 ID"`
CreativeName string `json:"creativeName" dc:"创意名称"`
CidActualRoiAfterSubsidy *float64 `json:"cidActualRoiAfterSubsidy" dc:"补贴后实际 ROI"`
CidCouponAmount *int64 `json:"cidCouponAmount" dc:"核销券金额"`
CidCouponCallbackPaidRefundAmount *int64 `json:"cidCouponCallbackPaidRefundAmount" dc:"退单有回传_核销券金额"`
CidVoucherCost *float64 `json:"cidVoucherCost" dc:"券成本"`
}
type ListCampaignReportDetailReq struct {
g.Meta `path:"/listCampaignReportDetail" method:"get" tags:"广告效果明细报表" summary:"获取广告效果指标明细表列表" dc:"分页查询广告效果指标明细表列表"`
*beans.Page
ReportDateStr string `json:"reportDateStr" dc:"时间"`
CampaignId *int64 `json:"campaignId" dc:"计划 ID"`
UnitId *int64 `json:"unitId" dc:"单元 ID"`
CreativeId *int64 `json:"creativeId" dc:"创意 ID"`
AuthorId string `json:"authorId" dc:"直播用户快手 Id"`
MerchantProductId string `json:"merchantProductId" dc:"商品 ID"`
Keyword string `json:"keyword" dc:"关键字"`
}
type ListCampaignReportDetailRes struct {
List []*CampaignReportDetailItem `json:"list" dc:"广告效果明细列表"`
Total int `json:"total" dc:"总数"`
}

View File

@@ -0,0 +1,237 @@
package copydata
import (
"gitea.com/red-future/common/beans"
"github.com/gogf/gf/v2/frame/g"
)
// CreateCampaignReportSumReq 创建广告计划效果指标表请求
type CreateCampaignReportSumReq struct {
g.Meta `path:"/createCampaignReportSum" method:"post" tags:"广告计划报表" summary:"创建广告计划效果指标表" dc:"创建新的广告计划效果指标表"`
*CampaignReportSumItem
}
// CreateCampaignReportSumRes 创建广告计划效果指标表响应
type CreateCampaignReportSumRes struct {
Id int64 `json:"id" dc:"广告计划效果 ID"`
}
// BatchCreateCampaignReportSumReq 批量创建广告计划效果指标表请求
type BatchCreateCampaignReportSumReq struct {
g.Meta `path:"/batchCreateCampaignReportSum" method:"post" tags:"广告计划报表" summary:"批量创建广告计划效果指标表" dc:"批量创建广告计划效果指标表"`
Items []*CampaignReportSumItem `json:"items" v:"required" dc:"广告计划效果列表"`
}
// BatchCreateCampaignReportSumRes 批量创建广告计划效果指标表响应
type BatchCreateCampaignReportSumRes struct {
SuccessCount int64 `json:"successCount" dc:"成功数量"`
FailCount int64 `json:"failCount" dc:"失败数量"`
FailedItems []int64 `json:"failedItems" dc:"失败项索引"`
}
// CampaignReportSumItem 广告计划效果指标表项
type CampaignReportSumItem struct {
T0OrderPaymentAmt *float64 `json:"t0OrderPaymentAmt" dc:"当日总成交订单金额"`
CreativeMaterialType string `json:"creativeMaterialType" dc:"视频素材类型视频HORIZONTAL_SCREEN, VERTICAL_SCREEN, UNKNOWN_TYPE图集ATLAS长图ATLAS_VERTICAL"`
LiveName string `json:"liveName" dc:"直播间名称"`
AuthorId string `json:"authorId" dc:"直播用户快手 Id"`
PicUrl string `json:"picUrl" dc:"图片 URL"`
PicName string `json:"picName" dc:"图片名称"`
PicId string `json:"picId" dc:"图片 Id"`
CoverUrl string `json:"coverUrl" dc:"封面 URL"`
CoverId *int64 `json:"coverId" dc:"封面 Id"`
ItemOrderConversionRatio *float64 `json:"itemOrderConversionRatio" dc:"转化率"`
ItemCardClickRatio *float64 `json:"itemCardClickRatio" dc:"点击率"`
ItemCardClkCnt *int64 `json:"itemCardClkCnt" dc:"商品卡点击数"`
LivePlayCntCost *float64 `json:"livePlayCntCost" dc:"直播间观看成本"`
AdMerchantFollowCost *float64 `json:"adMerchantFollowCost" dc:"涨粉成本"`
AdMerchantFollow *int64 `json:"adMerchantFollow" dc:"涨粉数"`
NetT0OrderCnt *int64 `json:"netT0OrderCnt" dc:"当日累计净成交订单数"`
NetT0Roi *float64 `json:"netT0Roi" dc:"净成交 ROI"`
NetT0Gmv *float64 `json:"netT0Gmv" dc:"净成交 GMV"`
PhotoName string `json:"photoName" dc:"视频名称"`
PhotoIdStr string `json:"photoIdStr" dc:"视频 id"`
PhotoId string `json:"photoId" dc:"视频 id"`
ModPriceSegment string `json:"modPriceSegment" dc:"设备价格区间"`
AgeSegment string `json:"ageSegment" dc:"年龄段"`
Province string `json:"province" dc:"省份名称"`
Gender string `json:"gender" dc:"性别"`
AdPhotoPlayedFiveRatio *float64 `json:"adPhotoPlayedFiveRatio" dc:"作品 5 秒播放率"`
AdPhotoPlayedThreeRatio *float64 `json:"adPhotoPlayedThreeRatio" dc:"作品 3 秒播放率"`
OrderSubmitRoi *float64 `json:"orderSubmitRoi" dc:"订单提交 ROI"`
OrderSubmitAmt *int64 `json:"orderSubmitAmt" dc:"外部订单金额"`
EventOrderSubmitCost *float64 `json:"eventOrderSubmitCost" dc:"订单提交成本"`
EventOrderSubmit *int64 `json:"eventOrderSubmit" dc:"订单提交数"`
EventOrderPaidRoi *float64 `json:"eventOrderPaidRoi" dc:"订单支付率"`
EventAppInvoked *int64 `json:"eventAppInvoked" dc:"唤起应用数"`
EventAddShoppingCart *int64 `json:"eventAddShoppingCart" dc:"添加购物车次数"`
ConversionNumCost *float64 `json:"conversionNumCost" dc:"转化成本(回传时间)"`
AdEffectivePlayNum *int64 `json:"adEffectivePlayNum" dc:"有效播放数"`
AdItemClick *int64 `json:"adItemClick" dc:"行为数"`
MerchantProductId string `json:"merchantProductId" dc:"商品 ID"`
CostTotal *float64 `json:"costTotal" dc:"花费"`
AdShow *int64 `json:"adShow" dc:"曝光数"`
AdShow1kCost *float64 `json:"adShow1kCost" dc:"平均千次广告曝光花费"`
Impression *int64 `json:"impression" dc:"封面曝光数"`
PhotoClick *int64 `json:"photoClick" dc:"封面点击数"`
PhotoClickRatio *float64 `json:"photoClickRatio" dc:"封面点击率"`
Click *int64 `json:"click" dc:"素材曝光数"`
ActionbarClick *int64 `json:"actionbarClick" dc:"行为数"`
ActionbarClickCost *float64 `json:"actionbarClickCost" dc:"行为成本"`
EspClickRatio *float64 `json:"espClickRatio" dc:"行为率"`
ActionRatio *float64 `json:"actionRatio" dc:"素材点击率"`
AdItemClickCount *int64 `json:"adItemClickCount" dc:"预约组件点击数"`
EspLivePlayedSeconds *int64 `json:"espLivePlayedSeconds" dc:"直播平均观看时长"`
PlayedThreeSeconds *int64 `json:"playedThreeSeconds" dc:"作品 3 秒播放数"`
Play3sRatio *float64 `json:"play3sRatio" dc:"作品 3 秒播放率"`
PlayedFiveSeconds *int64 `json:"playedFiveSeconds" dc:"作品 5 秒播放数"`
Play5sRatio *float64 `json:"play5sRatio" dc:"作品 5 秒播放率"`
PlayedEnd *int64 `json:"playedEnd" dc:"作品完播数"`
PlayEndRatio *float64 `json:"playEndRatio" dc:"作品完播率"`
Share *int64 `json:"share" dc:"作品分享数"`
Comment *int64 `json:"comment" dc:"作品评论数"`
Likes *int64 `json:"likes" dc:"作品点赞数"`
Report *int64 `json:"report" dc:"作品举报数"`
Block *int64 `json:"block" dc:"作品拉黑数"`
ItemNegative *int64 `json:"itemNegative" dc:"详情页减少此类作品数"`
LiveShare *int64 `json:"liveShare" dc:"直播送礼数"`
LiveComment *int64 `json:"liveComment" dc:"直播评论数"`
LiveReward *int64 `json:"liveReward" dc:"直播送礼数"`
EffectivePlayCount *int64 `json:"effectivePlayCount" dc:"有效播放数"`
EffectivePlayRatio *float64 `json:"effectivePlayRatio" dc:"有效播放率"`
ConversionNum *int64 `json:"conversionNum" dc:"转化数"`
ConversionCostEsp *float64 `json:"conversionCostEsp" dc:"转化成本"`
Roi *float64 `json:"roi" dc:"直接 ROI"`
Gmv *float64 `json:"gmv" dc:"直接 GMV"`
T0Gmv *float64 `json:"t0Gmv" dc:"当日累计 GMV"`
T1Gmv *float64 `json:"t1Gmv" dc:"次日累计 GMV"`
T7Gmv *float64 `json:"t7Gmv" dc:"7 日累计 GMV"`
T15Gmv *float64 `json:"t15Gmv" dc:"15 日累计 GMV"`
T30Gmv *float64 `json:"t30Gmv" dc:"30 日累计 GMV"`
T0Roi *float64 `json:"t0Roi" dc:"当日累计 ROI"`
T1Roi *float64 `json:"t1Roi" dc:"次日累计 ROI"`
T7Roi *float64 `json:"t7Roi" dc:"7 日累计 ROI"`
T15Roi *float64 `json:"t15Roi" dc:"15 日累计 ROI"`
T30Roi *float64 `json:"t30Roi" dc:"30 日累计 ROI"`
PaiedOrder *int64 `json:"paiedOrder" dc:"直接订单数"`
OrderRatio *float64 `json:"orderRatio" dc:"直接下单率"`
T0OrderCnt *int64 `json:"t0OrderCnt" dc:"当日累计订单数"`
T0OrderCntCost *float64 `json:"t0OrderCntCost" dc:"当日累计订单成本"`
T0OrderCntRatio *float64 `json:"t0OrderCntRatio" dc:"累计订单下单率"`
T1OrderCnt *int64 `json:"t1OrderCnt" dc:"次日累计订单数"`
T7OrderCnt *int64 `json:"t7OrderCnt" dc:"7 日累计订单数"`
T15OrderCnt *int64 `json:"t15OrderCnt" dc:"15 日累计订单数"`
T30OrderCnt *int64 `json:"t30OrderCnt" dc:"30 日累计订单数"`
MerchantRecoFans *int64 `json:"merchantRecoFans" dc:"涨粉数"`
T1Retention *float64 `json:"t1Retention" dc:"次日涨粉留存数"`
T7Retention *float64 `json:"t7Retention" dc:"7 日涨粉留存数"`
T15Retention *float64 `json:"t15Retention" dc:"15 日涨粉留存数"`
T30Retention *float64 `json:"t30Retention" dc:"30 日涨粉留存数"`
T1RetentionRatio *float64 `json:"t1RetentionRatio" dc:"次日涨粉留存率"`
T7RetentionRatio *float64 `json:"t7RetentionRatio" dc:"7 日涨粉留存率"`
T15RetentionRatio *float64 `json:"t15RetentionRatio" dc:"15 日涨粉留存率"`
T30RetentionRatio *float64 `json:"t30RetentionRatio" dc:"30 日涨粉留存率"`
ReservationSuccess *int64 `json:"reservationSuccess" dc:"直播预约成功数"`
ReservationCost *float64 `json:"reservationCost" dc:"直播预约成功成本"`
StandardLivePlayedStarted *int64 `json:"standardLivePlayedStarted" dc:"直播观看数"`
AdLivePlayCnt *int64 `json:"adLivePlayCnt" dc:"直播间人气数"`
AdLivePlayCntCost *float64 `json:"adLivePlayCntCost" dc:"直播间人气成本"`
LiveAudienceCost *float64 `json:"liveAudienceCost" dc:"直播观看成本"`
LiveEventGoodsView *int64 `json:"liveEventGoodsView" dc:"直播间商品点击数"`
GoodsClickRatio *float64 `json:"goodsClickRatio" dc:"直播间商品点击率"`
DirectAttrPlatNewBuyerCnt *int64 `json:"directAttrPlatNewBuyerCnt" dc:"直接平台新客"`
T30AttrPlatTotalBuyerCnt *int64 `json:"t30AttrPlatTotalBuyerCnt" dc:"30 日累计平台新客"`
DirectAttrSellerNewBuyerCnt *int64 `json:"directAttrSellerNewBuyerCnt" dc:"直接店铺新客"`
T30AttrSellerTotalBuyerCnt *int64 `json:"t30AttrSellerTotalBuyerCnt" dc:"30 日累计店铺新客"`
T3Gmv *float64 `json:"t3Gmv" dc:"3 日累计 GMV"`
T3OrderCnt *int64 `json:"t3OrderCnt" dc:"3 日累计订单数"`
T3Roi *float64 `json:"t3Roi" dc:"3 日累计 ROI"`
T7IndirectOrderAmt *float64 `json:"t7IndirectOrderAmt" dc:"7 日间接订单金额"`
T7IndirectOrderCnt *int64 `json:"t7IndirectOrderCnt" dc:"7 日间接订单数"`
FansT0GmvPerFans *float64 `json:"fansT0GmvPerFans" dc:"新增粉丝人均销售额"`
FansT3GmvPerFans *float64 `json:"fansT3GmvPerFans" dc:"3 日新增粉丝人均销售额"`
FansT7GmvPerFans *float64 `json:"fansT7GmvPerFans" dc:"7 日新增粉丝人均销售额"`
FansT15GmvPerFans *float64 `json:"fansT15GmvPerFans" dc:"15 日新增粉丝人均销售额"`
FansT30GmvPerFans *float64 `json:"fansT30GmvPerFans" dc:"30 日新增粉丝人均销售额"`
RecoFansCost *float64 `json:"recoFansCost" dc:"涨粉成本"`
QcpxWhiteboxDirectOrderPaymentAmt *float64 `json:"qcpxWhiteboxDirectOrderPaymentAmt" dc:"智能优惠券订单 GMV"`
QcpxWhiteboxDirectOrderCnt *int64 `json:"qcpxWhiteboxDirectOrderCnt" dc:"智能优惠券订单数"`
FansT0Gmv *float64 `json:"fansT0Gmv" dc:"涨粉当日 GMV"`
FansT1Gmv *float64 `json:"fansT1Gmv" dc:"涨粉次日 GMV"`
FansT7Gmv *float64 `json:"fansT7Gmv" dc:"涨粉 7 日 GMV"`
FansT15Gmv *float64 `json:"fansT15Gmv" dc:"涨粉 15 日 GMV"`
FansT30Gmv *float64 `json:"fansT30Gmv" dc:"涨粉 30 日 GMV"`
FansT0Roi *float64 `json:"fansT0Roi" dc:"涨粉当日 ROI"`
FansT1Roi *float64 `json:"fansT1Roi" dc:"涨粉次日 ROI"`
FansT7Roi *float64 `json:"fansT7Roi" dc:"涨粉 7 日 ROI"`
FansT15Roi *float64 `json:"fansT15Roi" dc:"涨粉 15 日 ROI"`
FansT30Roi *float64 `json:"fansT30Roi" dc:"涨粉 30 日 ROI"`
T0ShopNewBuyerOrderPaymentAmt *float64 `json:"t0ShopNewBuyerOrderPaymentAmt" dc:"当日新客 GMV"`
T1ShopNewBuyerOrderPaymentAmt *float64 `json:"t1ShopNewBuyerOrderPaymentAmt" dc:"投后 1 日新客 GMV"`
T3ShopNewBuyerOrderPaymentAmt *float64 `json:"t3ShopNewBuyerOrderPaymentAmt" dc:"投后 3 日新客 GMV"`
T7ShopNewBuyerOrderPaymentAmt *float64 `json:"t7ShopNewBuyerOrderPaymentAmt" dc:"投后 7 日新客 GMV"`
T15ShopNewBuyerOrderPaymentAmt *float64 `json:"t15ShopNewBuyerOrderPaymentAmt" dc:"投后 15 日新客 GMV"`
T30ShopNewBuyerOrderPaymentAmt *float64 `json:"t30ShopNewBuyerOrderPaymentAmt" dc:"投后 30 日新客 GMV"`
T0ShopNewBuyerOrderCnt *int64 `json:"t0ShopNewBuyerOrderCnt" dc:"当日新客成交订单量"`
T1ShopNewBuyerOrderCnt *int64 `json:"t1ShopNewBuyerOrderCnt" dc:"投后 1 日新客成交订单量"`
T3ShopNewBuyerOrderCnt *int64 `json:"t3ShopNewBuyerOrderCnt" dc:"投后 3 日新客成交订单量"`
T7ShopNewBuyerOrderCnt *int64 `json:"t7ShopNewBuyerOrderCnt" dc:"投后 7 日新客成交订单量"`
T15ShopNewBuyerOrderCnt *int64 `json:"t15ShopNewBuyerOrderCnt" dc:"投后 15 日新客成交订单量"`
T30ShopNewBuyerOrderCnt *int64 `json:"t30ShopNewBuyerOrderCnt" dc:"投后 30 日新客成交订单量"`
T1NewBuyerRepurchaseRatio *float64 `json:"t1NewBuyerRepurchaseRatio" dc:"投后 1 日新客复购率"`
T3NewBuyerRepurchaseRatio *float64 `json:"t3NewBuyerRepurchaseRatio" dc:"投后 3 日新客复购率"`
T7NewBuyerRepurchaseRatio *float64 `json:"t7NewBuyerRepurchaseRatio" dc:"投后 7 日新客复购率"`
T15NewBuyerRepurchaseRatio *float64 `json:"t15NewBuyerRepurchaseRatio" dc:"投后 15 日新客复购率"`
T30NewBuyerRepurchaseRatio *float64 `json:"t30NewBuyerRepurchaseRatio" dc:"投后 30 日新客复购率"`
T0ShopNewBuyerRoi *float64 `json:"t0ShopNewBuyerRoi" dc:"投后当日新客 ROI"`
T1ShopNewBuyerRoi *float64 `json:"t1ShopNewBuyerRoi" dc:"投后 1 日新客 ROI"`
T3ShopNewBuyerRoi *float64 `json:"t3ShopNewBuyerRoi" dc:"投后 3 日新客 ROI"`
T7ShopNewBuyerRoi *float64 `json:"t7ShopNewBuyerRoi" dc:"投后 7 日新客 ROI"`
T15ShopNewBuyerRoi *float64 `json:"t15ShopNewBuyerRoi" dc:"投后 15 日新客 ROI"`
T30ShopNewBuyerRoi *float64 `json:"t30ShopNewBuyerRoi" dc:"投后 30 日新客 ROI"`
CreateCardOrderCnt *int64 `json:"createCardOrderCnt" dc:"有效制卡订单数(回传时间)"`
ForwardTsCreateCardOrderCnt *int64 `json:"forwardTsCreateCardOrderCnt" dc:"有效制卡订单数(计费时间)"`
CreateCardOrderCost *float64 `json:"createCardOrderCost" dc:"有效制卡订单成本(回传时间)"`
ForwardTsCreateCardOrderCost *float64 `json:"forwardTsCreateCardOrderCost" dc:"有效制卡订单成本(计费时间)"`
ActivateCardOrderCnt *int64 `json:"activateCardOrderCnt" dc:"电话卡激活订单数(回传时间)"`
ForwardTsActivateCardOrderCnt *int64 `json:"forwardTsActivateCardOrderCnt" dc:"电话卡激活订单数(计费时间)"`
ActivateCardOrderCost *float64 `json:"activateCardOrderCost" dc:"电话卡激活订单成本(回传时间)"`
ForwardTsActivateCardOrderCost *float64 `json:"forwardTsActivateCardOrderCost" dc:"电话卡激活订单成本(计费时间)"`
CreateCardOrderRatio *float64 `json:"createCardOrderRatio" dc:"有效制卡订单率(回传时间)"`
ForwardTsCreateCardOrderRatio *float64 `json:"forwardTsCreateCardOrderRatio" dc:"有效制卡订单率(计费时间)"`
ActivateCardOrderCntRatio *float64 `json:"activateCardOrderCntRatio" dc:"电话卡激活率(回传时间)"`
ForwardTsActivateCardOrderRatio *float64 `json:"forwardTsActivateCardOrderRatio" dc:"电话卡激活率(计费时间)"`
LivePlayCnt *int64 `json:"livePlayCnt" dc:"全站直播观看数"`
ItemEntranceClkCnt *int64 `json:"itemEntranceClkCnt" dc:"小黄车点击数"`
ShowCnt *int64 `json:"showCnt" dc:"全站曝光"`
ReportDateStr string `json:"reportDateStr" v:"required" dc:"时间"`
CampaignId *int64 `json:"campaignId" dc:"计划 ID"`
CampaignName string `json:"campaignName" dc:"计划名称"`
UnitId *int64 `json:"unitId" dc:"单元 ID"`
UnitName string `json:"unitName" dc:"单元名称"`
CreativeId *int64 `json:"creativeId" dc:"创意 ID"`
CreativeName string `json:"creativeName" dc:"创意名称"`
CidActualRoiAfterSubsidy *float64 `json:"cidActualRoiAfterSubsidy" dc:"补贴后实际 ROI"`
CidCouponAmount *int64 `json:"cidCouponAmount" dc:"核销券金额"`
CidCouponCallbackPaidRefundAmount *int64 `json:"cidCouponCallbackPaidRefundAmount" dc:"退单有回传_核销券金额"`
CidVoucherCost *float64 `json:"cidVoucherCost" dc:"券成本"`
}
// ListCampaignReportSumReq 获取广告计划效果指标表列表请求
type ListCampaignReportSumReq struct {
g.Meta `path:"/listCampaignReportSum" method:"get" tags:"广告计划报表" summary:"获取广告计划效果指标表列表" dc:"分页查询广告计划效果指标表列表"`
*beans.Page
ReportDateStr string `json:"reportDateStr" dc:"时间"`
CampaignId *int64 `json:"campaignId" dc:"计划 ID"`
UnitId *int64 `json:"unitId" dc:"单元 ID"`
CreativeId *int64 `json:"creativeId" dc:"创意 ID"`
AuthorId string `json:"authorId" dc:"直播用户快手 Id"`
MerchantProductId string `json:"merchantProductId" dc:"商品 ID"`
Keyword string `json:"keyword" dc:"关键字(搜索直播间名称、视频名称等)"`
}
// ListCampaignReportSumRes 获取广告计划效果指标表列表响应
type ListCampaignReportSumRes struct {
List []*CampaignReportSumItem `json:"list" dc:"广告计划效果列表"`
Total int `json:"total" dc:"总数"`
}

View File

@@ -0,0 +1,58 @@
package copydata
// CreateSyncTaskLogReq 创建同步任务日志请求
type CreateSyncTaskLogReq struct {
TaskID string `json:"taskId"`
TaskType string `json:"taskType"`
AdvertiserID int64 `json:"advertiserId"`
StartTime interface{} `json:"startTime"`
EndTime interface{} `json:"endTime"`
Status string `json:"status"`
MaxRetry int `json:"maxRetry"`
PageInfo interface{} `json:"pageInfo,omitempty"`
RequestParams interface{} `json:"requestParams,omitempty"`
}
// UpdateSyncTaskLogReq 更新同步任务日志请求
type UpdateSyncTaskLogReq struct {
ID int64 `json:"id"`
Status string `json:"status,omitempty"`
RetryCount *int `json:"retryCount,omitempty"`
ErrorMessage string `json:"errorMessage,omitempty"`
ErrorCode string `json:"errorCode,omitempty"`
ResultSummary interface{} `json:"resultSummary,omitempty"`
NextRetryTime interface{} `json:"nextRetryTime,omitempty"`
CompletedAt interface{} `json:"completedAt,omitempty"`
DurationMs *int64 `json:"durationMs,omitempty"`
}
// QueryFailedTasksReq 查询失败任务请求
type QueryFailedTasksReq struct {
Status []string `json:"status,omitempty"` // 查询的状态列表
TaskType string `json:"taskType,omitempty"` // 任务类型
MaxRetries *int `json:"maxRetries,omitempty"` // 最大重试次数过滤
Limit int `json:"limit,omitempty"` // 限制数量
}
// SyncTaskLogItem 同步任务日志项
type SyncTaskLogItem struct {
Id int64 `json:"id"`
TaskID string `json:"taskId"`
TaskType string `json:"taskType"`
AdvertiserID int64 `json:"advertiserId"`
StartTime interface{} `json:"startTime"`
EndTime interface{} `json:"endTime"`
Status string `json:"status"`
RetryCount int `json:"retryCount"`
MaxRetry int `json:"maxRetry"`
ErrorMessage string `json:"errorMessage,omitempty"`
ErrorCode string `json:"errorCode,omitempty"`
ResultSummary interface{} `json:"resultSummary,omitempty"`
PageInfo interface{} `json:"pageInfo,omitempty"`
RequestParams interface{} `json:"requestParams,omitempty"`
NextRetryTime interface{} `json:"nextRetryTime,omitempty"`
CompletedAt interface{} `json:"completedAt,omitempty"`
DurationMs int64 `json:"durationMs"`
CreatedAt interface{} `json:"createdAt"`
UpdatedAt interface{} `json:"updatedAt"`
}

View File

@@ -255,21 +255,24 @@ type CidAccountReportDetail struct {
ShowCnt *int64 `orm:"show_cnt" json:"showCnt" description:"全站曝光"`
// 时间字段
ReportDateStr string `orm:"report_date_str" json:"reportDateStr" description:"时间"`
ReportDateStr string
// 分页字段
PageNumber string
// 广告结构字段
CampaignId *int64 `orm:"campaign_id" json:"campaignId" description:"计划ID"`
CampaignName string `orm:"campaign_name" json:"campaignName" description:"计划名称"`
UnitId *int64 `orm:"unit_id" json:"unitId" description:"单元ID"`
UnitName string `orm:"unit_name" json:"unitName" description:"单元名称"`
CreativeId *int64 `orm:"creative_id" json:"creativeId" description:"创意ID"`
CreativeName string `orm:"creative_name" json:"creativeName" description:"创意名称"`
CampaignId string
CampaignName string
UnitId string
UnitName string
CreativeId string
CreativeName string
// 补贴相关字段
CidActualRoiAfterSubsidy *float64 `orm:"cid_actual_roi_after_subsidy" json:"cidActualRoiAfterSubsidy" description:"补贴后实际ROI"`
CidCouponAmount *int64 `orm:"cid_coupon_amount" json:"cidCouponAmount" description:"核销券金额"`
CidCouponCallbackPaidRefundAmount *int64 `orm:"cid_coupon_callback_paid_refund_amount" json:"cidCouponCallbackPaidRefundAmount" description:"退单有回传_核销券金额"`
CidVoucherCost *float64 `orm:"cid_voucher_cost" json:"cidVoucherCost" description:"券成本"`
CidActualRoiAfterSubsidy *float64
CidCouponAmount *int64
CidCouponCallbackPaidRefundAmount *int64
CidVoucherCost *float64
}
// CidAccountReportDetailCol 广告数据报表详情表字段定义

View File

@@ -257,6 +257,9 @@ type CidAccountReportSum struct {
// 时间字段
ReportDateStr string `orm:"report_date_str" json:"reportDateStr" description:"时间"`
// 分页字段
PageNumber int `orm:"page_number" json:"pageNumber" description:"页码"`
// 广告结构字段
CampaignId *int64 `orm:"campaign_id" json:"campaignId" description:"计划ID"`
CampaignName string `orm:"campaign_name" json:"campaignName" description:"计划名称"`
@@ -451,6 +454,7 @@ type CidAccountReportSumCol struct {
ItemEntranceClkCnt string
ShowCnt string
ReportDateStr string
PageNumber string
CampaignId string
CampaignName string
UnitId string
@@ -651,6 +655,7 @@ func (e *CidAccountReportSum) GetCols() *CidAccountReportSumCol {
ItemEntranceClkCnt: "item_entrance_clk_cnt",
ShowCnt: "show_cnt",
ReportDateStr: "report_date_str",
PageNumber: "page_number",
CampaignId: "campaign_id",
CampaignName: "campaign_name",
UnitId: "unit_id",

View File

@@ -0,0 +1,582 @@
package copydata
import "gitea.com/red-future/common/beans"
// CampaignReportDetail 广告效果指标明细表实体
type CampaignReportDetail struct {
beans.SQLBaseDO `orm:",inherit"`
T0OrderPaymentAmt *float64 `orm:"t0_order_payment_amt" json:"t0OrderPaymentAmt" description:"当日总成交订单金额"`
CreativeMaterialType string `orm:"creative_material_type" json:"creativeMaterialType" description:"视频素材类型"`
LiveName string `orm:"live_name" json:"liveName" description:"直播间名称"`
AuthorId string `orm:"author_id" json:"authorId" description:"直播用户快手 Id"`
PicUrl string `orm:"pic_url" json:"picUrl" description:"图片 URL"`
PicName string `orm:"pic_name" json:"picName" description:"图片名称"`
PicId string `orm:"pic_id" json:"picId" description:"图片 Id"`
CoverUrl string `orm:"cover_url" json:"coverUrl" description:"封面 URL"`
CoverId *int64 `orm:"cover_id" json:"coverId" description:"封面 Id"`
ItemOrderConversionRatio *float64 `orm:"item_order_conversion_ratio" json:"itemOrderConversionRatio" description:"转化率"`
ItemCardClickRatio *float64 `orm:"item_card_click_ratio" json:"itemCardClickRatio" description:"点击率"`
ItemCardClkCnt *int64 `orm:"item_card_clk_cnt" json:"itemCardClkCnt" description:"商品卡点击数"`
LivePlayCntCost *float64 `orm:"live_play_cnt_cost" json:"livePlayCntCost" description:"直播间观看成本"`
AdMerchantFollowCost *float64 `orm:"ad_merchant_follow_cost" json:"adMerchantFollowCost" description:"涨粉成本"`
AdMerchantFollow *int64 `orm:"ad_merchant_follow" json:"adMerchantFollow" description:"涨粉数"`
NetT0OrderCnt *int64 `orm:"net_t0_order_cnt" json:"netT0OrderCnt" description:"当日累计净成交订单数"`
NetT0Roi *float64 `orm:"net_t0_roi" json:"netT0Roi" description:"净成交 ROI"`
NetT0Gmv *float64 `orm:"net_t0_gmv" json:"netT0Gmv" description:"净成交 GMV"`
PhotoName string `orm:"photo_name" json:"photoName" description:"视频名称"`
PhotoIdStr string `orm:"photo_id_str" json:"photoIdStr" description:"视频 id"`
PhotoId string `orm:"photo_id" json:"photoId" description:"视频 id"`
ModPriceSegment string `orm:"mod_price_segment" json:"modPriceSegment" description:"设备价格区间"`
AgeSegment string `orm:"age_segment" json:"ageSegment" description:"年龄段"`
Province string `orm:"province" json:"province" description:"省份名称"`
Gender string `orm:"gender" json:"gender" description:"性别"`
AdPhotoPlayedFiveRatio *float64 `orm:"ad_photo_played_five_ratio" json:"adPhotoPlayedFiveRatio" description:"作品 5 秒播放率"`
AdPhotoPlayedThreeRatio *float64 `orm:"ad_photo_played_three_ratio" json:"adPhotoPlayedThreeRatio" description:"作品 3 秒播放率"`
OrderSubmitRoi *float64 `orm:"order_submit_roi" json:"orderSubmitRoi" description:"订单提交 ROI"`
OrderSubmitAmt *int64 `orm:"order_submit_amt" json:"orderSubmitAmt" description:"外部订单金额"`
EventOrderSubmitCost *float64 `orm:"event_order_submit_cost" json:"eventOrderSubmitCost" description:"订单提交成本"`
EventOrderSubmit *int64 `orm:"event_order_submit" json:"eventOrderSubmit" description:"订单提交数"`
EventOrderPaidRoi *float64 `orm:"event_order_paid_roi" json:"eventOrderPaidRoi" description:"订单支付率"`
EventAppInvoked *int64 `orm:"event_app_invoked" json:"eventAppInvoked" description:"唤起应用数"`
EventAddShoppingCart *int64 `orm:"event_add_shopping_cart" json:"eventAddShoppingCart" description:"添加购物车次数"`
ConversionNumCost *float64 `orm:"conversion_num_cost" json:"conversionNumCost" description:"转化成本(回传时间)"`
AdEffectivePlayNum *int64 `orm:"ad_effective_play_num" json:"adEffectivePlayNum" description:"有效播放数"`
AdItemClick *int64 `orm:"ad_item_click" json:"adItemClick" description:"行为数"`
MerchantProductId string `orm:"merchant_product_id" json:"merchantProductId" description:"商品 ID"`
CostTotal *float64 `orm:"cost_total" json:"costTotal" description:"花费"`
AdShow *int64 `orm:"ad_show" json:"adShow" description:"曝光数"`
AdShow1kCost *float64 `orm:"ad_show1k_cost" json:"adShow1kCost" description:"平均千次广告曝光花费"`
Impression *int64 `orm:"impression" json:"impression" description:"封面曝光数"`
PhotoClick *int64 `orm:"photo_click" json:"photoClick" description:"封面点击数"`
PhotoClickRatio *float64 `orm:"photo_click_ratio" json:"photoClickRatio" description:"封面点击率"`
Click *int64 `orm:"click" json:"click" description:"素材曝光数"`
ActionbarClick *int64 `orm:"actionbar_click" json:"actionbarClick" description:"行为数"`
ActionbarClickCost *float64 `orm:"actionbar_click_cost" json:"actionbarClickCost" description:"行为成本"`
EspClickRatio *float64 `orm:"esp_click_ratio" json:"espClickRatio" description:"行为率"`
ActionRatio *float64 `orm:"action_ratio" json:"actionRatio" description:"素材点击率"`
AdItemClickCount *int64 `orm:"ad_item_click_count" json:"adItemClickCount" description:"预约组件点击数"`
EspLivePlayedSeconds *int64 `orm:"esp_live_played_seconds" json:"espLivePlayedSeconds" description:"直播平均观看时长"`
PlayedThreeSeconds *int64 `orm:"played_three_seconds" json:"playedThreeSeconds" description:"作品 3 秒播放数"`
Play3sRatio *float64 `orm:"play3s_ratio" json:"play3sRatio" description:"作品 3 秒播放率"`
PlayedFiveSeconds *int64 `orm:"played_five_seconds" json:"playedFiveSeconds" description:"作品 5 秒播放数"`
Play5sRatio *float64 `orm:"play5s_ratio" json:"play5sRatio" description:"作品 5 秒播放率"`
PlayedEnd *int64 `orm:"played_end" json:"playedEnd" description:"作品完播数"`
PlayEndRatio *float64 `orm:"play_end_ratio" json:"playEndRatio" description:"作品完播率"`
Share *int64 `orm:"share" json:"share" description:"作品分享数"`
Comment *int64 `orm:"comment" json:"comment" description:"作品评论数"`
Likes *int64 `orm:"likes" json:"likes" description:"作品点赞数"`
Report *int64 `orm:"report" json:"report" description:"作品举报数"`
Block *int64 `orm:"block" json:"block" description:"作品拉黑数"`
ItemNegative *int64 `orm:"item_negative" json:"itemNegative" description:"详情页减少此类作品数"`
LiveShare *int64 `orm:"live_share" json:"liveShare" description:"直播送礼数"`
LiveComment *int64 `orm:"live_comment" json:"liveComment" description:"直播评论数"`
LiveReward *int64 `orm:"live_reward" json:"liveReward" description:"直播送礼数"`
EffectivePlayCount *int64 `orm:"effective_play_count" json:"effectivePlayCount" description:"有效播放数"`
EffectivePlayRatio *float64 `orm:"effective_play_ratio" json:"effectivePlayRatio" description:"有效播放率"`
ConversionNum *int64 `orm:"conversion_num" json:"conversionNum" description:"转化数"`
ConversionCostEsp *float64 `orm:"conversion_cost_esp" json:"conversionCostEsp" description:"转化成本"`
Roi *float64 `orm:"roi" json:"roi" description:"直接 ROI"`
Gmv *float64 `orm:"gmv" json:"gmv" description:"直接 GMV"`
T0Gmv *float64 `orm:"t0_gmv" json:"t0Gmv" description:"当日累计 GMV"`
T1Gmv *float64 `orm:"t1_gmv" json:"t1Gmv" description:"次日累计 GMV"`
T7Gmv *float64 `orm:"t7_gmv" json:"t7Gmv" description:"7 日累计 GMV"`
T15Gmv *float64 `orm:"t15_gmv" json:"t15Gmv" description:"15 日累计 GMV"`
T30Gmv *float64 `orm:"t30_gmv" json:"t30Gmv" description:"30 日累计 GMV"`
T0Roi *float64 `orm:"t0_roi" json:"t0Roi" description:"当日累计 ROI"`
T1Roi *float64 `orm:"t1_roi" json:"t1Roi" description:"次日累计 ROI"`
T7Roi *float64 `orm:"t7_roi" json:"t7Roi" description:"7 日累计 ROI"`
T15Roi *float64 `orm:"t15_roi" json:"t15Roi" description:"15 日累计 ROI"`
T30Roi *float64 `orm:"t30_roi" json:"t30Roi" description:"30 日累计 ROI"`
PaiedOrder *int64 `orm:"paied_order" json:"paiedOrder" description:"直接订单数"`
OrderRatio *float64 `orm:"order_ratio" json:"orderRatio" description:"直接下单率"`
T0OrderCnt *int64 `orm:"t0_order_cnt" json:"t0OrderCnt" description:"当日累计订单数"`
T0OrderCntCost *float64 `orm:"t0_order_cnt_cost" json:"t0OrderCntCost" description:"当日累计订单成本"`
T0OrderCntRatio *float64 `orm:"t0_order_cnt_ratio" json:"t0OrderCntRatio" description:"累计订单下单率"`
T1OrderCnt *int64 `orm:"t1_order_cnt" json:"t1OrderCnt" description:"次日累计订单数"`
T7OrderCnt *int64 `orm:"t7_order_cnt" json:"t7OrderCnt" description:"7 日累计订单数"`
T15OrderCnt *int64 `orm:"t15_order_cnt" json:"t15OrderCnt" description:"15 日累计订单数"`
T30OrderCnt *int64 `orm:"t30_order_cnt" json:"t30OrderCnt" description:"30 日累计订单数"`
MerchantRecoFans *int64 `orm:"merchant_reco_fans" json:"merchantRecoFans" description:"涨粉数"`
T1Retention *float64 `orm:"t1_retention" json:"t1Retention" description:"次日涨粉留存数"`
T7Retention *float64 `orm:"t7_retention" json:"t7Retention" description:"7 日涨粉留存数"`
T15Retention *float64 `orm:"t15_retention" json:"t15Retention" description:"15 日涨粉留存数"`
T30Retention *float64 `orm:"t30_retention" json:"t30Retention" description:"30 日涨粉留存数"`
T1RetentionRatio *float64 `orm:"t1_retention_ratio" json:"t1RetentionRatio" description:"次日涨粉留存率"`
T7RetentionRatio *float64 `orm:"t7_retention_ratio" json:"t7RetentionRatio" description:"7 日涨粉留存率"`
T15RetentionRatio *float64 `orm:"t15_retention_ratio" json:"t15RetentionRatio" description:"15 日涨粉留存率"`
T30RetentionRatio *float64 `orm:"t30_retention_ratio" json:"t30RetentionRatio" description:"30 日涨粉留存率"`
ReservationSuccess *int64 `orm:"reservation_success" json:"reservationSuccess" description:"直播预约成功数"`
ReservationCost *float64 `orm:"reservation_cost" json:"reservationCost" description:"直播预约成功成本"`
StandardLivePlayedStarted *int64 `orm:"standard_live_played_started" json:"standardLivePlayedStarted" description:"直播观看数"`
AdLivePlayCnt *int64 `orm:"ad_live_play_cnt" json:"adLivePlayCnt" description:"直播间人气数"`
AdLivePlayCntCost *float64 `orm:"ad_live_play_cnt_cost" json:"adLivePlayCntCost" description:"直播间人气成本"`
LiveAudienceCost *float64 `orm:"live_audience_cost" json:"liveAudienceCost" description:"直播观看成本"`
LiveEventGoodsView *int64 `orm:"live_event_goods_view" json:"liveEventGoodsView" description:"直播间商品点击数"`
GoodsClickRatio *float64 `orm:"goods_click_ratio" json:"goodsClickRatio" description:"直播间商品点击率"`
DirectAttrPlatNewBuyerCnt *int64 `orm:"direct_attr_plat_new_buyer_cnt" json:"directAttrPlatNewBuyerCnt" description:"直接平台新客"`
T30AttrPlatTotalBuyerCnt *int64 `orm:"t30_attr_plat_total_buyer_cnt" json:"t30AttrPlatTotalBuyerCnt" description:"30 日累计平台新客"`
DirectAttrSellerNewBuyerCnt *int64 `orm:"direct_attr_seller_new_buyer_cnt" json:"directAttrSellerNewBuyerCnt" description:"直接店铺新客"`
T30AttrSellerTotalBuyerCnt *int64 `orm:"t30_attr_seller_total_buyer_cnt" json:"t30AttrSellerTotalBuyerCnt" description:"30 日累计店铺新客"`
T3Gmv *float64 `orm:"t3_gmv" json:"t3Gmv" description:"3 日累计 GMV"`
T3OrderCnt *int64 `orm:"t3_order_cnt" json:"t3OrderCnt" description:"3 日累计订单数"`
T3Roi *float64 `orm:"t3_roi" json:"t3Roi" description:"3 日累计 ROI"`
T7IndirectOrderAmt *float64 `orm:"t7_indirect_order_amt" json:"t7IndirectOrderAmt" description:"7 日间接订单金额"`
T7IndirectOrderCnt *int64 `orm:"t7_indirect_order_cnt" json:"t7IndirectOrderCnt" description:"7 日间接订单数"`
FansT0GmvPerFans *float64 `orm:"fans_t0_gmv_per_fans" json:"fansT0GmvPerFans" description:"新增粉丝人均销售额"`
FansT3GmvPerFans *float64 `orm:"fans_t3_gmv_per_fans" json:"fansT3GmvPerFans" description:"3 日新增粉丝人均销售额"`
FansT7GmvPerFans *float64 `orm:"fans_t7_gmv_per_fans" json:"fansT7GmvPerFans" description:"7 日新增粉丝人均销售额"`
FansT15GmvPerFans *float64 `orm:"fans_t15_gmv_per_fans" json:"fansT15GmvPerFans" description:"15 日新增粉丝人均销售额"`
FansT30GmvPerFans *float64 `orm:"fans_t30_gmv_per_fans" json:"fansT30GmvPerFans" description:"30 日新增粉丝人均销售额"`
RecoFansCost *float64 `orm:"reco_fans_cost" json:"recoFansCost" description:"涨粉成本"`
QcpxWhiteboxDirectOrderPaymentAmt *float64 `orm:"qcpx_whitebox_direct_order_payment_amt" json:"qcpxWhiteboxDirectOrderPaymentAmt" description:"智能优惠券订单 GMV"`
QcpxWhiteboxDirectOrderCnt *int64 `orm:"qcpx_whitebox_direct_order_cnt" json:"qcpxWhiteboxDirectOrderCnt" description:"智能优惠券订单数"`
FansT0Gmv *float64 `orm:"fans_t0_gmv" json:"fansT0Gmv" description:"涨粉当日 GMV"`
FansT1Gmv *float64 `orm:"fans_t1_gmv" json:"fansT1Gmv" description:"涨粉次日 GMV"`
FansT7Gmv *float64 `orm:"fans_t7_gmv" json:"fansT7Gmv" description:"涨粉 7 日 GMV"`
FansT15Gmv *float64 `orm:"fans_t15_gmv" json:"fansT15Gmv" description:"涨粉 15 日 GMV"`
FansT30Gmv *float64 `orm:"fans_t30_gmv" json:"fansT30Gmv" description:"涨粉 30 日 GMV"`
FansT0Roi *float64 `orm:"fans_t0_roi" json:"fansT0Roi" description:"涨粉当日 ROI"`
FansT1Roi *float64 `orm:"fans_t1_roi" json:"fansT1Roi" description:"涨粉次日 ROI"`
FansT7Roi *float64 `orm:"fans_t7_roi" json:"fansT7Roi" description:"涨粉 7 日 ROI"`
FansT15Roi *float64 `orm:"fans_t15_roi" json:"fansT15Roi" description:"涨粉 15 日 ROI"`
FansT30Roi *float64 `orm:"fans_t30_roi" json:"fansT30Roi" description:"涨粉 30 日 ROI"`
T0ShopNewBuyerOrderPaymentAmt *float64 `orm:"t0_shop_new_buyer_order_payment_amt" json:"t0ShopNewBuyerOrderPaymentAmt" description:"当日新客 GMV"`
T1ShopNewBuyerOrderPaymentAmt *float64 `orm:"t1_shop_new_buyer_order_payment_amt" json:"t1ShopNewBuyerOrderPaymentAmt" description:"投后 1 日新客 GMV"`
T3ShopNewBuyerOrderPaymentAmt *float64 `orm:"t3_shop_new_buyer_order_payment_amt" json:"t3ShopNewBuyerOrderPaymentAmt" description:"投后 3 日新客 GMV"`
T7ShopNewBuyerOrderPaymentAmt *float64 `orm:"t7_shop_new_buyer_order_payment_amt" json:"t7ShopNewBuyerOrderPaymentAmt" description:"投后 7 日新客 GMV"`
T15ShopNewBuyerOrderPaymentAmt *float64 `orm:"t15_shop_new_buyer_order_payment_amt" json:"t15ShopNewBuyerOrderPaymentAmt" description:"投后 15 日新客 GMV"`
T30ShopNewBuyerOrderPaymentAmt *float64 `orm:"t30_shop_new_buyer_order_payment_amt" json:"t30ShopNewBuyerOrderPaymentAmt" description:"投后 30 日新客 GMV"`
T0ShopNewBuyerOrderCnt *int64 `orm:"t0_shop_new_buyer_order_cnt" json:"t0ShopNewBuyerOrderCnt" description:"当日新客成交订单量"`
T1ShopNewBuyerOrderCnt *int64 `orm:"t1_shop_new_buyer_order_cnt" json:"t1ShopNewBuyerOrderCnt" description:"投后 1 日新客成交订单量"`
T3ShopNewBuyerOrderCnt *int64 `orm:"t3_shop_new_buyer_order_cnt" json:"t3ShopNewBuyerOrderCnt" description:"投后 3 日新客成交订单量"`
T7ShopNewBuyerOrderCnt *int64 `orm:"t7_shop_new_buyer_order_cnt" json:"t7ShopNewBuyerOrderCnt" description:"投后 7 日新客成交订单量"`
T15ShopNewBuyerOrderCnt *int64 `orm:"t15_shop_new_buyer_order_cnt" json:"t15ShopNewBuyerOrderCnt" description:"投后 15 日新客成交订单量"`
T30ShopNewBuyerOrderCnt *int64 `orm:"t30_shop_new_buyer_order_cnt" json:"t30ShopNewBuyerOrderCnt" description:"投后 30 日新客成交订单量"`
T1NewBuyerRepurchaseRatio *float64 `orm:"t1_new_buyer_repurchase_ratio" json:"t1NewBuyerRepurchaseRatio" description:"投后 1 日新客复购率"`
T3NewBuyerRepurchaseRatio *float64 `orm:"t3_new_buyer_repurchase_ratio" json:"t3NewBuyerRepurchaseRatio" description:"投后 3 日新客复购率"`
T7NewBuyerRepurchaseRatio *float64 `orm:"t7_new_buyer_repurchase_ratio" json:"t7NewBuyerRepurchaseRatio" description:"投后 7 日新客复购率"`
T15NewBuyerRepurchaseRatio *float64 `orm:"t15_new_buyer_repurchase_ratio" json:"t15NewBuyerRepurchaseRatio" description:"投后 15 日新客复购率"`
T30NewBuyerRepurchaseRatio *float64 `orm:"t30_new_buyer_repurchase_ratio" json:"t30NewBuyerRepurchaseRatio" description:"投后 30 日新客复购率"`
T0ShopNewBuyerRoi *float64 `orm:"t0_shop_new_buyer_roi" json:"t0ShopNewBuyerRoi" description:"投后当日新客 ROI"`
T1ShopNewBuyerRoi *float64 `orm:"t1_shop_new_buyer_roi" json:"t1ShopNewBuyerRoi" description:"投后 1 日新客 ROI"`
T3ShopNewBuyerRoi *float64 `orm:"t3_shop_new_buyer_roi" json:"t3ShopNewBuyerRoi" description:"投后 3 日新客 ROI"`
T7ShopNewBuyerRoi *float64 `orm:"t7_shop_new_buyer_roi" json:"t7ShopNewBuyerRoi" description:"投后 7 日新客 ROI"`
T15ShopNewBuyerRoi *float64 `orm:"t15_shop_new_buyer_roi" json:"t15ShopNewBuyerRoi" description:"投后 15 日新客 ROI"`
T30ShopNewBuyerRoi *float64 `orm:"t30_shop_new_buyer_roi" json:"t30ShopNewBuyerRoi" description:"投后 30 日新客 ROI"`
CreateCardOrderCnt *int64 `orm:"create_card_order_cnt" json:"createCardOrderCnt" description:"有效制卡订单数(回传时间)"`
ForwardTsCreateCardOrderCnt *int64 `orm:"forward_ts_create_card_order_cnt" json:"forwardTsCreateCardOrderCnt" description:"有效制卡订单数(计费时间)"`
CreateCardOrderCost *float64 `orm:"create_card_order_cost" json:"createCardOrderCost" description:"有效制卡订单成本(回传时间)"`
ForwardTsCreateCardOrderCost *float64 `orm:"forward_ts_create_card_order_cost" json:"forwardTsCreateCardOrderCost" description:"有效制卡订单成本(计费时间)"`
ActivateCardOrderCnt *int64 `orm:"activate_card_order_cnt" json:"activateCardOrderCnt" description:"电话卡激活订单数(回传时间)"`
ForwardTsActivateCardOrderCnt *int64 `orm:"forward_ts_activate_card_order_cnt" json:"forwardTsActivateCardOrderCnt" description:"电话卡激活订单数(计费时间)"`
ActivateCardOrderCost *float64 `orm:"activate_card_order_cost" json:"activateCardOrderCost" description:"电话卡激活订单成本(回传时间)"`
ForwardTsActivateCardOrderCost *float64 `orm:"forward_ts_activate_card_order_cost" json:"forwardTsActivateCardOrderCost" description:"电话卡激活订单成本(计费时间)"`
CreateCardOrderRatio *float64 `orm:"create_card_order_ratio" json:"createCardOrderRatio" description:"有效制卡订单率(回传时间)"`
ForwardTsCreateCardOrderRatio *float64 `orm:"forward_ts_create_card_order_ratio" json:"forwardTsCreateCardOrderRatio" description:"有效制卡订单率(计费时间)"`
ActivateCardOrderCntRatio *float64 `orm:"activate_card_order_cnt_ratio" json:"activateCardOrderCntRatio" description:"电话卡激活率(回传时间)"`
ForwardTsActivateCardOrderRatio *float64 `orm:"forward_ts_activate_card_order_ratio" json:"forwardTsActivateCardOrderRatio" description:"电话卡激活率(计费时间)"`
LivePlayCnt *int64 `orm:"live_play_cnt" json:"livePlayCnt" description:"全站直播观看数"`
ItemEntranceClkCnt *int64 `orm:"item_entrance_clk_cnt" json:"itemEntranceClkCnt" description:"小黄车点击数"`
ShowCnt *int64 `orm:"show_cnt" json:"showCnt" description:"全站曝光"`
ReportDateStr string `orm:"report_date_str" json:"reportDateStr" description:"时间"`
CampaignId *int64 `orm:"campaign_id" json:"campaignId" description:"计划 ID"`
CampaignName string `orm:"campaign_name" json:"campaignName" description:"计划名称"`
UnitId *int64 `orm:"unit_id" json:"unitId" description:"单元 ID"`
UnitName string `orm:"unit_name" json:"unitName" description:"单元名称"`
CreativeId *int64 `orm:"creative_id" json:"creativeId" description:"创意 ID"`
CreativeName string `orm:"creative_name" json:"creativeName" description:"创意名称"`
CidActualRoiAfterSubsidy *float64 `orm:"cid_actual_roi_after_subsidy" json:"cidActualRoiAfterSubsidy" description:"补贴后实际 ROI"`
CidCouponAmount *int64 `orm:"cid_coupon_amount" json:"cidCouponAmount" description:"核销券金额"`
CidCouponCallbackPaidRefundAmount *int64 `orm:"cid_coupon_callback_paid_refund_amount" json:"cidCouponCallbackPaidRefundAmount" description:"退单有回传_核销券金额"`
CidVoucherCost *float64 `orm:"cid_voucher_cost" json:"cidVoucherCost" description:"券成本"`
}
// CampaignReportDetailCol 广告效果指标明细表字段定义
type CampaignReportDetailCol struct {
beans.SQLBaseCol
T0OrderPaymentAmt string
CreativeMaterialType string
LiveName string
AuthorId string
PicUrl string
PicName string
PicId string
CoverUrl string
CoverId string
ItemOrderConversionRatio string
ItemCardClickRatio string
ItemCardClkCnt string
LivePlayCntCost string
AdMerchantFollowCost string
AdMerchantFollow string
NetT0OrderCnt string
NetT0Roi string
NetT0Gmv string
PhotoName string
PhotoIdStr string
PhotoId string
ModPriceSegment string
AgeSegment string
Province string
Gender string
AdPhotoPlayedFiveRatio string
AdPhotoPlayedThreeRatio string
OrderSubmitRoi string
OrderSubmitAmt string
EventOrderSubmitCost string
EventOrderSubmit string
EventOrderPaidRoi string
EventAppInvoked string
EventAddShoppingCart string
ConversionNumCost string
AdEffectivePlayNum string
AdItemClick string
MerchantProductId string
CostTotal string
AdShow string
AdShow1kCost string
Impression string
PhotoClick string
PhotoClickRatio string
Click string
ActionbarClick string
ActionbarClickCost string
EspClickRatio string
ActionRatio string
AdItemClickCount string
EspLivePlayedSeconds string
PlayedThreeSeconds string
Play3sRatio string
PlayedFiveSeconds string
Play5sRatio string
PlayedEnd string
PlayEndRatio string
Share string
Comment string
Likes string
Report string
Block string
ItemNegative string
LiveShare string
LiveComment string
LiveReward string
EffectivePlayCount string
EffectivePlayRatio string
ConversionNum string
ConversionCostEsp string
Roi string
Gmv string
T0Gmv string
T1Gmv string
T7Gmv string
T15Gmv string
T30Gmv string
T0Roi string
T1Roi string
T7Roi string
T15Roi string
T30Roi string
PaiedOrder string
OrderRatio string
T0OrderCnt string
T0OrderCntCost string
T0OrderCntRatio string
T1OrderCnt string
T7OrderCnt string
T15OrderCnt string
T30OrderCnt string
MerchantRecoFans string
T1Retention string
T7Retention string
T15Retention string
T30Retention string
T1RetentionRatio string
T7RetentionRatio string
T15RetentionRatio string
T30RetentionRatio string
ReservationSuccess string
ReservationCost string
StandardLivePlayedStarted string
AdLivePlayCnt string
AdLivePlayCntCost string
LiveAudienceCost string
LiveEventGoodsView string
GoodsClickRatio string
DirectAttrPlatNewBuyerCnt string
T30AttrPlatTotalBuyerCnt string
DirectAttrSellerNewBuyerCnt string
T30AttrSellerTotalBuyerCnt string
T3Gmv string
T3OrderCnt string
T3Roi string
T7IndirectOrderAmt string
T7IndirectOrderCnt string
FansT0GmvPerFans string
FansT3GmvPerFans string
FansT7GmvPerFans string
FansT15GmvPerFans string
FansT30GmvPerFans string
RecoFansCost string
QcpxWhiteboxDirectOrderPaymentAmt string
QcpxWhiteboxDirectOrderCnt string
FansT0Gmv string
FansT1Gmv string
FansT7Gmv string
FansT15Gmv string
FansT30Gmv string
FansT0Roi string
FansT1Roi string
FansT7Roi string
FansT15Roi string
FansT30Roi string
T0ShopNewBuyerOrderPaymentAmt string
T1ShopNewBuyerOrderPaymentAmt string
T3ShopNewBuyerOrderPaymentAmt string
T7ShopNewBuyerOrderPaymentAmt string
T15ShopNewBuyerOrderPaymentAmt string
T30ShopNewBuyerOrderPaymentAmt string
T0ShopNewBuyerOrderCnt string
T1ShopNewBuyerOrderCnt string
T3ShopNewBuyerOrderCnt string
T7ShopNewBuyerOrderCnt string
T15ShopNewBuyerOrderCnt string
T30ShopNewBuyerOrderCnt string
T1NewBuyerRepurchaseRatio string
T3NewBuyerRepurchaseRatio string
T7NewBuyerRepurchaseRatio string
T15NewBuyerRepurchaseRatio string
T30NewBuyerRepurchaseRatio string
T0ShopNewBuyerRoi string
T1ShopNewBuyerRoi string
T3ShopNewBuyerRoi string
T7ShopNewBuyerRoi string
T15ShopNewBuyerRoi string
T30ShopNewBuyerRoi string
CreateCardOrderCnt string
ForwardTsCreateCardOrderCnt string
CreateCardOrderCost string
ForwardTsCreateCardOrderCost string
ActivateCardOrderCnt string
ForwardTsActivateCardOrderCnt string
ActivateCardOrderCost string
ForwardTsActivateCardOrderCost string
CreateCardOrderRatio string
ForwardTsCreateCardOrderRatio string
ActivateCardOrderCntRatio string
ForwardTsActivateCardOrderRatio string
LivePlayCnt string
ItemEntranceClkCnt string
ShowCnt string
ReportDateStr string
CampaignId string
CampaignName string
UnitId string
UnitName string
CreativeId string
CreativeName string
CidActualRoiAfterSubsidy string
CidCouponAmount string
CidCouponCallbackPaidRefundAmount string
CidVoucherCost string
}
// TableName 返回表名
func (e *CampaignReportDetail) TableName() string {
return "campaign_report_detail"
}
// GetCols 获取所有字段名
func (e *CampaignReportDetail) GetCols() *CampaignReportDetailCol {
return &CampaignReportDetailCol{
SQLBaseCol: beans.SQLBaseCol{
Id: "id",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
},
T0OrderPaymentAmt: "t0_order_payment_amt",
CreativeMaterialType: "creative_material_type",
LiveName: "live_name",
AuthorId: "author_id",
PicUrl: "pic_url",
PicName: "pic_name",
PicId: "pic_id",
CoverUrl: "cover_url",
CoverId: "cover_id",
ItemOrderConversionRatio: "item_order_conversion_ratio",
ItemCardClickRatio: "item_card_click_ratio",
ItemCardClkCnt: "item_card_clk_cnt",
LivePlayCntCost: "live_play_cnt_cost",
AdMerchantFollowCost: "ad_merchant_follow_cost",
AdMerchantFollow: "ad_merchant_follow",
NetT0OrderCnt: "net_t0_order_cnt",
NetT0Roi: "net_t0_roi",
NetT0Gmv: "net_t0_gmv",
PhotoName: "photo_name",
PhotoIdStr: "photo_id_str",
PhotoId: "photo_id",
ModPriceSegment: "mod_price_segment",
AgeSegment: "age_segment",
Province: "province",
Gender: "gender",
AdPhotoPlayedFiveRatio: "ad_photo_played_five_ratio",
AdPhotoPlayedThreeRatio: "ad_photo_played_three_ratio",
OrderSubmitRoi: "order_submit_roi",
OrderSubmitAmt: "order_submit_amt",
EventOrderSubmitCost: "event_order_submit_cost",
EventOrderSubmit: "event_order_submit",
EventOrderPaidRoi: "event_order_paid_roi",
EventAppInvoked: "event_app_invoked",
EventAddShoppingCart: "event_add_shopping_cart",
ConversionNumCost: "conversion_num_cost",
AdEffectivePlayNum: "ad_effective_play_num",
AdItemClick: "ad_item_click",
MerchantProductId: "merchant_product_id",
CostTotal: "cost_total",
AdShow: "ad_show",
AdShow1kCost: "ad_show1k_cost",
Impression: "impression",
PhotoClick: "photo_click",
PhotoClickRatio: "photo_click_ratio",
Click: "click",
ActionbarClick: "actionbar_click",
ActionbarClickCost: "actionbar_click_cost",
EspClickRatio: "esp_click_ratio",
ActionRatio: "action_ratio",
AdItemClickCount: "ad_item_click_count",
EspLivePlayedSeconds: "esp_live_played_seconds",
PlayedThreeSeconds: "played_three_seconds",
Play3sRatio: "play3s_ratio",
PlayedFiveSeconds: "played_five_seconds",
Play5sRatio: "play5s_ratio",
PlayedEnd: "played_end",
PlayEndRatio: "play_end_ratio",
Share: "share",
Comment: "comment",
Likes: "likes",
Report: "report",
Block: "block",
ItemNegative: "item_negative",
LiveShare: "live_share",
LiveComment: "live_comment",
LiveReward: "live_reward",
EffectivePlayCount: "effective_play_count",
EffectivePlayRatio: "effective_play_ratio",
ConversionNum: "conversion_num",
ConversionCostEsp: "conversion_cost_esp",
Roi: "roi",
Gmv: "gmv",
T0Gmv: "t0_gmv",
T1Gmv: "t1_gmv",
T7Gmv: "t7_gmv",
T15Gmv: "t15_gmv",
T30Gmv: "t30_gmv",
T0Roi: "t0_roi",
T1Roi: "t1_roi",
T7Roi: "t7_roi",
T15Roi: "t15_roi",
T30Roi: "t30_roi",
PaiedOrder: "paied_order",
OrderRatio: "order_ratio",
T0OrderCnt: "t0_order_cnt",
T0OrderCntCost: "t0_order_cnt_cost",
T0OrderCntRatio: "t0_order_cnt_ratio",
T1OrderCnt: "t1_order_cnt",
T7OrderCnt: "t7_order_cnt",
T15OrderCnt: "t15_order_cnt",
T30OrderCnt: "t30_order_cnt",
MerchantRecoFans: "merchant_reco_fans",
T1Retention: "t1_retention",
T7Retention: "t7_retention",
T15Retention: "t15_retention",
T30Retention: "t30_retention",
T1RetentionRatio: "t1_retention_ratio",
T7RetentionRatio: "t7_retention_ratio",
T15RetentionRatio: "t15_retention_ratio",
T30RetentionRatio: "t30_retention_ratio",
ReservationSuccess: "reservation_success",
ReservationCost: "reservation_cost",
StandardLivePlayedStarted: "standard_live_played_started",
AdLivePlayCnt: "ad_live_play_cnt",
AdLivePlayCntCost: "ad_live_play_cnt_cost",
LiveAudienceCost: "live_audience_cost",
LiveEventGoodsView: "live_event_goods_view",
GoodsClickRatio: "goods_click_ratio",
DirectAttrPlatNewBuyerCnt: "direct_attr_plat_new_buyer_cnt",
T30AttrPlatTotalBuyerCnt: "t30_attr_plat_total_buyer_cnt",
DirectAttrSellerNewBuyerCnt: "direct_attr_seller_new_buyer_cnt",
T30AttrSellerTotalBuyerCnt: "t30_attr_seller_total_buyer_cnt",
T3Gmv: "t3_gmv",
T3OrderCnt: "t3_order_cnt",
T3Roi: "t3_roi",
T7IndirectOrderAmt: "t7_indirect_order_amt",
T7IndirectOrderCnt: "t7_indirect_order_cnt",
FansT0GmvPerFans: "fans_t0_gmv_per_fans",
FansT3GmvPerFans: "fans_t3_gmv_per_fans",
FansT7GmvPerFans: "fans_t7_gmv_per_fans",
FansT15GmvPerFans: "fans_t15_gmv_per_fans",
FansT30GmvPerFans: "fans_t30_gmv_per_fans",
RecoFansCost: "reco_fans_cost",
QcpxWhiteboxDirectOrderPaymentAmt: "qcpx_whitebox_direct_order_payment_amt",
QcpxWhiteboxDirectOrderCnt: "qcpx_whitebox_direct_order_cnt",
FansT0Gmv: "fans_t0_gmv",
FansT1Gmv: "fans_t1_gmv",
FansT7Gmv: "fans_t7_gmv",
FansT15Gmv: "fans_t15_gmv",
FansT30Gmv: "fans_t30_gmv",
FansT0Roi: "fans_t0_roi",
FansT1Roi: "fans_t1_roi",
FansT7Roi: "fans_t7_roi",
FansT15Roi: "fans_t15_roi",
FansT30Roi: "fans_t30_roi",
T0ShopNewBuyerOrderPaymentAmt: "t0_shop_new_buyer_order_payment_amt",
T1ShopNewBuyerOrderPaymentAmt: "t1_shop_new_buyer_order_payment_amt",
T3ShopNewBuyerOrderPaymentAmt: "t3_shop_new_buyer_order_payment_amt",
T7ShopNewBuyerOrderPaymentAmt: "t7_shop_new_buyer_order_payment_amt",
T15ShopNewBuyerOrderPaymentAmt: "t15_shop_new_buyer_order_payment_amt",
T30ShopNewBuyerOrderPaymentAmt: "t30_shop_new_buyer_order_payment_amt",
T0ShopNewBuyerOrderCnt: "t0_shop_new_buyer_order_cnt",
T1ShopNewBuyerOrderCnt: "t1_shop_new_buyer_order_cnt",
T3ShopNewBuyerOrderCnt: "t3_shop_new_buyer_order_cnt",
T7ShopNewBuyerOrderCnt: "t7_shop_new_buyer_order_cnt",
T15ShopNewBuyerOrderCnt: "t15_shop_new_buyer_order_cnt",
T30ShopNewBuyerOrderCnt: "t30_shop_new_buyer_order_cnt",
T1NewBuyerRepurchaseRatio: "t1_new_buyer_repurchase_ratio",
T3NewBuyerRepurchaseRatio: "t3_new_buyer_repurchase_ratio",
T7NewBuyerRepurchaseRatio: "t7_new_buyer_repurchase_ratio",
T15NewBuyerRepurchaseRatio: "t15_new_buyer_repurchase_ratio",
T30NewBuyerRepurchaseRatio: "t30_new_buyer_repurchase_ratio",
T0ShopNewBuyerRoi: "t0_shop_new_buyer_roi",
T1ShopNewBuyerRoi: "t1_shop_new_buyer_roi",
T3ShopNewBuyerRoi: "t3_shop_new_buyer_roi",
T7ShopNewBuyerRoi: "t7_shop_new_buyer_roi",
T15ShopNewBuyerRoi: "t15_shop_new_buyer_roi",
T30ShopNewBuyerRoi: "t30_shop_new_buyer_roi",
CreateCardOrderCnt: "create_card_order_cnt",
ForwardTsCreateCardOrderCnt: "forward_ts_create_card_order_cnt",
CreateCardOrderCost: "create_card_order_cost",
ForwardTsCreateCardOrderCost: "forward_ts_create_card_order_cost",
ActivateCardOrderCnt: "activate_card_order_cnt",
ForwardTsActivateCardOrderCnt: "forward_ts_activate_card_order_cnt",
ActivateCardOrderCost: "activate_card_order_cost",
ForwardTsActivateCardOrderCost: "forward_ts_activate_card_order_cost",
CreateCardOrderRatio: "create_card_order_ratio",
ForwardTsCreateCardOrderRatio: "forward_ts_create_card_order_ratio",
ActivateCardOrderCntRatio: "activate_card_order_cnt_ratio",
ForwardTsActivateCardOrderRatio: "forward_ts_activate_card_order_ratio",
LivePlayCnt: "live_play_cnt",
ItemEntranceClkCnt: "item_entrance_clk_cnt",
ShowCnt: "show_cnt",
ReportDateStr: "report_date_str",
CampaignId: "campaign_id",
CampaignName: "campaign_name",
UnitId: "unit_id",
UnitName: "unit_name",
CreativeId: "creative_id",
CreativeName: "creative_name",
CidActualRoiAfterSubsidy: "cid_actual_roi_after_subsidy",
CidCouponAmount: "cid_coupon_amount",
CidCouponCallbackPaidRefundAmount: "cid_coupon_callback_paid_refund_amount",
CidVoucherCost: "cid_voucher_cost",
}
}

View File

@@ -0,0 +1,582 @@
package copydata
import "gitea.com/red-future/common/beans"
// CampaignReportSum 广告计划效果指标表实体
type CampaignReportSum struct {
beans.SQLBaseDO `orm:",inherit"`
T0OrderPaymentAmt *float64 `orm:"t0_order_payment_amt" json:"t0OrderPaymentAmt" description:"当日总成交订单金额"`
CreativeMaterialType string `orm:"creative_material_type" json:"creativeMaterialType" description:"视频素材类型视频HORIZONTAL_SCREEN, VERTICAL_SCREEN, UNKNOWN_TYPE图集ATLAS长图ATLAS_VERTICAL"`
LiveName string `orm:"live_name" json:"liveName" description:"直播间名称"`
AuthorId string `orm:"author_id" json:"authorId" description:"直播用户快手 Id"`
PicUrl string `orm:"pic_url" json:"picUrl" description:"图片 URL"`
PicName string `orm:"pic_name" json:"picName" description:"图片名称"`
PicId string `orm:"pic_id" json:"picId" description:"图片 Id"`
CoverUrl string `orm:"cover_url" json:"coverUrl" description:"封面 URL"`
CoverId *int64 `orm:"cover_id" json:"coverId" description:"封面 Id"`
ItemOrderConversionRatio *float64 `orm:"item_order_conversion_ratio" json:"itemOrderConversionRatio" description:"转化率"`
ItemCardClickRatio *float64 `orm:"item_card_click_ratio" json:"itemCardClickRatio" description:"点击率"`
ItemCardClkCnt *int64 `orm:"item_card_clk_cnt" json:"itemCardClkCnt" description:"商品卡点击数"`
LivePlayCntCost *float64 `orm:"live_play_cnt_cost" json:"livePlayCntCost" description:"直播间观看成本"`
AdMerchantFollowCost *float64 `orm:"ad_merchant_follow_cost" json:"adMerchantFollowCost" description:"涨粉成本"`
AdMerchantFollow *int64 `orm:"ad_merchant_follow" json:"adMerchantFollow" description:"涨粉数"`
NetT0OrderCnt *int64 `orm:"net_t0_order_cnt" json:"netT0OrderCnt" description:"当日累计净成交订单数"`
NetT0Roi *float64 `orm:"net_t0_roi" json:"netT0Roi" description:"净成交 ROI"`
NetT0Gmv *float64 `orm:"net_t0_gmv" json:"netT0Gmv" description:"净成交 GMV"`
PhotoName string `orm:"photo_name" json:"photoName" description:"视频名称"`
PhotoIdStr string `orm:"photo_id_str" json:"photoIdStr" description:"视频 id"`
PhotoId string `orm:"photo_id" json:"photoId" description:"视频 id"`
ModPriceSegment string `orm:"mod_price_segment" json:"modPriceSegment" description:"设备价格区间"`
AgeSegment string `orm:"age_segment" json:"ageSegment" description:"年龄段"`
Province string `orm:"province" json:"province" description:"省份名称"`
Gender string `orm:"gender" json:"gender" description:"性别"`
AdPhotoPlayedFiveRatio *float64 `orm:"ad_photo_played_five_ratio" json:"adPhotoPlayedFiveRatio" description:"作品 5 秒播放率"`
AdPhotoPlayedThreeRatio *float64 `orm:"ad_photo_played_three_ratio" json:"adPhotoPlayedThreeRatio" description:"作品 3 秒播放率"`
OrderSubmitRoi *float64 `orm:"order_submit_roi" json:"orderSubmitRoi" description:"订单提交 ROI"`
OrderSubmitAmt *int64 `orm:"order_submit_amt" json:"orderSubmitAmt" description:"外部订单金额"`
EventOrderSubmitCost *float64 `orm:"event_order_submit_cost" json:"eventOrderSubmitCost" description:"订单提交成本"`
EventOrderSubmit *int64 `orm:"event_order_submit" json:"eventOrderSubmit" description:"订单提交数"`
EventOrderPaidRoi *float64 `orm:"event_order_paid_roi" json:"eventOrderPaidRoi" description:"订单支付率"`
EventAppInvoked *int64 `orm:"event_app_invoked" json:"eventAppInvoked" description:"唤起应用数"`
EventAddShoppingCart *int64 `orm:"event_add_shopping_cart" json:"eventAddShoppingCart" description:"添加购物车次数"`
ConversionNumCost *float64 `orm:"conversion_num_cost" json:"conversionNumCost" description:"转化成本(回传时间)"`
AdEffectivePlayNum *int64 `orm:"ad_effective_play_num" json:"adEffectivePlayNum" description:"有效播放数"`
AdItemClick *int64 `orm:"ad_item_click" json:"adItemClick" description:"行为数"`
MerchantProductId string `orm:"merchant_product_id" json:"merchantProductId" description:"商品 ID"`
CostTotal *float64 `orm:"cost_total" json:"costTotal" description:"花费"`
AdShow *int64 `orm:"ad_show" json:"adShow" description:"曝光数"`
AdShow1kCost *float64 `orm:"ad_show1k_cost" json:"adShow1kCost" description:"平均千次广告曝光花费"`
Impression *int64 `orm:"impression" json:"impression" description:"封面曝光数"`
PhotoClick *int64 `orm:"photo_click" json:"photoClick" description:"封面点击数"`
PhotoClickRatio *float64 `orm:"photo_click_ratio" json:"photoClickRatio" description:"封面点击率"`
Click *int64 `orm:"click" json:"click" description:"素材曝光数"`
ActionbarClick *int64 `orm:"actionbar_click" json:"actionbarClick" description:"行为数"`
ActionbarClickCost *float64 `orm:"actionbar_click_cost" json:"actionbarClickCost" description:"行为成本"`
EspClickRatio *float64 `orm:"esp_click_ratio" json:"espClickRatio" description:"行为率"`
ActionRatio *float64 `orm:"action_ratio" json:"actionRatio" description:"素材点击率"`
AdItemClickCount *int64 `orm:"ad_item_click_count" json:"adItemClickCount" description:"预约组件点击数"`
EspLivePlayedSeconds *int64 `orm:"esp_live_played_seconds" json:"espLivePlayedSeconds" description:"直播平均观看时长"`
PlayedThreeSeconds *int64 `orm:"played_three_seconds" json:"playedThreeSeconds" description:"作品 3 秒播放数"`
Play3sRatio *float64 `orm:"play3s_ratio" json:"play3sRatio" description:"作品 3 秒播放率"`
PlayedFiveSeconds *int64 `orm:"played_five_seconds" json:"playedFiveSeconds" description:"作品 5 秒播放数"`
Play5sRatio *float64 `orm:"play5s_ratio" json:"play5sRatio" description:"作品 5 秒播放率"`
PlayedEnd *int64 `orm:"played_end" json:"playedEnd" description:"作品完播数"`
PlayEndRatio *float64 `orm:"play_end_ratio" json:"playEndRatio" description:"作品完播率"`
Share *int64 `orm:"share" json:"share" description:"作品分享数"`
Comment *int64 `orm:"comment" json:"comment" description:"作品评论数"`
Likes *int64 `orm:"likes" json:"likes" description:"作品点赞数"`
Report *int64 `orm:"report" json:"report" description:"作品举报数"`
Block *int64 `orm:"block" json:"block" description:"作品拉黑数"`
ItemNegative *int64 `orm:"item_negative" json:"itemNegative" description:"详情页减少此类作品数"`
LiveShare *int64 `orm:"live_share" json:"liveShare" description:"直播送礼数"`
LiveComment *int64 `orm:"live_comment" json:"liveComment" description:"直播评论数"`
LiveReward *int64 `orm:"live_reward" json:"liveReward" description:"直播送礼数"`
EffectivePlayCount *int64 `orm:"effective_play_count" json:"effectivePlayCount" description:"有效播放数"`
EffectivePlayRatio *float64 `orm:"effective_play_ratio" json:"effectivePlayRatio" description:"有效播放率"`
ConversionNum *int64 `orm:"conversion_num" json:"conversionNum" description:"转化数"`
ConversionCostEsp *float64 `orm:"conversion_cost_esp" json:"conversionCostEsp" description:"转化成本"`
Roi *float64 `orm:"roi" json:"roi" description:"直接 ROI"`
Gmv *float64 `orm:"gmv" json:"gmv" description:"直接 GMV"`
T0Gmv *float64 `orm:"t0_gmv" json:"t0Gmv" description:"当日累计 GMV"`
T1Gmv *float64 `orm:"t1_gmv" json:"t1Gmv" description:"次日累计 GMV"`
T7Gmv *float64 `orm:"t7_gmv" json:"t7Gmv" description:"7 日累计 GMV"`
T15Gmv *float64 `orm:"t15_gmv" json:"t15Gmv" description:"15 日累计 GMV"`
T30Gmv *float64 `orm:"t30_gmv" json:"t30Gmv" description:"30 日累计 GMV"`
T0Roi *float64 `orm:"t0_roi" json:"t0Roi" description:"当日累计 ROI"`
T1Roi *float64 `orm:"t1_roi" json:"t1Roi" description:"次日累计 ROI"`
T7Roi *float64 `orm:"t7_roi" json:"t7Roi" description:"7 日累计 ROI"`
T15Roi *float64 `orm:"t15_roi" json:"t15Roi" description:"15 日累计 ROI"`
T30Roi *float64 `orm:"t30_roi" json:"t30Roi" description:"30 日累计 ROI"`
PaiedOrder *int64 `orm:"paied_order" json:"paiedOrder" description:"直接订单数"`
OrderRatio *float64 `orm:"order_ratio" json:"orderRatio" description:"直接下单率"`
T0OrderCnt *int64 `orm:"t0_order_cnt" json:"t0OrderCnt" description:"当日累计订单数"`
T0OrderCntCost *float64 `orm:"t0_order_cnt_cost" json:"t0OrderCntCost" description:"当日累计订单成本"`
T0OrderCntRatio *float64 `orm:"t0_order_cnt_ratio" json:"t0OrderCntRatio" description:"累计订单下单率"`
T1OrderCnt *int64 `orm:"t1_order_cnt" json:"t1OrderCnt" description:"次日累计订单数"`
T7OrderCnt *int64 `orm:"t7_order_cnt" json:"t7OrderCnt" description:"7 日累计订单数"`
T15OrderCnt *int64 `orm:"t15_order_cnt" json:"t15OrderCnt" description:"15 日累计订单数"`
T30OrderCnt *int64 `orm:"t30_order_cnt" json:"t30OrderCnt" description:"30 日累计订单数"`
MerchantRecoFans *int64 `orm:"merchant_reco_fans" json:"merchantRecoFans" description:"涨粉数"`
T1Retention *float64 `orm:"t1_retention" json:"t1Retention" description:"次日涨粉留存数"`
T7Retention *float64 `orm:"t7_retention" json:"t7Retention" description:"7 日涨粉留存数"`
T15Retention *float64 `orm:"t15_retention" json:"t15Retention" description:"15 日涨粉留存数"`
T30Retention *float64 `orm:"t30_retention" json:"t30Retention" description:"30 日涨粉留存数"`
T1RetentionRatio *float64 `orm:"t1_retention_ratio" json:"t1RetentionRatio" description:"次日涨粉留存率"`
T7RetentionRatio *float64 `orm:"t7_retention_ratio" json:"t7RetentionRatio" description:"7 日涨粉留存率"`
T15RetentionRatio *float64 `orm:"t15_retention_ratio" json:"t15RetentionRatio" description:"15 日涨粉留存率"`
T30RetentionRatio *float64 `orm:"t30_retention_ratio" json:"t30RetentionRatio" description:"30 日涨粉留存率"`
ReservationSuccess *int64 `orm:"reservation_success" json:"reservationSuccess" description:"直播预约成功数"`
ReservationCost *float64 `orm:"reservation_cost" json:"reservationCost" description:"直播预约成功成本"`
StandardLivePlayedStarted *int64 `orm:"standard_live_played_started" json:"standardLivePlayedStarted" description:"直播观看数"`
AdLivePlayCnt *int64 `orm:"ad_live_play_cnt" json:"adLivePlayCnt" description:"直播间人气数"`
AdLivePlayCntCost *float64 `orm:"ad_live_play_cnt_cost" json:"adLivePlayCntCost" description:"直播间人气成本"`
LiveAudienceCost *float64 `orm:"live_audience_cost" json:"liveAudienceCost" description:"直播观看成本"`
LiveEventGoodsView *int64 `orm:"live_event_goods_view" json:"liveEventGoodsView" description:"直播间商品点击数"`
GoodsClickRatio *float64 `orm:"goods_click_ratio" json:"goodsClickRatio" description:"直播间商品点击率"`
DirectAttrPlatNewBuyerCnt *int64 `orm:"direct_attr_plat_new_buyer_cnt" json:"directAttrPlatNewBuyerCnt" description:"直接平台新客"`
T30AttrPlatTotalBuyerCnt *int64 `orm:"t30_attr_plat_total_buyer_cnt" json:"t30AttrPlatTotalBuyerCnt" description:"30 日累计平台新客"`
DirectAttrSellerNewBuyerCnt *int64 `orm:"direct_attr_seller_new_buyer_cnt" json:"directAttrSellerNewBuyerCnt" description:"直接店铺新客"`
T30AttrSellerTotalBuyerCnt *int64 `orm:"t30_attr_seller_total_buyer_cnt" json:"t30AttrSellerTotalBuyerCnt" description:"30 日累计店铺新客"`
T3Gmv *float64 `orm:"t3_gmv" json:"t3Gmv" description:"3 日累计 GMV"`
T3OrderCnt *int64 `orm:"t3_order_cnt" json:"t3OrderCnt" description:"3 日累计订单数"`
T3Roi *float64 `orm:"t3_roi" json:"t3Roi" description:"3 日累计 ROI"`
T7IndirectOrderAmt *float64 `orm:"t7_indirect_order_amt" json:"t7IndirectOrderAmt" description:"7 日间接订单金额"`
T7IndirectOrderCnt *int64 `orm:"t7_indirect_order_cnt" json:"t7IndirectOrderCnt" description:"7 日间接订单数"`
FansT0GmvPerFans *float64 `orm:"fans_t0_gmv_per_fans" json:"fansT0GmvPerFans" description:"新增粉丝人均销售额"`
FansT3GmvPerFans *float64 `orm:"fans_t3_gmv_per_fans" json:"fansT3GmvPerFans" description:"3 日新增粉丝人均销售额"`
FansT7GmvPerFans *float64 `orm:"fans_t7_gmv_per_fans" json:"fansT7GmvPerFans" description:"7 日新增粉丝人均销售额"`
FansT15GmvPerFans *float64 `orm:"fans_t15_gmv_per_fans" json:"fansT15GmvPerFans" description:"15 日新增粉丝人均销售额"`
FansT30GmvPerFans *float64 `orm:"fans_t30_gmv_per_fans" json:"fansT30GmvPerFans" description:"30 日新增粉丝人均销售额"`
RecoFansCost *float64 `orm:"reco_fans_cost" json:"recoFansCost" description:"涨粉成本"`
QcpxWhiteboxDirectOrderPaymentAmt *float64 `orm:"qcpx_whitebox_direct_order_payment_amt" json:"qcpxWhiteboxDirectOrderPaymentAmt" description:"智能优惠券订单 GMV"`
QcpxWhiteboxDirectOrderCnt *int64 `orm:"qcpx_whitebox_direct_order_cnt" json:"qcpxWhiteboxDirectOrderCnt" description:"智能优惠券订单数"`
FansT0Gmv *float64 `orm:"fans_t0_gmv" json:"fansT0Gmv" description:"涨粉当日 GMV"`
FansT1Gmv *float64 `orm:"fans_t1_gmv" json:"fansT1Gmv" description:"涨粉次日 GMV"`
FansT7Gmv *float64 `orm:"fans_t7_gmv" json:"fansT7Gmv" description:"涨粉 7 日 GMV"`
FansT15Gmv *float64 `orm:"fans_t15_gmv" json:"fansT15Gmv" description:"涨粉 15 日 GMV"`
FansT30Gmv *float64 `orm:"fans_t30_gmv" json:"fansT30Gmv" description:"涨粉 30 日 GMV"`
FansT0Roi *float64 `orm:"fans_t0_roi" json:"fansT0Roi" description:"涨粉当日 ROI"`
FansT1Roi *float64 `orm:"fans_t1_roi" json:"fansT1Roi" description:"涨粉次日 ROI"`
FansT7Roi *float64 `orm:"fans_t7_roi" json:"fansT7Roi" description:"涨粉 7 日 ROI"`
FansT15Roi *float64 `orm:"fans_t15_roi" json:"fansT15Roi" description:"涨粉 15 日 ROI"`
FansT30Roi *float64 `orm:"fans_t30_roi" json:"fansT30Roi" description:"涨粉 30 日 ROI"`
T0ShopNewBuyerOrderPaymentAmt *float64 `orm:"t0_shop_new_buyer_order_payment_amt" json:"t0ShopNewBuyerOrderPaymentAmt" description:"当日新客 GMV"`
T1ShopNewBuyerOrderPaymentAmt *float64 `orm:"t1_shop_new_buyer_order_payment_amt" json:"t1ShopNewBuyerOrderPaymentAmt" description:"投后 1 日新客 GMV"`
T3ShopNewBuyerOrderPaymentAmt *float64 `orm:"t3_shop_new_buyer_order_payment_amt" json:"t3ShopNewBuyerOrderPaymentAmt" description:"投后 3 日新客 GMV"`
T7ShopNewBuyerOrderPaymentAmt *float64 `orm:"t7_shop_new_buyer_order_payment_amt" json:"t7ShopNewBuyerOrderPaymentAmt" description:"投后 7 日新客 GMV"`
T15ShopNewBuyerOrderPaymentAmt *float64 `orm:"t15_shop_new_buyer_order_payment_amt" json:"t15ShopNewBuyerOrderPaymentAmt" description:"投后 15 日新客 GMV"`
T30ShopNewBuyerOrderPaymentAmt *float64 `orm:"t30_shop_new_buyer_order_payment_amt" json:"t30ShopNewBuyerOrderPaymentAmt" description:"投后 30 日新客 GMV"`
T0ShopNewBuyerOrderCnt *int64 `orm:"t0_shop_new_buyer_order_cnt" json:"t0ShopNewBuyerOrderCnt" description:"当日新客成交订单量"`
T1ShopNewBuyerOrderCnt *int64 `orm:"t1_shop_new_buyer_order_cnt" json:"t1ShopNewBuyerOrderCnt" description:"投后 1 日新客成交订单量"`
T3ShopNewBuyerOrderCnt *int64 `orm:"t3_shop_new_buyer_order_cnt" json:"t3ShopNewBuyerOrderCnt" description:"投后 3 日新客成交订单量"`
T7ShopNewBuyerOrderCnt *int64 `orm:"t7_shop_new_buyer_order_cnt" json:"t7ShopNewBuyerOrderCnt" description:"投后 7 日新客成交订单量"`
T15ShopNewBuyerOrderCnt *int64 `orm:"t15_shop_new_buyer_order_cnt" json:"t15ShopNewBuyerOrderCnt" description:"投后 15 日新客成交订单量"`
T30ShopNewBuyerOrderCnt *int64 `orm:"t30_shop_new_buyer_order_cnt" json:"t30ShopNewBuyerOrderCnt" description:"投后 30 日新客成交订单量"`
T1NewBuyerRepurchaseRatio *float64 `orm:"t1_new_buyer_repurchase_ratio" json:"t1NewBuyerRepurchaseRatio" description:"投后 1 日新客复购率"`
T3NewBuyerRepurchaseRatio *float64 `orm:"t3_new_buyer_repurchase_ratio" json:"t3NewBuyerRepurchaseRatio" description:"投后 3 日新客复购率"`
T7NewBuyerRepurchaseRatio *float64 `orm:"t7_new_buyer_repurchase_ratio" json:"t7NewBuyerRepurchaseRatio" description:"投后 7 日新客复购率"`
T15NewBuyerRepurchaseRatio *float64 `orm:"t15_new_buyer_repurchase_ratio" json:"t15NewBuyerRepurchaseRatio" description:"投后 15 日新客复购率"`
T30NewBuyerRepurchaseRatio *float64 `orm:"t30_new_buyer_repurchase_ratio" json:"t30NewBuyerRepurchaseRatio" description:"投后 30 日新客复购率"`
T0ShopNewBuyerRoi *float64 `orm:"t0_shop_new_buyer_roi" json:"t0ShopNewBuyerRoi" description:"投后当日新客 ROI"`
T1ShopNewBuyerRoi *float64 `orm:"t1_shop_new_buyer_roi" json:"t1ShopNewBuyerRoi" description:"投后 1 日新客 ROI"`
T3ShopNewBuyerRoi *float64 `orm:"t3_shop_new_buyer_roi" json:"t3ShopNewBuyerRoi" description:"投后 3 日新客 ROI"`
T7ShopNewBuyerRoi *float64 `orm:"t7_shop_new_buyer_roi" json:"t7ShopNewBuyerRoi" description:"投后 7 日新客 ROI"`
T15ShopNewBuyerRoi *float64 `orm:"t15_shop_new_buyer_roi" json:"t15ShopNewBuyerRoi" description:"投后 15 日新客 ROI"`
T30ShopNewBuyerRoi *float64 `orm:"t30_shop_new_buyer_roi" json:"t30ShopNewBuyerRoi" description:"投后 30 日新客 ROI"`
CreateCardOrderCnt *int64 `orm:"create_card_order_cnt" json:"createCardOrderCnt" description:"有效制卡订单数(回传时间)"`
ForwardTsCreateCardOrderCnt *int64 `orm:"forward_ts_create_card_order_cnt" json:"forwardTsCreateCardOrderCnt" description:"有效制卡订单数(计费时间)"`
CreateCardOrderCost *float64 `orm:"create_card_order_cost" json:"createCardOrderCost" description:"有效制卡订单成本(回传时间)"`
ForwardTsCreateCardOrderCost *float64 `orm:"forward_ts_create_card_order_cost" json:"forwardTsCreateCardOrderCost" description:"有效制卡订单成本(计费时间)"`
ActivateCardOrderCnt *int64 `orm:"activate_card_order_cnt" json:"activateCardOrderCnt" description:"电话卡激活订单数(回传时间)"`
ForwardTsActivateCardOrderCnt *int64 `orm:"forward_ts_activate_card_order_cnt" json:"forwardTsActivateCardOrderCnt" description:"电话卡激活订单数(计费时间)"`
ActivateCardOrderCost *float64 `orm:"activate_card_order_cost" json:"activateCardOrderCost" description:"电话卡激活订单成本(回传时间)"`
ForwardTsActivateCardOrderCost *float64 `orm:"forward_ts_activate_card_order_cost" json:"forwardTsActivateCardOrderCost" description:"电话卡激活订单成本(计费时间)"`
CreateCardOrderRatio *float64 `orm:"create_card_order_ratio" json:"createCardOrderRatio" description:"有效制卡订单率(回传时间)"`
ForwardTsCreateCardOrderRatio *float64 `orm:"forward_ts_create_card_order_ratio" json:"forwardTsCreateCardOrderRatio" description:"有效制卡订单率(计费时间)"`
ActivateCardOrderCntRatio *float64 `orm:"activate_card_order_cnt_ratio" json:"activateCardOrderCntRatio" description:"电话卡激活率(回传时间)"`
ForwardTsActivateCardOrderRatio *float64 `orm:"forward_ts_activate_card_order_ratio" json:"forwardTsActivateCardOrderRatio" description:"电话卡激活率(计费时间)"`
LivePlayCnt *int64 `orm:"live_play_cnt" json:"livePlayCnt" description:"全站直播观看数"`
ItemEntranceClkCnt *int64 `orm:"item_entrance_clk_cnt" json:"itemEntranceClkCnt" description:"小黄车点击数"`
ShowCnt *int64 `orm:"show_cnt" json:"showCnt" description:"全站曝光"`
ReportDateStr string `orm:"report_date_str" json:"reportDateStr" description:"时间"`
CampaignId *int64 `orm:"campaign_id" json:"campaignId" description:"计划 ID"`
CampaignName string `orm:"campaign_name" json:"campaignName" description:"计划名称"`
UnitId *int64 `orm:"unit_id" json:"unitId" description:"单元 ID"`
UnitName string `orm:"unit_name" json:"unitName" description:"单元名称"`
CreativeId *int64 `orm:"creative_id" json:"creativeId" description:"创意 ID"`
CreativeName string `orm:"creative_name" json:"creativeName" description:"创意名称"`
CidActualRoiAfterSubsidy *float64 `orm:"cid_actual_roi_after_subsidy" json:"cidActualRoiAfterSubsidy" description:"补贴后实际 ROI"`
CidCouponAmount *int64 `orm:"cid_coupon_amount" json:"cidCouponAmount" description:"核销券金额"`
CidCouponCallbackPaidRefundAmount *int64 `orm:"cid_coupon_callback_paid_refund_amount" json:"cidCouponCallbackPaidRefundAmount" description:"退单有回传_核销券金额"`
CidVoucherCost *float64 `orm:"cid_voucher_cost" json:"cidVoucherCost" description:"券成本"`
}
// CampaignReportSumCol 广告计划效果指标表字段定义
type CampaignReportSumCol struct {
beans.SQLBaseCol
T0OrderPaymentAmt string
CreativeMaterialType string
LiveName string
AuthorId string
PicUrl string
PicName string
PicId string
CoverUrl string
CoverId string
ItemOrderConversionRatio string
ItemCardClickRatio string
ItemCardClkCnt string
LivePlayCntCost string
AdMerchantFollowCost string
AdMerchantFollow string
NetT0OrderCnt string
NetT0Roi string
NetT0Gmv string
PhotoName string
PhotoIdStr string
PhotoId string
ModPriceSegment string
AgeSegment string
Province string
Gender string
AdPhotoPlayedFiveRatio string
AdPhotoPlayedThreeRatio string
OrderSubmitRoi string
OrderSubmitAmt string
EventOrderSubmitCost string
EventOrderSubmit string
EventOrderPaidRoi string
EventAppInvoked string
EventAddShoppingCart string
ConversionNumCost string
AdEffectivePlayNum string
AdItemClick string
MerchantProductId string
CostTotal string
AdShow string
AdShow1kCost string
Impression string
PhotoClick string
PhotoClickRatio string
Click string
ActionbarClick string
ActionbarClickCost string
EspClickRatio string
ActionRatio string
AdItemClickCount string
EspLivePlayedSeconds string
PlayedThreeSeconds string
Play3sRatio string
PlayedFiveSeconds string
Play5sRatio string
PlayedEnd string
PlayEndRatio string
Share string
Comment string
Likes string
Report string
Block string
ItemNegative string
LiveShare string
LiveComment string
LiveReward string
EffectivePlayCount string
EffectivePlayRatio string
ConversionNum string
ConversionCostEsp string
Roi string
Gmv string
T0Gmv string
T1Gmv string
T7Gmv string
T15Gmv string
T30Gmv string
T0Roi string
T1Roi string
T7Roi string
T15Roi string
T30Roi string
PaiedOrder string
OrderRatio string
T0OrderCnt string
T0OrderCntCost string
T0OrderCntRatio string
T1OrderCnt string
T7OrderCnt string
T15OrderCnt string
T30OrderCnt string
MerchantRecoFans string
T1Retention string
T7Retention string
T15Retention string
T30Retention string
T1RetentionRatio string
T7RetentionRatio string
T15RetentionRatio string
T30RetentionRatio string
ReservationSuccess string
ReservationCost string
StandardLivePlayedStarted string
AdLivePlayCnt string
AdLivePlayCntCost string
LiveAudienceCost string
LiveEventGoodsView string
GoodsClickRatio string
DirectAttrPlatNewBuyerCnt string
T30AttrPlatTotalBuyerCnt string
DirectAttrSellerNewBuyerCnt string
T30AttrSellerTotalBuyerCnt string
T3Gmv string
T3OrderCnt string
T3Roi string
T7IndirectOrderAmt string
T7IndirectOrderCnt string
FansT0GmvPerFans string
FansT3GmvPerFans string
FansT7GmvPerFans string
FansT15GmvPerFans string
FansT30GmvPerFans string
RecoFansCost string
QcpxWhiteboxDirectOrderPaymentAmt string
QcpxWhiteboxDirectOrderCnt string
FansT0Gmv string
FansT1Gmv string
FansT7Gmv string
FansT15Gmv string
FansT30Gmv string
FansT0Roi string
FansT1Roi string
FansT7Roi string
FansT15Roi string
FansT30Roi string
T0ShopNewBuyerOrderPaymentAmt string
T1ShopNewBuyerOrderPaymentAmt string
T3ShopNewBuyerOrderPaymentAmt string
T7ShopNewBuyerOrderPaymentAmt string
T15ShopNewBuyerOrderPaymentAmt string
T30ShopNewBuyerOrderPaymentAmt string
T0ShopNewBuyerOrderCnt string
T1ShopNewBuyerOrderCnt string
T3ShopNewBuyerOrderCnt string
T7ShopNewBuyerOrderCnt string
T15ShopNewBuyerOrderCnt string
T30ShopNewBuyerOrderCnt string
T1NewBuyerRepurchaseRatio string
T3NewBuyerRepurchaseRatio string
T7NewBuyerRepurchaseRatio string
T15NewBuyerRepurchaseRatio string
T30NewBuyerRepurchaseRatio string
T0ShopNewBuyerRoi string
T1ShopNewBuyerRoi string
T3ShopNewBuyerRoi string
T7ShopNewBuyerRoi string
T15ShopNewBuyerRoi string
T30ShopNewBuyerRoi string
CreateCardOrderCnt string
ForwardTsCreateCardOrderCnt string
CreateCardOrderCost string
ForwardTsCreateCardOrderCost string
ActivateCardOrderCnt string
ForwardTsActivateCardOrderCnt string
ActivateCardOrderCost string
ForwardTsActivateCardOrderCost string
CreateCardOrderRatio string
ForwardTsCreateCardOrderRatio string
ActivateCardOrderCntRatio string
ForwardTsActivateCardOrderRatio string
LivePlayCnt string
ItemEntranceClkCnt string
ShowCnt string
ReportDateStr string
CampaignId string
CampaignName string
UnitId string
UnitName string
CreativeId string
CreativeName string
CidActualRoiAfterSubsidy string
CidCouponAmount string
CidCouponCallbackPaidRefundAmount string
CidVoucherCost string
}
// TableName 返回表名
func (e *CampaignReportSum) TableName() string {
return "campaign_report_sum"
}
// GetCols 获取所有字段名
func (e *CampaignReportSum) GetCols() *CampaignReportSumCol {
return &CampaignReportSumCol{
SQLBaseCol: beans.SQLBaseCol{
Id: "id",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
},
T0OrderPaymentAmt: "t0_order_payment_amt",
CreativeMaterialType: "creative_material_type",
LiveName: "live_name",
AuthorId: "author_id",
PicUrl: "pic_url",
PicName: "pic_name",
PicId: "pic_id",
CoverUrl: "cover_url",
CoverId: "cover_id",
ItemOrderConversionRatio: "item_order_conversion_ratio",
ItemCardClickRatio: "item_card_click_ratio",
ItemCardClkCnt: "item_card_clk_cnt",
LivePlayCntCost: "live_play_cnt_cost",
AdMerchantFollowCost: "ad_merchant_follow_cost",
AdMerchantFollow: "ad_merchant_follow",
NetT0OrderCnt: "net_t0_order_cnt",
NetT0Roi: "net_t0_roi",
NetT0Gmv: "net_t0_gmv",
PhotoName: "photo_name",
PhotoIdStr: "photo_id_str",
PhotoId: "photo_id",
ModPriceSegment: "mod_price_segment",
AgeSegment: "age_segment",
Province: "province",
Gender: "gender",
AdPhotoPlayedFiveRatio: "ad_photo_played_five_ratio",
AdPhotoPlayedThreeRatio: "ad_photo_played_three_ratio",
OrderSubmitRoi: "order_submit_roi",
OrderSubmitAmt: "order_submit_amt",
EventOrderSubmitCost: "event_order_submit_cost",
EventOrderSubmit: "event_order_submit",
EventOrderPaidRoi: "event_order_paid_roi",
EventAppInvoked: "event_app_invoked",
EventAddShoppingCart: "event_add_shopping_cart",
ConversionNumCost: "conversion_num_cost",
AdEffectivePlayNum: "ad_effective_play_num",
AdItemClick: "ad_item_click",
MerchantProductId: "merchant_product_id",
CostTotal: "cost_total",
AdShow: "ad_show",
AdShow1kCost: "ad_show1k_cost",
Impression: "impression",
PhotoClick: "photo_click",
PhotoClickRatio: "photo_click_ratio",
Click: "click",
ActionbarClick: "actionbar_click",
ActionbarClickCost: "actionbar_click_cost",
EspClickRatio: "esp_click_ratio",
ActionRatio: "action_ratio",
AdItemClickCount: "ad_item_click_count",
EspLivePlayedSeconds: "esp_live_played_seconds",
PlayedThreeSeconds: "played_three_seconds",
Play3sRatio: "play3s_ratio",
PlayedFiveSeconds: "played_five_seconds",
Play5sRatio: "play5s_ratio",
PlayedEnd: "played_end",
PlayEndRatio: "play_end_ratio",
Share: "share",
Comment: "comment",
Likes: "likes",
Report: "report",
Block: "block",
ItemNegative: "item_negative",
LiveShare: "live_share",
LiveComment: "live_comment",
LiveReward: "live_reward",
EffectivePlayCount: "effective_play_count",
EffectivePlayRatio: "effective_play_ratio",
ConversionNum: "conversion_num",
ConversionCostEsp: "conversion_cost_esp",
Roi: "roi",
Gmv: "gmv",
T0Gmv: "t0_gmv",
T1Gmv: "t1_gmv",
T7Gmv: "t7_gmv",
T15Gmv: "t15_gmv",
T30Gmv: "t30_gmv",
T0Roi: "t0_roi",
T1Roi: "t1_roi",
T7Roi: "t7_roi",
T15Roi: "t15_roi",
T30Roi: "t30_roi",
PaiedOrder: "paied_order",
OrderRatio: "order_ratio",
T0OrderCnt: "t0_order_cnt",
T0OrderCntCost: "t0_order_cnt_cost",
T0OrderCntRatio: "t0_order_cnt_ratio",
T1OrderCnt: "t1_order_cnt",
T7OrderCnt: "t7_order_cnt",
T15OrderCnt: "t15_order_cnt",
T30OrderCnt: "t30_order_cnt",
MerchantRecoFans: "merchant_reco_fans",
T1Retention: "t1_retention",
T7Retention: "t7_retention",
T15Retention: "t15_retention",
T30Retention: "t30_retention",
T1RetentionRatio: "t1_retention_ratio",
T7RetentionRatio: "t7_retention_ratio",
T15RetentionRatio: "t15_retention_ratio",
T30RetentionRatio: "t30_retention_ratio",
ReservationSuccess: "reservation_success",
ReservationCost: "reservation_cost",
StandardLivePlayedStarted: "standard_live_played_started",
AdLivePlayCnt: "ad_live_play_cnt",
AdLivePlayCntCost: "ad_live_play_cnt_cost",
LiveAudienceCost: "live_audience_cost",
LiveEventGoodsView: "live_event_goods_view",
GoodsClickRatio: "goods_click_ratio",
DirectAttrPlatNewBuyerCnt: "direct_attr_plat_new_buyer_cnt",
T30AttrPlatTotalBuyerCnt: "t30_attr_plat_total_buyer_cnt",
DirectAttrSellerNewBuyerCnt: "direct_attr_seller_new_buyer_cnt",
T30AttrSellerTotalBuyerCnt: "t30_attr_seller_total_buyer_cnt",
T3Gmv: "t3_gmv",
T3OrderCnt: "t3_order_cnt",
T3Roi: "t3_roi",
T7IndirectOrderAmt: "t7_indirect_order_amt",
T7IndirectOrderCnt: "t7_indirect_order_cnt",
FansT0GmvPerFans: "fans_t0_gmv_per_fans",
FansT3GmvPerFans: "fans_t3_gmv_per_fans",
FansT7GmvPerFans: "fans_t7_gmv_per_fans",
FansT15GmvPerFans: "fans_t15_gmv_per_fans",
FansT30GmvPerFans: "fans_t30_gmv_per_fans",
RecoFansCost: "reco_fans_cost",
QcpxWhiteboxDirectOrderPaymentAmt: "qcpx_whitebox_direct_order_payment_amt",
QcpxWhiteboxDirectOrderCnt: "qcpx_whitebox_direct_order_cnt",
FansT0Gmv: "fans_t0_gmv",
FansT1Gmv: "fans_t1_gmv",
FansT7Gmv: "fans_t7_gmv",
FansT15Gmv: "fans_t15_gmv",
FansT30Gmv: "fans_t30_gmv",
FansT0Roi: "fans_t0_roi",
FansT1Roi: "fans_t1_roi",
FansT7Roi: "fans_t7_roi",
FansT15Roi: "fans_t15_roi",
FansT30Roi: "fans_t30_roi",
T0ShopNewBuyerOrderPaymentAmt: "t0_shop_new_buyer_order_payment_amt",
T1ShopNewBuyerOrderPaymentAmt: "t1_shop_new_buyer_order_payment_amt",
T3ShopNewBuyerOrderPaymentAmt: "t3_shop_new_buyer_order_payment_amt",
T7ShopNewBuyerOrderPaymentAmt: "t7_shop_new_buyer_order_payment_amt",
T15ShopNewBuyerOrderPaymentAmt: "t15_shop_new_buyer_order_payment_amt",
T30ShopNewBuyerOrderPaymentAmt: "t30_shop_new_buyer_order_payment_amt",
T0ShopNewBuyerOrderCnt: "t0_shop_new_buyer_order_cnt",
T1ShopNewBuyerOrderCnt: "t1_shop_new_buyer_order_cnt",
T3ShopNewBuyerOrderCnt: "t3_shop_new_buyer_order_cnt",
T7ShopNewBuyerOrderCnt: "t7_shop_new_buyer_order_cnt",
T15ShopNewBuyerOrderCnt: "t15_shop_new_buyer_order_cnt",
T30ShopNewBuyerOrderCnt: "t30_shop_new_buyer_order_cnt",
T1NewBuyerRepurchaseRatio: "t1_new_buyer_repurchase_ratio",
T3NewBuyerRepurchaseRatio: "t3_new_buyer_repurchase_ratio",
T7NewBuyerRepurchaseRatio: "t7_new_buyer_repurchase_ratio",
T15NewBuyerRepurchaseRatio: "t15_new_buyer_repurchase_ratio",
T30NewBuyerRepurchaseRatio: "t30_new_buyer_repurchase_ratio",
T0ShopNewBuyerRoi: "t0_shop_new_buyer_roi",
T1ShopNewBuyerRoi: "t1_shop_new_buyer_roi",
T3ShopNewBuyerRoi: "t3_shop_new_buyer_roi",
T7ShopNewBuyerRoi: "t7_shop_new_buyer_roi",
T15ShopNewBuyerRoi: "t15_shop_new_buyer_roi",
T30ShopNewBuyerRoi: "t30_shop_new_buyer_roi",
CreateCardOrderCnt: "create_card_order_cnt",
ForwardTsCreateCardOrderCnt: "forward_ts_create_card_order_cnt",
CreateCardOrderCost: "create_card_order_cost",
ForwardTsCreateCardOrderCost: "forward_ts_create_card_order_cost",
ActivateCardOrderCnt: "activate_card_order_cnt",
ForwardTsActivateCardOrderCnt: "forward_ts_activate_card_order_cnt",
ActivateCardOrderCost: "activate_card_order_cost",
ForwardTsActivateCardOrderCost: "forward_ts_activate_card_order_cost",
CreateCardOrderRatio: "create_card_order_ratio",
ForwardTsCreateCardOrderRatio: "forward_ts_create_card_order_ratio",
ActivateCardOrderCntRatio: "activate_card_order_cnt_ratio",
ForwardTsActivateCardOrderRatio: "forward_ts_activate_card_order_ratio",
LivePlayCnt: "live_play_cnt",
ItemEntranceClkCnt: "item_entrance_clk_cnt",
ShowCnt: "show_cnt",
ReportDateStr: "report_date_str",
CampaignId: "campaign_id",
CampaignName: "campaign_name",
UnitId: "unit_id",
UnitName: "unit_name",
CreativeId: "creative_id",
CreativeName: "creative_name",
CidActualRoiAfterSubsidy: "cid_actual_roi_after_subsidy",
CidCouponAmount: "cid_coupon_amount",
CidCouponCallbackPaidRefundAmount: "cid_coupon_callback_paid_refund_amount",
CidVoucherCost: "cid_voucher_cost",
}
}

View File

@@ -0,0 +1,30 @@
package copydata
import "gitea.com/red-future/common/beans"
// SyncTaskLog 同步任务日志实体
type SyncTaskLog struct {
beans.SQLBaseDO `orm:",inherit"`
Id int64 `orm:"Id" json:"Id" description:"主键id"`
TaskID string `orm:"task_id" json:"taskId" description:"任务唯一标识"`
TaskType string `orm:"task_type" json:"taskType" description:"任务类型"`
AdvertiserID int64 `orm:"advertiser_id" json:"advertiserId" description:"广告主ID"`
StartTime interface{} `orm:"start_time" json:"startTime" description:"数据开始时间"`
EndTime interface{} `orm:"end_time" json:"endTime" description:"数据结束时间"`
Status string `orm:"status" json:"status" description:"任务状态"`
RetryCount int `orm:"retry_count" json:"retryCount" description:"已重试次数"`
MaxRetry int `orm:"max_retry" json:"maxRetry" description:"最大重试次数"`
PageInfo interface{} `orm:"page_info" json:"pageInfo" description:"分页信息"`
RequestParams interface{} `orm:"request_params" json:"requestParams" description:"请求参数快照"`
ErrorMessage string `orm:"error_message" json:"errorMessage" description:"错误信息"`
ErrorCode string `orm:"error_code" json:"errorCode" description:"错误码"`
ResultSummary interface{} `orm:"result_summary" json:"resultSummary" description:"结果摘要"`
NextRetryTime interface{} `orm:"next_retry_time" json:"nextRetryTime" description:"下次重试时间"`
CompletedAt interface{} `orm:"completed_at" json:"completedAt" description:"完成时间"`
DurationMs int64 `orm:"duration_ms" json:"durationMs" description:"执行耗时毫秒"`
}
// TableName 返回表名
func (e *SyncTaskLog) TableName() string {
return "sync_task_log"
}

View File

@@ -0,0 +1,101 @@
package main
import (
"cid/syncdata"
"context"
"fmt"
"time"
"gitea.com/red-future/common/beans"
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
"github.com/gogf/gf/v2/os/gctx"
"github.com/sirupsen/logrus"
)
func main() {
ctx := gctx.New()
syncService := syncdata.NewSyncService()
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
now := time.Now()
lastHourEnd := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
lastHourStart := lastHourEnd.Add(-1 * time.Hour)
req := &syncdata.AccountReportRequest{
AdvertiserID: 10001,
StartTime: lastHourStart.UnixMilli(),
EndTime: lastHourEnd.UnixMilli(),
SelectColumns: []string{"impression", "click", "cost", "t0GMV"},
GroupType: 1,
QueryVersion: 1,
PageInfo: &syncdata.PageInfo{
CurrentPage: 1,
PageSize: 10,
},
}
config := syncdata.ConcurrentSyncConfig{
MaxConcurrency: 5,
UseMock: true,
MaxRetries: 3,
}
logrus.Infof("=== 开始执行定时同步任务(并发模式)===")
logrus.Infof("时间区间:%s ~ %s", lastHourStart.Format("2006-01-02 15:04:05"), lastHourEnd.Format("2006-01-02 15:04:05"))
logrus.Infof("分页配置:每页大小=%d", req.PageInfo.PageSize)
logrus.Infof("并发配置:最大并发数=%d, 最大重试次数=%d", config.MaxConcurrency, config.MaxRetries)
result, err := syncService.SyncAccountReportConcurrent(ctx, req, config)
if err != nil {
logrus.Errorf("定时同步任务执行失败:%v", err)
logrus.Infof("主任务日志ID%d", result.TaskLogID)
return
}
hasFailedPages := result.DetailFailCount > 0
if hasFailedPages {
logrus.Warnf("⚠ 定时同步任务完成,但存在失败的页面")
} else {
logrus.Infof("✓ 定时同步任务全部成功")
}
logrus.Infof("主任务日志ID%d", result.TaskLogID)
logrus.Infof("汇总数据:已保存=%v, ID=%d", result.SumSuccess, result.SumID)
logrus.Infof("明细统计:总记录数=%d, 成功页数=%d, 失败页数=%d",
result.DetailCount, result.DetailSuccessCount, result.DetailFailCount)
if hasFailedPages {
logrus.Warnf("失败的页面已记录到 sync_task_log 表,等待补偿调度器处理")
for _, pageResult := range result.PageResults {
if !pageResult.Success {
logrus.Warnf(" - 第 %d 页失败任务日志ID=%d错误%s",
pageResult.PageNumber, pageResult.PageTaskLogID, pageResult.ErrorMessage)
}
}
}
fmt.Printf("\n=== 同步结果汇总 ===\n")
fmt.Printf("时间区间:%s ~ %s\n", lastHourStart.Format("2006-01-02 15:04:05"), lastHourEnd.Format("2006-01-02 15:04:05"))
fmt.Printf("汇总数据:已保存=%v, ID=%d\n", result.SumSuccess, result.SumID)
fmt.Printf("明细统计:总记录数=%d, 成功页数=%d, 失败页数=%d\n",
result.DetailCount, result.DetailSuccessCount, result.DetailFailCount)
fmt.Printf("主任务日志ID%d\n", result.TaskLogID)
if len(result.PageResults) > 0 {
fmt.Printf("\n分页任务详情\n")
for _, pageResult := range result.PageResults {
status := "✓ 成功"
if !pageResult.Success {
status = fmt.Sprintf("✗ 失败: %s", pageResult.ErrorMessage)
}
fmt.Printf(" - 第 %d 页任务ID=%d, 记录数=%d, 耗时=%dms, 状态=%s\n",
pageResult.PageNumber, pageResult.PageTaskLogID,
pageResult.RecordCount, pageResult.DurationMs, status)
}
}
if hasFailedPages {
fmt.Printf("\n⚠ 警告:存在 %d 个失败的页面,请检查日志并触发补偿任务\n", result.DetailFailCount)
}
}

View File

@@ -0,0 +1,373 @@
package main
import (
dao "cid/dao/copydata"
taskDto "cid/model/dto/copydata"
"cid/syncdata"
"context"
"fmt"
"strings"
"sync"
"sync/atomic"
"time"
"gitea.com/red-future/common/beans"
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
"github.com/gogf/gf/v2/os/gctx"
"github.com/sirupsen/logrus"
"golang.org/x/sync/semaphore"
)
// CompensationScheduler 补偿调度器,负责扫描和补偿失败的分页同步任务
type CompensationScheduler struct {
syncService *syncdata.SyncService
}
// NewCompensationScheduler 创建补偿调度器实例
func NewCompensationScheduler() *CompensationScheduler {
return &CompensationScheduler{
syncService: syncdata.NewSyncService(),
}
}
// RunCompensationOnce 执行一次补偿任务(用于手动触发或定时任务调用)
func (s *CompensationScheduler) RunCompensationOnce() {
ctx := gctx.New()
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
logrus.Info("=== 开始执行数据同步补偿任务 ===")
s.processCompensation(ctx)
logrus.Info("=== 补偿任务执行完毕 ===")
}
// processCompensation 处理补偿逻辑:扫描失败的分页任务并逐个补偿
func (s *CompensationScheduler) processCompensation(ctx context.Context) {
logrus.Info(">>> 开始扫描需要补偿的失败分页任务...")
queryReq := &taskDto.QueryFailedTasksReq{
Status: []string{"failed"},
TaskType: "account_report_page",
Limit: 50,
}
failedPageTasks, err := dao.SyncTaskLog.QueryFailedTasks(ctx, queryReq)
if err != nil {
logrus.Errorf("查询失败的分页任务异常:%v", err)
return
}
if len(failedPageTasks) == 0 {
logrus.Info("✓ 当前没有需要补偿的失败分页任务")
return
}
logrus.Infof("发现 %d 个需要补偿的失败分页任务,开始并发处理...", len(failedPageTasks))
maxConcurrency := 5
var successCount int64
var failCount int64
var manualReviewCount int64
sem := semaphore.NewWeighted(int64(maxConcurrency))
var wg sync.WaitGroup
for _, pageTask := range failedPageTasks {
wg.Add(1)
go func(task *taskDto.SyncTaskLogItem) {
defer wg.Done()
if err := sem.Acquire(ctx, 1); err != nil {
logrus.Errorf("获取信号量失败:%v", err)
atomic.AddInt64(&failCount, 1)
return
}
defer sem.Release(1)
if task.RetryCount >= task.MaxRetry {
logrus.Warnf("⚠ 分页任务 %s 已达到最大重试次数 %d标记为需人工处理", task.TaskID, task.MaxRetry)
updateReq := &taskDto.UpdateSyncTaskLogReq{
ID: task.Id,
Status: "manual_review",
ErrorMessage: fmt.Sprintf("已达到最大重试次数 %d 次", task.MaxRetry),
ErrorCode: "MAX_RETRY_EXCEEDED",
}
dao.SyncTaskLog.Update(ctx, updateReq)
s.sendAlert(task)
atomic.AddInt64(&manualReviewCount, 1)
return
}
logrus.Infof("▶ 开始补偿分页任务:%s (广告主=%d, 第 %d/%d 次重试)",
task.TaskID, task.AdvertiserID, task.RetryCount+1, task.MaxRetry)
if s.compensatePageTask(ctx, task) {
atomic.AddInt64(&successCount, 1)
logrus.Infof("✓ 分页任务 %s 补偿成功", task.TaskID)
parentTaskID := s.extractParentTaskID(task.TaskID)
if parentTaskID != "" {
s.checkAndUpdateParentTaskStatus(ctx, parentTaskID)
}
} else {
atomic.AddInt64(&failCount, 1)
logrus.Warnf("✗ 分页任务 %s 补偿失败", task.TaskID)
}
}(pageTask)
}
wg.Wait()
finalSuccess := atomic.LoadInt64(&successCount)
finalFail := atomic.LoadInt64(&failCount)
finalManualReview := atomic.LoadInt64(&manualReviewCount)
logrus.Infof("=== 补偿任务执行完成:总计=%d, 成功=%d, 失败=%d, 需人工处理=%d ===",
len(failedPageTasks), finalSuccess, finalFail, finalManualReview)
}
// compensatePageTask 补偿单个分页任务重新请求API并插入数据
// 返回 true 表示补偿成功false 表示补偿失败
func (s *CompensationScheduler) compensatePageTask(ctx context.Context, pageTask *taskDto.SyncTaskLogItem) bool {
retryCount := pageTask.RetryCount + 1
updateReq := &taskDto.UpdateSyncTaskLogReq{
ID: pageTask.Id,
Status: "retrying",
RetryCount: &retryCount,
}
if err := dao.SyncTaskLog.Update(ctx, updateReq); err != nil {
logrus.Errorf("更新任务状态为 retrying 失败:%v", err)
return false
}
startTime := s.parseTime(pageTask.StartTime)
endTime := s.parseTime(pageTask.EndTime)
pageNumber := s.extractPageNumber(pageTask.TaskID)
if pageNumber == 0 {
logrus.Errorf("无法从任务ID %s 解析页码", pageTask.TaskID)
s.markPageTaskFailed(ctx, pageTask.Id, retryCount, "无法解析页码", "PARSE_PAGE_NUMBER_FAILED")
return false
}
pageSize := s.extractPageSize(pageTask)
req := &syncdata.AccountReportRequest{
AdvertiserID: pageTask.AdvertiserID,
StartTime: startTime.UnixMilli(),
EndTime: endTime.UnixMilli(),
SelectColumns: []string{"impression", "click", "cost", "t0GMV"},
GroupType: 1,
QueryVersion: 1,
PageInfo: &syncdata.PageInfo{
CurrentPage: pageNumber,
PageSize: pageSize,
},
}
maxRetries := 3
parentTaskID := s.extractParentTaskID(pageTask.TaskID)
pageTaskID := fmt.Sprintf("%s_page_%d", parentTaskID, pageNumber)
result, _, err := s.syncService.SyncSinglePageWithTask(ctx, req, true, maxRetries, pageTaskID, pageNumber)
if err != nil {
logrus.Errorf("补偿分页任务 %s 失败(第 %d 次):%v", pageTask.TaskID, retryCount, err)
s.markPageTaskFailed(ctx, pageTask.Id, retryCount, err.Error(), "PAGE_COMPENSATION_FAILED")
return false
}
logrus.Infof("✓ 补偿分页任务 %s 成功 - 记录数=%d", pageTask.TaskID, result.DetailCount)
return true
}
// markPageTaskFailed 标记分页任务为失败状态,并设置下次重试时间(指数退避策略)
func (s *CompensationScheduler) markPageTaskFailed(ctx context.Context, taskID int64, retryCount int, errMsg, errCode string) {
backoffMinutes := s.calculateBackoff(retryCount)
nextRetry := time.Now().Add(time.Duration(backoffMinutes) * time.Minute)
updateReq := &taskDto.UpdateSyncTaskLogReq{
ID: taskID,
Status: "failed",
ErrorMessage: errMsg,
ErrorCode: errCode,
NextRetryTime: nextRetry,
}
dao.SyncTaskLog.Update(ctx, updateReq)
}
// checkAndUpdateParentTaskStatus 检查主任务的所有分页任务状态,如果全部成功则更新主任务状态
func (s *CompensationScheduler) checkAndUpdateParentTaskStatus(ctx context.Context, parentTaskID string) {
logrus.Infof(">>> 检查主任务 %s 的所有分页任务状态...", parentTaskID)
parentTask, err := dao.SyncTaskLog.GetByTaskID(ctx, parentTaskID, "account_report")
if err != nil || parentTask == nil {
logrus.Warnf("未找到主任务 %s跳过状态更新", parentTaskID)
return
}
if parentTask.Status == "success" {
logrus.Infof("主任务 %s 已经是成功状态,无需更新", parentTaskID)
return
}
allPageTasks, err := dao.SyncTaskLog.QueryAllPageTasksByParentID(ctx, parentTaskID, 1000)
if err != nil {
logrus.Errorf("查询主任务 %s 的分页任务失败:%v", parentTaskID, err)
return
}
if len(allPageTasks) == 0 {
logrus.Warnf("主任务 %s 没有找到任何分页任务", parentTaskID)
return
}
failedPages := make([]int, 0)
successPages := make([]int, 0)
for _, pageTask := range allPageTasks {
pageNumber := s.extractPageNumber(pageTask.TaskID)
if pageTask.Status == "success" {
successPages = append(successPages, pageNumber)
} else if pageTask.Status == "failed" || pageTask.Status == "manual_review" {
failedPages = append(failedPages, pageNumber)
}
}
logrus.Infof("主任务 %s 分页状态:总数=%d, 成功=%d, 失败=%d",
parentTaskID, len(allPageTasks), len(successPages), len(failedPages))
if len(failedPages) == 0 {
logrus.Infof("✓ 主任务 %s 的所有分页任务都已成功,更新主任务状态为 success", parentTaskID)
summary := map[string]interface{}{
"total_pages": len(allPageTasks),
"success_pages": len(successPages),
"failed_pages": 0,
"compensated": true,
}
updateReq := &taskDto.UpdateSyncTaskLogReq{
ID: parentTask.Id,
Status: "success",
ResultSummary: summary,
}
if err := dao.SyncTaskLog.Update(ctx, updateReq); err != nil {
logrus.Errorf("更新主任务 %s 状态失败:%v", parentTaskID, err)
}
} else {
logrus.Infof("⚠ 主任务 %s 仍有 %d 个失败的分页任务:%v保持部分失败状态",
parentTaskID, len(failedPages), failedPages)
}
}
// extractParentTaskID 从分页任务ID中提取主任务ID
// 例如:从 "12345_1234567890_account_page_2" 提取 "12345_1234567890_account"
func (s *CompensationScheduler) extractParentTaskID(taskID string) string {
if idx := strings.LastIndex(taskID, "_page_"); idx > 0 {
return taskID[:idx]
}
return ""
}
// extractPageNumber 从分页任务ID中提取页码
// 例如:从 "12345_1234567890_account_page_2" 提取 2
func (s *CompensationScheduler) extractPageNumber(taskID string) int {
if idx := strings.LastIndex(taskID, "_page_"); idx > 0 {
var pageNum int
fmt.Sscanf(taskID[idx+6:], "%d", &pageNum)
return pageNum
}
return 0
}
// extractPageSize 从任务日志的 PageInfo 或 RequestParams 字段中提取每页大小
// 优先级PageInfo.page_size > RequestParams.page_size > 默认值10
func (s *CompensationScheduler) extractPageSize(pageTask *taskDto.SyncTaskLogItem) int {
logrus.Infof("DEBUG - PageInfo 类型: %T, 值: %+v", pageTask.PageInfo, pageTask.PageInfo)
logrus.Infof("DEBUG - RequestParams 类型: %T, 值: %+v", pageTask.RequestParams, pageTask.RequestParams)
// 优先从 PageInfo 中提取
if pageTask.PageInfo != nil {
switch v := pageTask.PageInfo.(type) {
case map[string]interface{}:
// 尝试 float64 类型JSON 数字默认类型)
if pageSize, ok := v["page_size"].(float64); ok {
return int(pageSize)
}
// 尝试 string 类型
if pageSizeStr, ok := v["page_size"].(string); ok {
var pageSize int
fmt.Sscanf(pageSizeStr, "%d", &pageSize)
if pageSize > 0 {
return pageSize
}
}
case map[string]string:
if pageSizeStr, ok := v["page_size"]; ok {
var pageSize int
fmt.Sscanf(pageSizeStr, "%d", &pageSize)
if pageSize > 0 {
return pageSize
}
}
}
}
// 其次从 RequestParams 中提取
if pageTask.RequestParams != nil {
switch v := pageTask.RequestParams.(type) {
case map[string]interface{}:
if pageSize, ok := v["page_size"].(float64); ok {
return int(pageSize)
}
if pageSizeStr, ok := v["page_size"].(string); ok {
var pageSize int
fmt.Sscanf(pageSizeStr, "%d", &pageSize)
if pageSize > 0 {
return pageSize
}
}
}
}
// 默认值改为 10
return 10
}
// calculateBackoff 根据重试次数计算退避时间(分钟)
// 重试次数1->5分钟, 2->15分钟, 3->30分钟, 4->60分钟, 5+->120分钟
func (s *CompensationScheduler) calculateBackoff(retryCount int) int {
backoffs := []int{5, 15, 30, 60, 120}
if retryCount <= len(backoffs) {
return backoffs[retryCount-1]
}
return backoffs[len(backoffs)-1]
}
// parseTime 解析时间字段,支持 time.Time 和字符串格式
func (s *CompensationScheduler) parseTime(t interface{}) time.Time {
switch v := t.(type) {
case time.Time:
return v
case string:
if parsed, err := time.Parse("2006-01-02 15:04:05", v); err == nil {
return parsed
}
}
return time.Now()
}
// sendAlert 发送告警通知(当前仅记录错误日志)
func (s *CompensationScheduler) sendAlert(task *taskDto.SyncTaskLogItem) {
logrus.Errorf("【告警】分页任务 %s 需要人工介入:广告主=%d, 错误=%s",
task.TaskID, task.AdvertiserID, task.ErrorMessage)
}
func main() {
scheduler := NewCompensationScheduler()
scheduler.RunCompensationOnce()
}

View File

@@ -68,7 +68,7 @@ func (s *cidAccountReportDetailService) BatchCreate(ctx context.Context, req *dt
return
}
// Create 创建广告数据报表汇总
// CreateSum Create 创建广告数据报表汇总
func (s *cidAccountReportDetailService) CreateSum(ctx context.Context, req *dto.CidAccountReportSumItem) (res *dto.CreateCidAccountReportSumRes, err error) {
// 验证必要字段
if req.DataType == "" {
@@ -90,7 +90,7 @@ func (s *cidAccountReportDetailService) CreateSum(ctx context.Context, req *dto.
return
}
// BatchCreate 批量创建广告数据报表汇总
// BatchCreateSum 批量创建广告数据报表汇总
func (s *cidAccountReportDetailService) BatchCreateSum(ctx context.Context, req *dto.BatchCreateCidAccountReportSumReq) (res *dto.BatchCreateCidAccountReportSumRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
// 验证数据

View File

@@ -0,0 +1,97 @@
package copydata
import (
dao "cid/dao/copydata"
dto "cid/model/dto/copydata"
"context"
"errors"
"gitea.com/red-future/common/beans"
)
type campaignReportSumService struct{}
// CampaignReportSum 广告计划效果指标表服务
var CampaignReportSum = new(campaignReportSumService)
// Create 创建广告计划效果指标表
func (s *campaignReportSumService) Create(ctx context.Context, req *dto.CampaignReportSumItem) (res *dto.CreateCampaignReportSumRes, err error) {
// 验证必要字段
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
// 插入数据库
id, err := dao.CampaignReportSum.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateCampaignReportSumRes{
Id: id,
}
return
}
// BatchCreate 批量创建广告计划效果指标表
func (s *campaignReportSumService) BatchCreate(ctx context.Context, req *dto.BatchCreateCampaignReportSumReq) (res *dto.BatchCreateCampaignReportSumRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
// 验证数据
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
// 批量插入数据库
successCount, failCount, failedIndexes, err := dao.CampaignReportSum.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateCampaignReportSumRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}
// CreateDetail 创建广告效果指标表
func (s *campaignReportSumService) CreateDetail(ctx context.Context, req *dto.CampaignReportDetailItem) (res *dto.CreateCampaignReportDetailRes, err error) {
// 验证必要字段
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
// 插入数据库
id, err := dao.CampaignReportDetail.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateCampaignReportDetailRes{
Id: id,
}
return
}
// BatchCreateDetail 批量创建广告效果指标表
func (s *campaignReportSumService) BatchCreateDetail(ctx context.Context, req *dto.BatchCreateCampaignReportDetailReq) (res *dto.BatchCreateCampaignReportDetailRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
// 验证数据
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
// 批量插入数据库
successCount, failCount, failedIndexes, err := dao.CampaignReportDetail.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateCampaignReportDetailRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}

View File

@@ -0,0 +1,115 @@
package syncdata
import (
dto "cid/model/dto/copydata"
"cid/service/copydata"
"context"
"encoding/json"
"fmt"
"github.com/sirupsen/logrus"
)
type AccountReportSync struct {
*BaseReportSync
converter *DataConverter
mockGen *MockDataGenerator
}
func NewAccountReportSync() *AccountReportSync {
return &AccountReportSync{
BaseReportSync: NewBaseReportSync(),
converter: NewDataConverter(),
mockGen: NewMockDataGenerator(),
}
}
func (c *AccountReportSync) FetchReport(ctx context.Context, params interface{}) (interface{}, error) {
req, ok := params.(*AccountReportRequest)
if !ok {
return nil, fmt.Errorf("参数类型错误,期望 AccountReportRequest 类型")
}
useMock := false
if useMock {
logrus.Info("使用 Mock 数据")
return c.mockGen.GenerateAccountReportResponse(), nil
}
respBytes, err := NewHttpClient("https://ad.e.kuaishou.com", 0).Post(ctx, "/rest/openapi/gw/esp/report/accountReport", req)
if err != nil {
return nil, fmt.Errorf("调用 API 失败:%w", err)
}
var response AccountReportResponse
if err := json.Unmarshal(respBytes, &response); err != nil {
return nil, fmt.Errorf("解析响应失败:%w", err)
}
if response.Code != 0 {
return nil, fmt.Errorf("API 返回错误code=%d, message=%s", response.Code, response.Message)
}
return &response, nil
}
func (c *AccountReportSync) ConvertToSum(apiData interface{}, dataType string) interface{} {
response, ok := apiData.(*AccountReportResponse)
if !ok || response.Data == nil || response.Data.Sum == nil {
return nil
}
return c.converter.ConvertToSumItem(response.Data.Sum, dataType, 0)
}
func (c *AccountReportSync) ConvertToDetails(apiData interface{}, dataType string) []interface{} {
response, ok := apiData.(*AccountReportResponse)
if !ok || response.Data == nil || len(response.Data.Detail) == 0 {
return nil
}
detailItems := c.converter.ConvertToDetailItems(response.Data.Detail, dataType, 0)
result := make([]interface{}, len(detailItems))
for i, item := range detailItems {
result[i] = item
}
return result
}
func (c *AccountReportSync) SaveSum(ctx context.Context, data interface{}) (int64, error) {
sumItem, ok := data.(*dto.CidAccountReportSumItem)
if !ok {
return 0, fmt.Errorf("数据类型错误,期望 CidAccountReportSumItem 类型")
}
res, err := copydata.CidAccountReportDetail.CreateSum(ctx, sumItem)
if err != nil {
return 0, err
}
return res.Id, nil
}
func (c *AccountReportSync) SaveDetails(ctx context.Context, data []interface{}) (int64, int64, error) {
detailItems := make([]*dto.CidAccountReportDetailItem, len(data))
for i, item := range data {
detailItem, ok := item.(*dto.CidAccountReportDetailItem)
if !ok {
return 0, 0, fmt.Errorf("第 %d 条数据类型错误", i)
}
detailItems[i] = detailItem
}
req := &dto.BatchCreateCidAccountReportDetailReq{
Items: detailItems,
}
res, err := copydata.CidAccountReportDetail.BatchCreate(ctx, req)
if err != nil {
return 0, 0, err
}
return res.SuccessCount, res.FailCount, nil
}

View File

@@ -0,0 +1,235 @@
package syncdata
type AccountReportRequest struct {
AdvertiserID int64 `json:"advertiser_id"`
StartTime int64 `json:"start_time"`
EndTime int64 `json:"end_time"`
SelectColumns []string `json:"select_columns"`
GroupType int `json:"group_type"`
QueryVersion int `json:"query_version"`
SelectParam *AccountSelectParam `json:"select_param,omitempty"`
PageInfo *PageInfo `json:"page_info,omitempty"`
}
type AccountSelectParam struct {
CampaignIDs []int64 `json:"campaign_ids,omitempty"`
AuthorID int64 `json:"author_id,omitempty"`
AdTypeStr string `json:"ad_type_str,omitempty"`
MarketingObjective int `json:"marketing_objective,omitempty"`
DeliveryScenario int `json:"delivery_scenario,omitempty"`
DeliveryMethod int `json:"delivery_method,omitempty"`
SupportType string `json:"support_type,omitempty"`
OcpcActionType string `json:"ocpc_action_type,omitempty"`
SpeedType string `json:"speed_type,omitempty"`
ItemType string `json:"item_type,omitempty"`
CreativeBuildType string `json:"creative_build_type,omitempty"`
AdScene string `json:"ad_scene,omitempty"`
IncrementExploreType []int `json:"increment_explore_type,omitempty"`
}
type PageInfo struct {
CurrentPage int `json:"current_page"`
PageSize int `json:"page_size"`
TotalCount int `json:"total_count"`
}
type AccountReportResponse struct {
Code int `json:"code"`
Message string `json:"message"`
Data *AccountReportData `json:"data"`
}
type AccountReportData struct {
Sum *AccountReportSum `json:"sum"`
Detail []*AccountReportItem `json:"detail"`
TotalCount int `json:"total_count"`
}
type AccountReportSum struct {
T0OrderPaymentAmt string `json:"t0_order_payment_amt"`
CreativeMaterialType string `json:"creative_material_type"`
LiveName string `json:"live_name"`
AuthorId string `json:"author_id"`
PicUrl string `json:"pic_url"`
PicName string `json:"pic_name"`
PicId string `json:"pic_id"`
CoverUrl string `json:"cover_url"`
CoverId int64 `json:"cover_id"`
ItemOrderConversionRatio *float64 `json:"item_order_conversion_ratio"`
ItemCardClickRatio *float64 `json:"item_card_click_ratio"`
ItemCardClkCnt *int64 `json:"item_card_clk_cnt"`
LivePlayCntCost *float64 `json:"live_play_cnt_cost"`
AdMerchantFollowCost *float64 `json:"ad_merchant_follow_cost"`
AdMerchantFollow *int64 `json:"ad_merchant_follow"`
NetT0OrderCnt *int64 `json:"net_t0_order_cnt"`
NetT0Roi *float64 `json:"net_t0_roi"`
NetT0Gmv *float64 `json:"net_t0_gmv"`
PhotoName string `json:"photo_name"`
PhotoIdStr string `json:"photo_id_str"`
PhotoId string `json:"photo_id"`
ModPriceSegment string `json:"mod_price_segment"`
AgeSegment string `json:"age_segment"`
Province string `json:"province"`
Gender string `json:"gender"`
AdPhotoPlayedFiveRatio *float64 `json:"ad_photo_played_five_ratio"`
AdPhotoPlayedThreeRatio *float64 `json:"ad_photo_played_three_ratio"`
OrderSubmitRoi *float64 `json:"order_submit_roi"`
OrderSubmitAmt *int64 `json:"order_submit_amt"`
EventOrderSubmitCost *float64 `json:"event_order_submit_cost"`
EventOrderSubmit *int64 `json:"event_order_submit"`
EventOrderPaidRoi *float64 `json:"event_order_paid_roi"`
EventAppInvoked *int64 `json:"event_app_invoked"`
EventAddShoppingCart *int64 `json:"event_add_shopping_cart"`
ConversionNumCost *float64 `json:"conversion_num_cost"`
AdEffectivePlayNum *int64 `json:"ad_effective_play_num"`
AdItemClick *int64 `json:"ad_item_click"`
MerchantProductId string `json:"merchant_product_id"`
CostTotal *float64 `json:"cost_total"`
AdShow *int64 `json:"ad_show"`
AdShow1kCost *float64 `json:"ad_show1k_cost"`
Impression *int64 `json:"impression"`
PhotoClick *int64 `json:"photo_click"`
PhotoClickRatio *float64 `json:"photo_click_ratio"`
Click *int64 `json:"click"`
ActionbarClick *int64 `json:"actionbar_click"`
ActionbarClickCost *float64 `json:"actionbar_click_cost"`
EspClickRatio *float64 `json:"esp_click_ratio"`
ActionRatio *float64 `json:"action_ratio"`
AdItemClickCount *int64 `json:"ad_item_click_count"`
EspLivePlayedSeconds *int64 `json:"esp_live_played_seconds"`
PlayedThreeSeconds *int64 `json:"played_three_seconds"`
Play3sRatio *float64 `json:"play3s_ratio"`
PlayedFiveSeconds *int64 `json:"played_five_seconds"`
Play5sRatio *float64 `json:"play5s_ratio"`
PlayedEnd *int64 `json:"played_end"`
PlayEndRatio *float64 `json:"play_end_ratio"`
Share *int64 `json:"share"`
Comment *int64 `json:"comment"`
Likes *int64 `json:"likes"`
Report *int64 `json:"report"`
Block *int64 `json:"block"`
ItemNegative *int64 `json:"item_negative"`
LiveShare *int64 `json:"live_share"`
LiveComment *int64 `json:"live_comment"`
LiveReward *int64 `json:"live_reward"`
EffectivePlayCount *int64 `json:"effective_play_count"`
EffectivePlayRatio *float64 `json:"effective_play_ratio"`
ConversionNum *int64 `json:"conversion_num"`
ConversionCostEsp *float64 `json:"conversion_cost_esp"`
Roi *float64 `json:"roi"`
Gmv *float64 `json:"gmv"`
T0Gmv *float64 `json:"t0_gmv"`
T1Gmv *float64 `json:"t1_gmv"`
T7Gmv *float64 `json:"t7_gmv"`
T15Gmv *float64 `json:"t15_gmv"`
T30Gmv *float64 `json:"t30_gmv"`
T0Roi *float64 `json:"t0_roi"`
T1Roi *float64 `json:"t1_roi"`
T7Roi *float64 `json:"t7_roi"`
T15Roi *float64 `json:"t15_roi"`
T30Roi *float64 `json:"t30_roi"`
PaiedOrder *int64 `json:"paied_order"`
OrderRatio *float64 `json:"order_ratio"`
T0OrderCnt *int64 `json:"t0_order_cnt"`
T0OrderCntCost *float64 `json:"t0_order_cnt_cost"`
T0OrderCntRatio *float64 `json:"t0_order_cnt_ratio"`
T1OrderCnt *int64 `json:"t1_order_cnt"`
T3OrderCnt *int64 `json:"t3_order_cnt"`
T7OrderCnt *int64 `json:"t7_order_cnt"`
T15OrderCnt *int64 `json:"t15_order_cnt"`
T30OrderCnt *int64 `json:"t30_order_cnt"`
MerchantRecoFans *int64 `json:"merchant_reco_fans"`
T1Retention *float64 `json:"t1_retention"`
T7Retention *float64 `json:"t7_retention"`
T15Retention *float64 `json:"t15_retention"`
T30Retention *float64 `json:"t30_retention"`
T1RetentionRatio *float64 `json:"t1_retention_ratio"`
T7RetentionRatio *float64 `json:"t7_retention_ratio"`
T15RetentionRatio *float64 `json:"t15_retention_ratio"`
T30RetentionRatio *float64 `json:"t30_retention_ratio"`
ReservationSuccess *int64 `json:"reservation_success"`
ReservationCost *float64 `json:"reservation_cost"`
StandardLivePlayedStarted *int64 `json:"standard_live_played_started"`
AdLivePlayCnt *int64 `json:"ad_live_play_cnt"`
AdLivePlayCntCost *float64 `json:"ad_live_play_cnt_cost"`
LiveAudienceCost *float64 `json:"live_audience_cost"`
LiveEventGoodsView *int64 `json:"live_event_goods_view"`
GoodsClickRatio *float64 `json:"goods_click_ratio"`
DirectAttrPlatNewBuyerCnt *int64 `json:"direct_attr_plat_new_buyer_cnt"`
T30AttrPlatTotalBuyerCnt *int64 `json:"t30_attr_plat_total_buyer_cnt"`
DirectAttrSellerNewBuyerCnt *int64 `json:"direct_attr_seller_new_buyer_cnt"`
T30AttrSellerTotalBuyerCnt *int64 `json:"t30_attr_seller_total_buyer_cnt"`
T3Gmv *float64 `json:"t3_gmv"`
T3Roi *float64 `json:"t3_roi"`
T7IndirectOrderAmt *float64 `json:"t7_indirect_order_amt"`
T7IndirectOrderCnt *int64 `json:"t7_indirect_order_cnt"`
FansT0GmvPerFans *float64 `json:"fans_t0_gmv_per_fans"`
FansT3GmvPerFans *float64 `json:"fans_t3_gmv_per_fans"`
FansT7GmvPerFans *float64 `json:"fans_t7_gmv_per_fans"`
FansT15GmvPerFans *float64 `json:"fans_t15_gmv_per_fans"`
FansT30GmvPerFans *float64 `json:"fans_t30_gmv_per_fans"`
RecoFansCost *float64 `json:"reco_fans_cost"`
QcpxWhiteboxDirectOrderPaymentAmt *float64 `json:"qcpx_whitebox_direct_order_payment_amt"`
QcpxWhiteboxDirectOrderCnt *int64 `json:"qcpx_whitebox_direct_order_cnt"`
FansT0Gmv *float64 `json:"fans_t0_gmv"`
FansT1Gmv *float64 `json:"fans_t1_gmv"`
FansT7Gmv *float64 `json:"fans_t7_gmv"`
FansT15Gmv *float64 `json:"fans_t15_gmv"`
FansT30Gmv *float64 `json:"fans_t30_gmv"`
FansT0Roi *float64 `json:"fans_t0_roi"`
FansT1Roi *float64 `json:"fans_t1_roi"`
FansT7Roi *float64 `json:"fans_t7_roi"`
FansT15Roi *float64 `json:"fans_t15_roi"`
FansT30Roi *float64 `json:"fans_t30_roi"`
T0ShopNewBuyerOrderPaymentAmt *float64 `json:"t0_shop_new_buyer_order_payment_amt"`
T1ShopNewBuyerOrderPaymentAmt *float64 `json:"t1_shop_new_buyer_order_payment_amt"`
T3ShopNewBuyerOrderPaymentAmt *float64 `json:"t3_shop_new_buyer_order_payment_amt"`
T7ShopNewBuyerOrderPaymentAmt *float64 `json:"t7_shop_new_buyer_order_payment_amt"`
T15ShopNewBuyerOrderPaymentAmt *float64 `json:"t15_shop_new_buyer_order_payment_amt"`
T30ShopNewBuyerOrderPaymentAmt *float64 `json:"t30_shop_new_buyer_order_payment_amt"`
T0ShopNewBuyerOrderCnt *int64 `json:"t0_shop_new_buyer_order_cnt"`
T1ShopNewBuyerOrderCnt *int64 `json:"t1_shop_new_buyer_order_cnt"`
T3ShopNewBuyerOrderCnt *int64 `json:"t3_shop_new_buyer_order_cnt"`
T7ShopNewBuyerOrderCnt *int64 `json:"t7_shop_new_buyer_order_cnt"`
T15ShopNewBuyerOrderCnt *int64 `json:"t15_shop_new_buyer_order_cnt"`
T30ShopNewBuyerOrderCnt *int64 `json:"t30_shop_new_buyer_order_cnt"`
T1NewBuyerRepurchaseRatio *float64 `json:"t1_new_buyer_repurchase_ratio"`
T3NewBuyerRepurchaseRatio *float64 `json:"t3_new_buyer_repurchase_ratio"`
T7NewBuyerRepurchaseRatio *float64 `json:"t7_new_buyer_repurchase_ratio"`
T15NewBuyerRepurchaseRatio *float64 `json:"t15_new_buyer_repurchase_ratio"`
T30NewBuyerRepurchaseRatio *float64 `json:"t30_new_buyer_repurchase_ratio"`
T0ShopNewBuyerRoi *float64 `json:"t0_shop_new_buyer_roi"`
T1ShopNewBuyerRoi *float64 `json:"t1_shop_new_buyer_roi"`
T3ShopNewBuyerRoi *float64 `json:"t3_shop_new_buyer_roi"`
T7ShopNewBuyerRoi *float64 `json:"t7_shop_new_buyer_roi"`
T15ShopNewBuyerRoi *float64 `json:"t15_shop_new_buyer_roi"`
T30ShopNewBuyerRoi *float64 `json:"t30_shop_new_buyer_roi"`
CreateCardOrderCnt *int64 `json:"create_card_order_cnt"`
ForwardTsCreateCardOrderCnt *int64 `json:"forward_ts_create_card_order_cnt"`
CreateCardOrderCost *float64 `json:"create_card_order_cost"`
ForwardTsCreateCardOrderCost *float64 `json:"forward_ts_create_card_order_cost"`
ActivateCardOrderCnt *int64 `json:"activate_card_order_cnt"`
ForwardTsActivateCardOrderCnt *int64 `json:"forward_ts_activate_card_order_cnt"`
ActivateCardOrderCost *float64 `json:"activate_card_order_cost"`
ForwardTsActivateCardOrderCost *float64 `json:"forward_ts_activate_card_order_cost"`
CreateCardOrderRatio *float64 `json:"create_card_order_ratio"`
ForwardTsCreateCardOrderRatio *float64 `json:"forward_ts_create_card_order_ratio"`
ActivateCardOrderCntRatio *float64 `json:"activate_card_order_cnt_ratio"`
ForwardTsActivateCardOrderRatio *float64 `json:"forward_ts_activate_card_order_ratio"`
LivePlayCnt *int64 `json:"live_play_cnt"`
ItemEntranceClkCnt *int64 `json:"item_entrance_clk_cnt"`
ShowCnt *int64 `json:"show_cnt"`
ReportDateStr string `json:"report_date_str"`
CampaignId *int64 `json:"campaign_id"`
CampaignName string `json:"campaign_name"`
UnitId *int64 `json:"unit_id"`
UnitName string `json:"unit_name"`
CreativeId *int64 `json:"creative_id"`
CreativeName string `json:"creative_name"`
CidActualRoiAfterSubsidy *float64 `json:"cid_actual_roi_after_subsidy"`
CidCouponAmount *int64 `json:"cid_coupon_amount"`
CidCouponCallbackPaidRefundAmount *int64 `json:"cid_coupon_callback_paid_refund_amount"`
CidVoucherCost *float64 `json:"cid_voucher_cost"`
}
type AccountReportItem AccountReportSum

View File

@@ -0,0 +1,79 @@
package syncdata
import (
"context"
)
type ReportSyncable interface {
FetchReport(ctx context.Context, params interface{}) (interface{}, error)
ConvertToSum(apiData interface{}, dataType string) interface{}
ConvertToDetails(apiData interface{}, dataType string) []interface{}
SaveSum(ctx context.Context, data interface{}) (int64, error)
SaveDetails(ctx context.Context, data []interface{}) (successCount, failCount int64, err error)
}
type BaseReportSync struct {
httpClient *HttpClient
}
func NewBaseReportSync() *BaseReportSync {
return &BaseReportSync{
httpClient: NewHttpClient("", 0),
}
}
func (b *BaseReportSync) FetchReport(ctx context.Context, params interface{}) (interface{}, error) {
return nil, nil
}
func (b *BaseReportSync) ConvertToSum(apiData interface{}, dataType string) interface{} {
return nil
}
func (b *BaseReportSync) ConvertToDetails(apiData interface{}, dataType string) []interface{} {
return nil
}
func (b *BaseReportSync) SaveSum(ctx context.Context, data interface{}) (int64, error) {
return 0, nil
}
func (b *BaseReportSync) SaveDetails(ctx context.Context, data []interface{}) (int64, int64, error) {
return 0, 0, nil
}
func (b *BaseReportSync) ExecuteSync(ctx context.Context, syncer ReportSyncable, params interface{}, dataType string, useMock bool) (*SyncResult, error) {
result := &SyncResult{}
apiData, err := syncer.FetchReport(ctx, params)
if err != nil {
result.Error = err
return result, err
}
sumData := syncer.ConvertToSum(apiData, dataType)
if sumData != nil {
sumID, err := syncer.SaveSum(ctx, sumData)
if err != nil {
result.Error = err
return result, err
}
result.SumSuccess = true
result.SumID = sumID
}
detailData := syncer.ConvertToDetails(apiData, dataType)
if len(detailData) > 0 {
successCount, failCount, err := syncer.SaveDetails(ctx, detailData)
if err != nil {
result.Error = err
return result, err
}
result.DetailSuccess = true
result.DetailCount = len(detailData)
result.DetailSuccessCount = successCount
result.DetailFailCount = failCount
}
return result, nil
}

417
syncdata/data_converter.go Normal file
View File

@@ -0,0 +1,417 @@
package syncdata
import (
"cid/model/dto/copydata"
)
type DataConverter struct{}
func NewDataConverter() *DataConverter {
return &DataConverter{}
}
func (c *DataConverter) ConvertToSumItem(apiData *AccountReportSum, dataType string, pageNumber int) *copydata.CidAccountReportSumItem {
if apiData == nil {
return nil
}
return &copydata.CidAccountReportSumItem{
DataType: dataType,
T0OrderPaymentAmt: apiData.T0OrderPaymentAmt,
CreativeMaterialType: apiData.CreativeMaterialType,
LiveName: apiData.LiveName,
AuthorId: apiData.AuthorId,
PicUrl: apiData.PicUrl,
PicName: apiData.PicName,
PicId: apiData.PicId,
CoverUrl: apiData.CoverUrl,
CoverId: apiData.CoverId,
ItemOrderConversionRatio: apiData.ItemOrderConversionRatio,
ItemCardClickRatio: apiData.ItemCardClickRatio,
ItemCardClkCnt: apiData.ItemCardClkCnt,
LivePlayCntCost: apiData.LivePlayCntCost,
AdMerchantFollowCost: apiData.AdMerchantFollowCost,
AdMerchantFollow: apiData.AdMerchantFollow,
NetT0OrderCnt: apiData.NetT0OrderCnt,
NetT0Roi: apiData.NetT0Roi,
NetT0Gmv: apiData.NetT0Gmv,
PhotoName: apiData.PhotoName,
PhotoIdStr: apiData.PhotoIdStr,
PhotoId: apiData.PhotoId,
ModPriceSegment: apiData.ModPriceSegment,
AgeSegment: apiData.AgeSegment,
Province: apiData.Province,
Gender: apiData.Gender,
AdPhotoPlayedFiveRatio: apiData.AdPhotoPlayedFiveRatio,
AdPhotoPlayedThreeRatio: apiData.AdPhotoPlayedThreeRatio,
OrderSubmitRoi: apiData.OrderSubmitRoi,
OrderSubmitAmt: apiData.OrderSubmitAmt,
EventOrderSubmitCost: apiData.EventOrderSubmitCost,
EventOrderSubmit: apiData.EventOrderSubmit,
EventOrderPaidRoi: apiData.EventOrderPaidRoi,
EventAppInvoked: apiData.EventAppInvoked,
EventAddShoppingCart: apiData.EventAddShoppingCart,
ConversionNumCost: apiData.ConversionNumCost,
AdEffectivePlayNum: apiData.AdEffectivePlayNum,
AdItemClick: apiData.AdItemClick,
MerchantProductId: apiData.MerchantProductId,
CostTotal: apiData.CostTotal,
AdShow: apiData.AdShow,
AdShow1kCost: apiData.AdShow1kCost,
Impression: apiData.Impression,
PhotoClick: apiData.PhotoClick,
PhotoClickRatio: apiData.PhotoClickRatio,
Click: apiData.Click,
ActionbarClick: apiData.ActionbarClick,
ActionbarClickCost: apiData.ActionbarClickCost,
EspClickRatio: apiData.EspClickRatio,
ActionRatio: apiData.ActionRatio,
AdItemClickCount: apiData.AdItemClickCount,
EspLivePlayedSeconds: apiData.EspLivePlayedSeconds,
PlayedThreeSeconds: apiData.PlayedThreeSeconds,
Play3sRatio: apiData.Play3sRatio,
PlayedFiveSeconds: apiData.PlayedFiveSeconds,
Play5sRatio: apiData.Play5sRatio,
PlayedEnd: apiData.PlayedEnd,
PlayEndRatio: apiData.PlayEndRatio,
Share: apiData.Share,
Comment: apiData.Comment,
Likes: apiData.Likes,
Report: apiData.Report,
Block: apiData.Block,
ItemNegative: apiData.ItemNegative,
LiveShare: apiData.LiveShare,
LiveComment: apiData.LiveComment,
LiveReward: apiData.LiveReward,
EffectivePlayCount: apiData.EffectivePlayCount,
EffectivePlayRatio: apiData.EffectivePlayRatio,
ConversionNum: apiData.ConversionNum,
ConversionCostEsp: apiData.ConversionCostEsp,
Roi: apiData.Roi,
Gmv: apiData.Gmv,
T0Gmv: apiData.T0Gmv,
T1Gmv: apiData.T1Gmv,
T3Gmv: apiData.T3Gmv,
T7Gmv: apiData.T7Gmv,
T15Gmv: apiData.T15Gmv,
T30Gmv: apiData.T30Gmv,
T0Roi: apiData.T0Roi,
T1Roi: apiData.T1Roi,
T3Roi: apiData.T3Roi,
T7Roi: apiData.T7Roi,
T15Roi: apiData.T15Roi,
T30Roi: apiData.T30Roi,
PaiedOrder: apiData.PaiedOrder,
OrderRatio: apiData.OrderRatio,
T0OrderCnt: apiData.T0OrderCnt,
T0OrderCntCost: apiData.T0OrderCntCost,
T0OrderCntRatio: apiData.T0OrderCntRatio,
T1OrderCnt: apiData.T1OrderCnt,
T3OrderCnt: apiData.T3OrderCnt,
T7OrderCnt: apiData.T7OrderCnt,
T15OrderCnt: apiData.T15OrderCnt,
T30OrderCnt: apiData.T30OrderCnt,
MerchantRecoFans: apiData.MerchantRecoFans,
T1Retention: apiData.T1Retention,
T7Retention: apiData.T7Retention,
T15Retention: apiData.T15Retention,
T30Retention: apiData.T30Retention,
T1RetentionRatio: apiData.T1RetentionRatio,
T7RetentionRatio: apiData.T7RetentionRatio,
T15RetentionRatio: apiData.T15RetentionRatio,
T30RetentionRatio: apiData.T30RetentionRatio,
ReservationSuccess: apiData.ReservationSuccess,
ReservationCost: apiData.ReservationCost,
StandardLivePlayedStarted: apiData.StandardLivePlayedStarted,
AdLivePlayCnt: apiData.AdLivePlayCnt,
AdLivePlayCntCost: apiData.AdLivePlayCntCost,
LiveAudienceCost: apiData.LiveAudienceCost,
LiveEventGoodsView: apiData.LiveEventGoodsView,
GoodsClickRatio: apiData.GoodsClickRatio,
DirectAttrPlatNewBuyerCnt: apiData.DirectAttrPlatNewBuyerCnt,
T30AttrPlatTotalBuyerCnt: apiData.T30AttrPlatTotalBuyerCnt,
DirectAttrSellerNewBuyerCnt: apiData.DirectAttrSellerNewBuyerCnt,
T30AttrSellerTotalBuyerCnt: apiData.T30AttrSellerTotalBuyerCnt,
T7IndirectOrderAmt: apiData.T7IndirectOrderAmt,
T7IndirectOrderCnt: apiData.T7IndirectOrderCnt,
FansT0GmvPerFans: apiData.FansT0GmvPerFans,
FansT3GmvPerFans: apiData.FansT3GmvPerFans,
FansT7GmvPerFans: apiData.FansT7GmvPerFans,
FansT15GmvPerFans: apiData.FansT15GmvPerFans,
FansT30GmvPerFans: apiData.FansT30GmvPerFans,
RecoFansCost: apiData.RecoFansCost,
QcpxWhiteboxDirectOrderPaymentAmt: apiData.QcpxWhiteboxDirectOrderPaymentAmt,
QcpxWhiteboxDirectOrderCnt: apiData.QcpxWhiteboxDirectOrderCnt,
FansT0Gmv: apiData.FansT0Gmv,
FansT1Gmv: apiData.FansT1Gmv,
FansT7Gmv: apiData.FansT7Gmv,
FansT15Gmv: apiData.FansT15Gmv,
FansT30Gmv: apiData.FansT30Gmv,
FansT0Roi: apiData.FansT0Roi,
FansT1Roi: apiData.FansT1Roi,
FansT7Roi: apiData.FansT7Roi,
FansT15Roi: apiData.FansT15Roi,
FansT30Roi: apiData.FansT30Roi,
T0ShopNewBuyerOrderPaymentAmt: apiData.T0ShopNewBuyerOrderPaymentAmt,
T1ShopNewBuyerOrderPaymentAmt: apiData.T1ShopNewBuyerOrderPaymentAmt,
T3ShopNewBuyerOrderPaymentAmt: apiData.T3ShopNewBuyerOrderPaymentAmt,
T7ShopNewBuyerOrderPaymentAmt: apiData.T7ShopNewBuyerOrderPaymentAmt,
T15ShopNewBuyerOrderPaymentAmt: apiData.T15ShopNewBuyerOrderPaymentAmt,
T30ShopNewBuyerOrderPaymentAmt: apiData.T30ShopNewBuyerOrderPaymentAmt,
T0ShopNewBuyerOrderCnt: apiData.T0ShopNewBuyerOrderCnt,
T1ShopNewBuyerOrderCnt: apiData.T1ShopNewBuyerOrderCnt,
T3ShopNewBuyerOrderCnt: apiData.T3ShopNewBuyerOrderCnt,
T7ShopNewBuyerOrderCnt: apiData.T7ShopNewBuyerOrderCnt,
T15ShopNewBuyerOrderCnt: apiData.T15ShopNewBuyerOrderCnt,
T30ShopNewBuyerOrderCnt: apiData.T30ShopNewBuyerOrderCnt,
T1NewBuyerRepurchaseRatio: apiData.T1NewBuyerRepurchaseRatio,
T3NewBuyerRepurchaseRatio: apiData.T3NewBuyerRepurchaseRatio,
T7NewBuyerRepurchaseRatio: apiData.T7NewBuyerRepurchaseRatio,
T15NewBuyerRepurchaseRatio: apiData.T15NewBuyerRepurchaseRatio,
T30NewBuyerRepurchaseRatio: apiData.T30NewBuyerRepurchaseRatio,
T0ShopNewBuyerRoi: apiData.T0ShopNewBuyerRoi,
T1ShopNewBuyerRoi: apiData.T1ShopNewBuyerRoi,
T3ShopNewBuyerRoi: apiData.T3ShopNewBuyerRoi,
T7ShopNewBuyerRoi: apiData.T7ShopNewBuyerRoi,
T15ShopNewBuyerRoi: apiData.T15ShopNewBuyerRoi,
T30ShopNewBuyerRoi: apiData.T30ShopNewBuyerRoi,
CreateCardOrderCnt: apiData.CreateCardOrderCnt,
ForwardTsCreateCardOrderCnt: apiData.ForwardTsCreateCardOrderCnt,
CreateCardOrderCost: apiData.CreateCardOrderCost,
ForwardTsCreateCardOrderCost: apiData.ForwardTsCreateCardOrderCost,
ActivateCardOrderCnt: apiData.ActivateCardOrderCnt,
ForwardTsActivateCardOrderCnt: apiData.ForwardTsActivateCardOrderCnt,
ActivateCardOrderCost: apiData.ActivateCardOrderCost,
ForwardTsActivateCardOrderCost: apiData.ForwardTsActivateCardOrderCost,
CreateCardOrderRatio: apiData.CreateCardOrderRatio,
ForwardTsCreateCardOrderRatio: apiData.ForwardTsCreateCardOrderRatio,
ActivateCardOrderCntRatio: apiData.ActivateCardOrderCntRatio,
ForwardTsActivateCardOrderRatio: apiData.ForwardTsActivateCardOrderRatio,
LivePlayCnt: apiData.LivePlayCnt,
ItemEntranceClkCnt: apiData.ItemEntranceClkCnt,
ShowCnt: apiData.ShowCnt,
ReportDateStr: apiData.ReportDateStr,
PageNumber: pageNumber,
CampaignId: apiData.CampaignId,
CampaignName: apiData.CampaignName,
UnitId: apiData.UnitId,
UnitName: apiData.UnitName,
CreativeId: apiData.CreativeId,
CreativeName: apiData.CreativeName,
CidActualRoiAfterSubsidy: apiData.CidActualRoiAfterSubsidy,
CidCouponAmount: apiData.CidCouponAmount,
CidCouponCallbackPaidRefundAmount: apiData.CidCouponCallbackPaidRefundAmount,
CidVoucherCost: apiData.CidVoucherCost,
}
}
func (c *DataConverter) ConvertToDetailItems(apiItems []*AccountReportItem, dataType string, pageNumber int) []*copydata.CidAccountReportDetailItem {
if len(apiItems) == 0 {
return nil
}
result := make([]*copydata.CidAccountReportDetailItem, 0, len(apiItems))
for _, item := range apiItems {
detailItem := c.convertItemToDetail(item, dataType, pageNumber)
result = append(result, detailItem)
}
return result
}
func (c *DataConverter) convertItemToDetail(apiItem *AccountReportItem, dataType string, pageNumber int) *copydata.CidAccountReportDetailItem {
if apiItem == nil {
return nil
}
item := (*AccountReportSum)(apiItem)
sumItem := c.ConvertToSumItem(item, dataType, pageNumber)
return &copydata.CidAccountReportDetailItem{
DataType: sumItem.DataType,
T0OrderPaymentAmt: sumItem.T0OrderPaymentAmt,
CreativeMaterialType: sumItem.CreativeMaterialType,
LiveName: sumItem.LiveName,
AuthorId: sumItem.AuthorId,
PicUrl: sumItem.PicUrl,
PicName: sumItem.PicName,
PicId: sumItem.PicId,
CoverUrl: sumItem.CoverUrl,
CoverId: sumItem.CoverId,
ItemOrderConversionRatio: sumItem.ItemOrderConversionRatio,
ItemCardClickRatio: sumItem.ItemCardClickRatio,
ItemCardClkCnt: sumItem.ItemCardClkCnt,
LivePlayCntCost: sumItem.LivePlayCntCost,
AdMerchantFollowCost: sumItem.AdMerchantFollowCost,
AdMerchantFollow: sumItem.AdMerchantFollow,
NetT0OrderCnt: sumItem.NetT0OrderCnt,
NetT0Roi: sumItem.NetT0Roi,
NetT0Gmv: sumItem.NetT0Gmv,
PhotoName: sumItem.PhotoName,
PhotoIdStr: sumItem.PhotoIdStr,
PhotoId: sumItem.PhotoId,
ModPriceSegment: sumItem.ModPriceSegment,
AgeSegment: sumItem.AgeSegment,
Province: sumItem.Province,
Gender: sumItem.Gender,
AdPhotoPlayedFiveRatio: sumItem.AdPhotoPlayedFiveRatio,
AdPhotoPlayedThreeRatio: sumItem.AdPhotoPlayedThreeRatio,
OrderSubmitRoi: sumItem.OrderSubmitRoi,
OrderSubmitAmt: sumItem.OrderSubmitAmt,
EventOrderSubmitCost: sumItem.EventOrderSubmitCost,
EventOrderSubmit: sumItem.EventOrderSubmit,
EventOrderPaidRoi: sumItem.EventOrderPaidRoi,
EventAppInvoked: sumItem.EventAppInvoked,
EventAddShoppingCart: sumItem.EventAddShoppingCart,
ConversionNumCost: sumItem.ConversionNumCost,
AdEffectivePlayNum: sumItem.AdEffectivePlayNum,
AdItemClick: sumItem.AdItemClick,
MerchantProductId: sumItem.MerchantProductId,
CostTotal: sumItem.CostTotal,
AdShow: sumItem.AdShow,
AdShow1kCost: sumItem.AdShow1kCost,
Impression: sumItem.Impression,
PhotoClick: sumItem.PhotoClick,
PhotoClickRatio: sumItem.PhotoClickRatio,
Click: sumItem.Click,
ActionbarClick: sumItem.ActionbarClick,
ActionbarClickCost: sumItem.ActionbarClickCost,
EspClickRatio: sumItem.EspClickRatio,
ActionRatio: sumItem.ActionRatio,
AdItemClickCount: sumItem.AdItemClickCount,
EspLivePlayedSeconds: sumItem.EspLivePlayedSeconds,
PlayedThreeSeconds: sumItem.PlayedThreeSeconds,
Play3sRatio: sumItem.Play3sRatio,
PlayedFiveSeconds: sumItem.PlayedFiveSeconds,
Play5sRatio: sumItem.Play5sRatio,
PlayedEnd: sumItem.PlayedEnd,
PlayEndRatio: sumItem.PlayEndRatio,
Share: sumItem.Share,
Comment: sumItem.Comment,
Likes: sumItem.Likes,
Report: sumItem.Report,
Block: sumItem.Block,
ItemNegative: sumItem.ItemNegative,
LiveShare: sumItem.LiveShare,
LiveComment: sumItem.LiveComment,
LiveReward: sumItem.LiveReward,
EffectivePlayCount: sumItem.EffectivePlayCount,
EffectivePlayRatio: sumItem.EffectivePlayRatio,
ConversionNum: sumItem.ConversionNum,
ConversionCostEsp: sumItem.ConversionCostEsp,
Roi: sumItem.Roi,
Gmv: sumItem.Gmv,
T0Gmv: sumItem.T0Gmv,
T1Gmv: sumItem.T1Gmv,
T3Gmv: sumItem.T3Gmv,
T7Gmv: sumItem.T7Gmv,
T15Gmv: sumItem.T15Gmv,
T30Gmv: sumItem.T30Gmv,
T0Roi: sumItem.T0Roi,
T1Roi: sumItem.T1Roi,
T3Roi: sumItem.T3Roi,
T7Roi: sumItem.T7Roi,
T15Roi: sumItem.T15Roi,
T30Roi: sumItem.T30Roi,
PaiedOrder: sumItem.PaiedOrder,
OrderRatio: sumItem.OrderRatio,
T0OrderCnt: sumItem.T0OrderCnt,
T0OrderCntCost: sumItem.T0OrderCntCost,
T0OrderCntRatio: sumItem.T0OrderCntRatio,
T1OrderCnt: sumItem.T1OrderCnt,
T3OrderCnt: sumItem.T3OrderCnt,
T7OrderCnt: sumItem.T7OrderCnt,
T15OrderCnt: sumItem.T15OrderCnt,
T30OrderCnt: sumItem.T30OrderCnt,
MerchantRecoFans: sumItem.MerchantRecoFans,
T1Retention: sumItem.T1Retention,
T7Retention: sumItem.T7Retention,
T15Retention: sumItem.T15Retention,
T30Retention: sumItem.T30Retention,
T1RetentionRatio: sumItem.T1RetentionRatio,
T7RetentionRatio: sumItem.T7RetentionRatio,
T15RetentionRatio: sumItem.T15RetentionRatio,
T30RetentionRatio: sumItem.T30RetentionRatio,
ReservationSuccess: sumItem.ReservationSuccess,
ReservationCost: sumItem.ReservationCost,
StandardLivePlayedStarted: sumItem.StandardLivePlayedStarted,
AdLivePlayCnt: sumItem.AdLivePlayCnt,
AdLivePlayCntCost: sumItem.AdLivePlayCntCost,
LiveAudienceCost: sumItem.LiveAudienceCost,
LiveEventGoodsView: sumItem.LiveEventGoodsView,
GoodsClickRatio: sumItem.GoodsClickRatio,
DirectAttrPlatNewBuyerCnt: sumItem.DirectAttrPlatNewBuyerCnt,
T30AttrPlatTotalBuyerCnt: sumItem.T30AttrPlatTotalBuyerCnt,
DirectAttrSellerNewBuyerCnt: sumItem.DirectAttrSellerNewBuyerCnt,
T30AttrSellerTotalBuyerCnt: sumItem.T30AttrSellerTotalBuyerCnt,
T7IndirectOrderAmt: sumItem.T7IndirectOrderAmt,
T7IndirectOrderCnt: sumItem.T7IndirectOrderCnt,
FansT0GmvPerFans: sumItem.FansT0GmvPerFans,
FansT3GmvPerFans: sumItem.FansT3GmvPerFans,
FansT7GmvPerFans: sumItem.FansT7GmvPerFans,
FansT15GmvPerFans: sumItem.FansT15GmvPerFans,
FansT30GmvPerFans: sumItem.FansT30GmvPerFans,
RecoFansCost: sumItem.RecoFansCost,
QcpxWhiteboxDirectOrderPaymentAmt: sumItem.QcpxWhiteboxDirectOrderPaymentAmt,
QcpxWhiteboxDirectOrderCnt: sumItem.QcpxWhiteboxDirectOrderCnt,
FansT0Gmv: sumItem.FansT0Gmv,
FansT1Gmv: sumItem.FansT1Gmv,
FansT7Gmv: sumItem.FansT7Gmv,
FansT15Gmv: sumItem.FansT15Gmv,
FansT30Gmv: sumItem.FansT30Gmv,
FansT0Roi: sumItem.FansT0Roi,
FansT1Roi: sumItem.FansT1Roi,
FansT7Roi: sumItem.FansT7Roi,
FansT15Roi: sumItem.FansT15Roi,
FansT30Roi: sumItem.FansT30Roi,
T0ShopNewBuyerOrderPaymentAmt: sumItem.T0ShopNewBuyerOrderPaymentAmt,
T1ShopNewBuyerOrderPaymentAmt: sumItem.T1ShopNewBuyerOrderPaymentAmt,
T3ShopNewBuyerOrderPaymentAmt: sumItem.T3ShopNewBuyerOrderPaymentAmt,
T7ShopNewBuyerOrderPaymentAmt: sumItem.T7ShopNewBuyerOrderPaymentAmt,
T15ShopNewBuyerOrderPaymentAmt: sumItem.T15ShopNewBuyerOrderPaymentAmt,
T30ShopNewBuyerOrderPaymentAmt: sumItem.T30ShopNewBuyerOrderPaymentAmt,
T0ShopNewBuyerOrderCnt: sumItem.T0ShopNewBuyerOrderCnt,
T1ShopNewBuyerOrderCnt: sumItem.T1ShopNewBuyerOrderCnt,
T3ShopNewBuyerOrderCnt: sumItem.T3ShopNewBuyerOrderCnt,
T7ShopNewBuyerOrderCnt: sumItem.T7ShopNewBuyerOrderCnt,
T15ShopNewBuyerOrderCnt: sumItem.T15ShopNewBuyerOrderCnt,
T30ShopNewBuyerOrderCnt: sumItem.T30ShopNewBuyerOrderCnt,
T1NewBuyerRepurchaseRatio: sumItem.T1NewBuyerRepurchaseRatio,
T3NewBuyerRepurchaseRatio: sumItem.T3NewBuyerRepurchaseRatio,
T7NewBuyerRepurchaseRatio: sumItem.T7NewBuyerRepurchaseRatio,
T15NewBuyerRepurchaseRatio: sumItem.T15NewBuyerRepurchaseRatio,
T30NewBuyerRepurchaseRatio: sumItem.T30NewBuyerRepurchaseRatio,
T0ShopNewBuyerRoi: sumItem.T0ShopNewBuyerRoi,
T1ShopNewBuyerRoi: sumItem.T1ShopNewBuyerRoi,
T3ShopNewBuyerRoi: sumItem.T3ShopNewBuyerRoi,
T7ShopNewBuyerRoi: sumItem.T7ShopNewBuyerRoi,
T15ShopNewBuyerRoi: sumItem.T15ShopNewBuyerRoi,
T30ShopNewBuyerRoi: sumItem.T30ShopNewBuyerRoi,
CreateCardOrderCnt: sumItem.CreateCardOrderCnt,
ForwardTsCreateCardOrderCnt: sumItem.ForwardTsCreateCardOrderCnt,
CreateCardOrderCost: sumItem.CreateCardOrderCost,
ForwardTsCreateCardOrderCost: sumItem.ForwardTsCreateCardOrderCost,
ActivateCardOrderCnt: sumItem.ActivateCardOrderCnt,
ForwardTsActivateCardOrderCnt: sumItem.ForwardTsActivateCardOrderCnt,
ActivateCardOrderCost: sumItem.ActivateCardOrderCost,
ForwardTsActivateCardOrderCost: sumItem.ForwardTsActivateCardOrderCost,
CreateCardOrderRatio: sumItem.CreateCardOrderRatio,
ForwardTsCreateCardOrderRatio: sumItem.ForwardTsCreateCardOrderRatio,
ActivateCardOrderCntRatio: sumItem.ActivateCardOrderCntRatio,
ForwardTsActivateCardOrderRatio: sumItem.ForwardTsActivateCardOrderRatio,
LivePlayCnt: sumItem.LivePlayCnt,
ItemEntranceClkCnt: sumItem.ItemEntranceClkCnt,
ShowCnt: sumItem.ShowCnt,
ReportDateStr: sumItem.ReportDateStr,
PageNumber: pageNumber,
CampaignId: sumItem.CampaignId,
CampaignName: sumItem.CampaignName,
UnitId: sumItem.UnitId,
UnitName: sumItem.UnitName,
CreativeId: sumItem.CreativeId,
CreativeName: sumItem.CreativeName,
CidActualRoiAfterSubsidy: sumItem.CidActualRoiAfterSubsidy,
CidCouponAmount: sumItem.CidCouponAmount,
CidCouponCallbackPaidRefundAmount: sumItem.CidCouponCallbackPaidRefundAmount,
CidVoucherCost: sumItem.CidVoucherCost,
}
}

68
syncdata/http_client.go Normal file
View File

@@ -0,0 +1,68 @@
package syncdata
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
type HttpClient struct {
BaseURL string
Timeout time.Duration
HTTPClient *http.Client
}
func NewHttpClient(baseURL string, timeout time.Duration) *HttpClient {
if timeout == 0 {
timeout = 30 * time.Second
}
return &HttpClient{
BaseURL: baseURL,
Timeout: timeout,
HTTPClient: &http.Client{
Timeout: timeout,
},
}
}
func (c *HttpClient) Post(ctx context.Context, url string, body interface{}) ([]byte, error) {
jsonData, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("序列化请求失败:%w", err)
}
fullURL := url
if c.BaseURL != "" && len(url) > 0 && url[0] != '/' {
fullURL = c.BaseURL + url
} else if c.BaseURL != "" {
fullURL = c.BaseURL + url
}
req, err := http.NewRequestWithContext(ctx, "POST", fullURL, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("创建请求失败:%w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("请求失败:%w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应失败:%w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("HTTP 错误状态码:%d", resp.StatusCode)
}
return respBody, nil
}

329
syncdata/mock_generator.go Normal file
View File

@@ -0,0 +1,329 @@
package syncdata
import (
"math/rand"
"time"
)
type MockDataGenerator struct {
rand *rand.Rand
}
func NewMockDataGenerator() *MockDataGenerator {
return &MockDataGenerator{
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
}
}
func (m *MockDataGenerator) GenerateAccountReportRequest() *AccountReportRequest {
return &AccountReportRequest{
AdvertiserID: 10001,
StartTime: time.Now().AddDate(0, 0, -30).UnixNano() / 1e6,
EndTime: time.Now().UnixNano() / 1e6,
SelectColumns: []string{"impression", "click", "cost", "t0GMV"},
GroupType: 1,
QueryVersion: 1,
SelectParam: &AccountSelectParam{
CampaignIDs: []int64{1, 2, 3},
},
PageInfo: &PageInfo{
CurrentPage: 1,
PageSize: 10,
},
}
}
func (m *MockDataGenerator) GenerateAccountReportResponse() *AccountReportResponse {
return m.GenerateAccountReportResponseWithPage(1, 10)
}
func (m *MockDataGenerator) GenerateAccountReportResponseWithPage(page int, pageSize int) *AccountReportResponse {
sumData := m.generateSumData()
detailData := m.generateDetailDataByPage(page, pageSize)
totalCount := 23
return &AccountReportResponse{
Code: 0,
Message: "success",
Data: &AccountReportData{
Sum: sumData,
Detail: detailData,
TotalCount: totalCount,
},
}
}
func (m *MockDataGenerator) generateDetailDataByPage(page int, pageSize int) []*AccountReportItem {
totalCount := 23
if page < 1 || pageSize <= 0 {
return []*AccountReportItem{}
}
startIndex := (page - 1) * pageSize
if startIndex >= totalCount {
return []*AccountReportItem{}
}
endIndex := startIndex + pageSize
if endIndex > totalCount {
endIndex = totalCount
}
actualCount := endIndex - startIndex
items := make([]*AccountReportItem, actualCount)
for i := 0; i < actualCount; i++ {
itemIndex := startIndex + i + 1
campaignId := int64(itemIndex)
unitId := int64(itemIndex * 10)
creativeId := int64(itemIndex * 100)
campaignName := "测试计划_" + string(rune('A'+itemIndex-1))
unitName := "测试单元_" + string(rune('A'+itemIndex-1))
creativeName := "测试创意_" + string(rune('A'+itemIndex-1))
item := m.generateSumData()
item.CampaignId = &campaignId
item.UnitId = &unitId
item.CreativeId = &creativeId
item.CampaignName = campaignName
item.UnitName = unitName
item.CreativeName = creativeName
items[i] = (*AccountReportItem)(item)
}
return items
}
func (m *MockDataGenerator) generateSumData() *AccountReportSum {
cost := m.randomFloat(1000, 10000)
impression := m.randomInt64(10000, 100000)
click := m.randomInt64(100, 1000)
return &AccountReportSum{
T0OrderPaymentAmt: "888.99",
CreativeMaterialType: "视频素材类型",
LiveName: "测试直播间",
AuthorId: "123456",
PicUrl: "http://example.com/pic.jpg",
PicName: "图片名称",
PicId: "pic_123",
CoverUrl: "http://example.com/cover.jpg",
CoverId: 4551122,
ItemOrderConversionRatio: m.randomFloatPtr(0.01, 0.5),
ItemCardClickRatio: m.randomFloatPtr(0.02, 0.3),
ItemCardClkCnt: m.randomIntPtr(10, 100),
LivePlayCntCost: m.randomFloatPtr(0.5, 5.0),
AdMerchantFollowCost: m.randomFloatPtr(1.0, 10.0),
AdMerchantFollow: m.randomIntPtr(50, 500),
NetT0OrderCnt: m.randomIntPtr(10, 100),
NetT0Roi: m.randomFloatPtr(1.5, 5.0),
NetT0Gmv: m.randomFloatPtr(5000, 50000),
PhotoName: "测试视频",
PhotoIdStr: "video_123",
PhotoId: "video_123",
ModPriceSegment: "1000-2000",
AgeSegment: "24-30",
Province: "广东",
Gender: "男",
AdPhotoPlayedFiveRatio: m.randomFloatPtr(0.3, 0.8),
AdPhotoPlayedThreeRatio: m.randomFloatPtr(0.5, 0.9),
OrderSubmitRoi: m.randomFloatPtr(1.0, 3.0),
OrderSubmitAmt: m.randomIntPtr(10, 100),
EventOrderSubmitCost: m.randomFloatPtr(5.0, 20.0),
EventOrderSubmit: m.randomIntPtr(5, 50),
EventOrderPaidRoi: m.randomFloatPtr(0.5, 2.0),
EventAppInvoked: m.randomIntPtr(100, 1000),
EventAddShoppingCart: m.randomIntPtr(50, 500),
ConversionNumCost: m.randomFloatPtr(10.0, 50.0),
AdEffectivePlayNum: m.randomIntPtr(1000, 10000),
AdItemClick: m.randomIntPtr(100, 1000),
MerchantProductId: "product_123",
CostTotal: &cost,
AdShow: m.randomIntPtr(10000, 100000),
AdShow1kCost: m.randomFloatPtr(5.0, 50.0),
Impression: &impression,
PhotoClick: m.randomIntPtr(100, 5000),
PhotoClickRatio: m.randomFloatPtr(0.01, 0.1),
Click: &click,
ActionbarClick: m.randomIntPtr(50, 500),
ActionbarClickCost: m.randomFloatPtr(1.0, 10.0),
EspClickRatio: m.randomFloatPtr(0.01, 0.1),
ActionRatio: m.randomFloatPtr(0.02, 0.2),
AdItemClickCount: m.randomIntPtr(10, 100),
EspLivePlayedSeconds: m.randomIntPtr(30, 300),
PlayedThreeSeconds: m.randomIntPtr(5000, 50000),
Play3sRatio: m.randomFloatPtr(0.3, 0.8),
PlayedFiveSeconds: m.randomIntPtr(3000, 30000),
Play5sRatio: m.randomFloatPtr(0.2, 0.6),
PlayedEnd: m.randomIntPtr(1000, 10000),
PlayEndRatio: m.randomFloatPtr(0.1, 0.4),
Share: m.randomIntPtr(10, 100),
Comment: m.randomIntPtr(20, 200),
Likes: m.randomIntPtr(100, 1000),
Report: m.randomIntPtr(1, 10),
Block: m.randomIntPtr(1, 10),
ItemNegative: m.randomIntPtr(5, 50),
LiveShare: m.randomIntPtr(5, 50),
LiveComment: m.randomIntPtr(10, 100),
LiveReward: m.randomIntPtr(20, 200),
EffectivePlayCount: m.randomIntPtr(1000, 10000),
EffectivePlayRatio: m.randomFloatPtr(0.1, 0.5),
ConversionNum: m.randomIntPtr(5, 50),
ConversionCostEsp: m.randomFloatPtr(10.0, 50.0),
Roi: m.randomFloatPtr(1.0, 3.0),
Gmv: m.randomFloatPtr(1000, 10000),
T0Gmv: m.randomFloatPtr(500, 5000),
T1Gmv: m.randomFloatPtr(800, 8000),
T3Gmv: m.randomFloatPtr(1200, 12000),
T7Gmv: m.randomFloatPtr(2000, 20000),
T15Gmv: m.randomFloatPtr(3000, 30000),
T30Gmv: m.randomFloatPtr(5000, 50000),
T0Roi: m.randomFloatPtr(0.5, 2.0),
T1Roi: m.randomFloatPtr(0.8, 2.5),
T3Roi: m.randomFloatPtr(1.0, 3.0),
T7Roi: m.randomFloatPtr(1.5, 4.0),
T15Roi: m.randomFloatPtr(2.0, 5.0),
T30Roi: m.randomFloatPtr(2.5, 6.0),
PaiedOrder: m.randomIntPtr(5, 50),
OrderRatio: m.randomFloatPtr(0.01, 0.1),
T0OrderCnt: m.randomIntPtr(5, 50),
T0OrderCntCost: m.randomFloatPtr(10.0, 100.0),
T0OrderCntRatio: m.randomFloatPtr(0.5, 0.9),
T1OrderCnt: m.randomIntPtr(10, 100),
T3OrderCnt: m.randomIntPtr(20, 200),
T7OrderCnt: m.randomIntPtr(30, 300),
T15OrderCnt: m.randomIntPtr(40, 400),
T30OrderCnt: m.randomIntPtr(50, 500),
MerchantRecoFans: m.randomIntPtr(100, 1000),
T1Retention: m.randomFloatPtr(0.3, 0.8),
T7Retention: m.randomFloatPtr(0.2, 0.6),
T15Retention: m.randomFloatPtr(0.15, 0.5),
T30Retention: m.randomFloatPtr(0.1, 0.4),
T1RetentionRatio: m.randomFloatPtr(0.3, 0.8),
T7RetentionRatio: m.randomFloatPtr(0.2, 0.6),
T15RetentionRatio: m.randomFloatPtr(0.15, 0.5),
T30RetentionRatio: m.randomFloatPtr(0.1, 0.4),
ReservationSuccess: m.randomIntPtr(10, 100),
ReservationCost: m.randomFloatPtr(5.0, 50.0),
StandardLivePlayedStarted: m.randomIntPtr(100, 1000),
AdLivePlayCnt: m.randomIntPtr(50, 500),
AdLivePlayCntCost: m.randomFloatPtr(1.0, 10.0),
LiveAudienceCost: m.randomFloatPtr(0.5, 5.0),
LiveEventGoodsView: m.randomIntPtr(100, 1000),
GoodsClickRatio: m.randomFloatPtr(0.05, 0.3),
DirectAttrPlatNewBuyerCnt: m.randomIntPtr(10, 100),
T30AttrPlatTotalBuyerCnt: m.randomIntPtr(50, 500),
DirectAttrSellerNewBuyerCnt: m.randomIntPtr(5, 50),
T30AttrSellerTotalBuyerCnt: m.randomIntPtr(20, 200),
T7IndirectOrderAmt: m.randomFloatPtr(500, 5000),
T7IndirectOrderCnt: m.randomIntPtr(5, 50),
FansT0GmvPerFans: m.randomFloatPtr(10.0, 100.0),
FansT3GmvPerFans: m.randomFloatPtr(20.0, 200.0),
FansT7GmvPerFans: m.randomFloatPtr(30.0, 300.0),
FansT15GmvPerFans: m.randomFloatPtr(40.0, 400.0),
FansT30GmvPerFans: m.randomFloatPtr(50.0, 500.0),
RecoFansCost: m.randomFloatPtr(5.0, 50.0),
QcpxWhiteboxDirectOrderPaymentAmt: m.randomFloatPtr(100, 1000),
QcpxWhiteboxDirectOrderCnt: m.randomIntPtr(1, 10),
FansT0Gmv: m.randomFloatPtr(100, 1000),
FansT1Gmv: m.randomFloatPtr(200, 2000),
FansT7Gmv: m.randomFloatPtr(300, 3000),
FansT15Gmv: m.randomFloatPtr(400, 4000),
FansT30Gmv: m.randomFloatPtr(500, 5000),
FansT0Roi: m.randomFloatPtr(0.5, 2.0),
FansT1Roi: m.randomFloatPtr(0.8, 2.5),
FansT7Roi: m.randomFloatPtr(1.0, 3.0),
FansT15Roi: m.randomFloatPtr(1.5, 4.0),
FansT30Roi: m.randomFloatPtr(2.0, 5.0),
T0ShopNewBuyerOrderPaymentAmt: m.randomFloatPtr(100, 1000),
T1ShopNewBuyerOrderPaymentAmt: m.randomFloatPtr(200, 2000),
T3ShopNewBuyerOrderPaymentAmt: m.randomFloatPtr(300, 3000),
T7ShopNewBuyerOrderPaymentAmt: m.randomFloatPtr(400, 4000),
T15ShopNewBuyerOrderPaymentAmt: m.randomFloatPtr(500, 5000),
T30ShopNewBuyerOrderPaymentAmt: m.randomFloatPtr(600, 6000),
T0ShopNewBuyerOrderCnt: m.randomIntPtr(1, 10),
T1ShopNewBuyerOrderCnt: m.randomIntPtr(2, 20),
T3ShopNewBuyerOrderCnt: m.randomIntPtr(3, 30),
T7ShopNewBuyerOrderCnt: m.randomIntPtr(4, 40),
T15ShopNewBuyerOrderCnt: m.randomIntPtr(5, 50),
T30ShopNewBuyerOrderCnt: m.randomIntPtr(6, 60),
T1NewBuyerRepurchaseRatio: m.randomFloatPtr(0.1, 0.5),
T3NewBuyerRepurchaseRatio: m.randomFloatPtr(0.15, 0.55),
T7NewBuyerRepurchaseRatio: m.randomFloatPtr(0.2, 0.6),
T15NewBuyerRepurchaseRatio: m.randomFloatPtr(0.25, 0.65),
T30NewBuyerRepurchaseRatio: m.randomFloatPtr(0.3, 0.7),
T0ShopNewBuyerRoi: m.randomFloatPtr(0.5, 2.0),
T1ShopNewBuyerRoi: m.randomFloatPtr(0.8, 2.5),
T3ShopNewBuyerRoi: m.randomFloatPtr(1.0, 3.0),
T7ShopNewBuyerRoi: m.randomFloatPtr(1.5, 4.0),
T15ShopNewBuyerRoi: m.randomFloatPtr(2.0, 5.0),
T30ShopNewBuyerRoi: m.randomFloatPtr(2.5, 6.0),
CreateCardOrderCnt: m.randomIntPtr(1, 10),
ForwardTsCreateCardOrderCnt: m.randomIntPtr(1, 10),
CreateCardOrderCost: m.randomFloatPtr(10.0, 100.0),
ForwardTsCreateCardOrderCost: m.randomFloatPtr(10.0, 100.0),
ActivateCardOrderCnt: m.randomIntPtr(1, 10),
ForwardTsActivateCardOrderCnt: m.randomIntPtr(1, 10),
ActivateCardOrderCost: m.randomFloatPtr(10.0, 100.0),
ForwardTsActivateCardOrderCost: m.randomFloatPtr(10.0, 100.0),
CreateCardOrderRatio: m.randomFloatPtr(0.01, 0.1),
ForwardTsCreateCardOrderRatio: m.randomFloatPtr(0.01, 0.1),
ActivateCardOrderCntRatio: m.randomFloatPtr(0.01, 0.1),
ForwardTsActivateCardOrderRatio: m.randomFloatPtr(0.01, 0.1),
LivePlayCnt: m.randomIntPtr(100, 1000),
ItemEntranceClkCnt: m.randomIntPtr(50, 500),
ShowCnt: m.randomIntPtr(1000, 10000),
ReportDateStr: time.Now().Format("2006-01-02"),
CampaignId: int64Ptr(23),
CampaignName: "测试计划",
UnitId: int64Ptr(10),
UnitName: "测试单元",
CreativeId: int64Ptr(13),
CreativeName: "测试创意",
CidActualRoiAfterSubsidy: m.randomFloatPtr(1.0, 3.0),
CidCouponAmount: m.randomIntPtr(100, 1000),
CidCouponCallbackPaidRefundAmount: m.randomIntPtr(50, 500),
CidVoucherCost: m.randomFloatPtr(5.0, 50.0),
}
}
func int64Ptr(v int64) *int64 {
return &v
}
func (m *MockDataGenerator) generateDetailData(count int) []*AccountReportItem {
items := make([]*AccountReportItem, count)
for i := 0; i < count; i++ {
items[i] = (*AccountReportItem)(m.generateSumData())
}
return items
}
func (m *MockDataGenerator) randomInt(min, max int) int {
return m.rand.Intn(max-min) + min
}
func (m *MockDataGenerator) randomInt64(min, max int64) int64 {
return m.rand.Int63n(max-min) + min
}
func (m *MockDataGenerator) randomFloat(min, max float64) float64 {
return m.rand.Float64()*(max-min) + min
}
func (m *MockDataGenerator) randomIntPtr(min, max int) *int64 {
v := int64(m.randomInt(min, max))
return &v
}
func (m *MockDataGenerator) randomFloatPtr(min, max float64) *float64 {
v := m.randomFloat(min, max)
return &v
}

51
syncdata/quick_sync.go Normal file
View File

@@ -0,0 +1,51 @@
package syncdata
import (
"context"
"time"
"github.com/sirupsen/logrus"
)
func SyncAccountReportWithMock(ctx context.Context) error {
syncService := NewSyncService()
req := &AccountReportRequest{
AdvertiserID: 10001,
StartTime: time.Now().AddDate(0, 0, -30).UnixNano() / 1e6,
EndTime: time.Now().UnixNano() / 1e6,
SelectColumns: []string{"impression", "click", "cost", "t0GMV"},
GroupType: 1,
QueryVersion: 1,
SelectParam: &AccountSelectParam{
CampaignIDs: []int64{1, 2, 3},
},
PageInfo: &PageInfo{
CurrentPage: 1,
PageSize: 20,
},
}
result, err := syncService.SyncAccountReport(ctx, req, true, true)
if err != nil {
logrus.Errorf("同步失败:%v", err)
return err
}
logrus.Infof("同步成功 - 汇总 ID: %d, 明细数量:%d", result.SumID, result.DetailCount)
return nil
}
func SyncAccountReportWithRealAPI(ctx context.Context, req *AccountReportRequest) error {
syncService := NewSyncService()
result, err := syncService.SyncAccountReport(ctx, req, false, true)
if err != nil {
logrus.Errorf("同步失败:%v", err)
return err
}
logrus.Infof("同步成功 - 汇总 ID: %d, 明细数量:%d, 成功:%d, 失败:%d",
result.SumID, result.DetailCount, result.DetailSuccessCount, result.DetailFailCount)
return nil
}

782
syncdata/sync_service.go Normal file
View File

@@ -0,0 +1,782 @@
package syncdata
import (
dao "cid/dao/copydata"
dto "cid/model/dto/copydata"
taskDto "cid/model/dto/copydata"
"cid/service/copydata"
"context"
"encoding/json"
"fmt"
"sync"
"sync/atomic"
"time"
"github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
)
type SyncService struct {
httpClient *HttpClient
converter *DataConverter
mockGen *MockDataGenerator
}
func NewSyncService() *SyncService {
return &SyncService{
httpClient: NewHttpClient("https://ad.e.kuaishou.com", 0),
converter: NewDataConverter(),
mockGen: NewMockDataGenerator(),
}
}
type SyncResult struct {
SumSuccess bool `json:"sum_success"`
SumID int64 `json:"sum_id"`
DetailSuccess bool `json:"detail_success"`
DetailCount int `json:"detail_count"`
DetailSuccessCount int64 `json:"detail_success_count"`
DetailFailCount int64 `json:"detail_fail_count"`
Error error `json:"error"`
TaskLogID int64 `json:"task_log_id"`
PageResults []*PageSyncResult `json:"page_results,omitempty"`
}
type PageSyncResult struct {
PageNumber int `json:"page_number"`
PageTaskLogID int64 `json:"page_task_log_id"`
Success bool `json:"success"`
RecordCount int `json:"record_count"`
DurationMs int64 `json:"duration_ms"`
ErrorMessage string `json:"error_message,omitempty"`
RetryCount int `json:"retry_count"`
}
func (s *SyncService) SyncAccountReport(ctx context.Context, req *AccountReportRequest, useMock bool, saveSum bool) (*SyncResult, error) {
result := &SyncResult{}
var responseData *AccountReportResponse
if useMock {
logrus.Infof("使用 Mock 数据同步快手广告账户报表 - page=%d, pageSize=%d",
req.PageInfo.CurrentPage, req.PageInfo.PageSize)
responseData = s.mockGen.GenerateAccountReportResponseWithPage(req.PageInfo.CurrentPage, req.PageInfo.PageSize)
logrus.Infof("✓ Mock 数据生成完成 - TotalCount=%d, Detail数组长度=%d",
responseData.Data.TotalCount, len(responseData.Data.Detail))
if len(responseData.Data.Detail) > 0 {
firstItem := responseData.Data.Detail[0]
lastItem := responseData.Data.Detail[len(responseData.Data.Detail)-1]
logrus.Infof(" 第一条: campaignId=%v, creativeId=%v", firstItem.CampaignId, firstItem.CreativeId)
logrus.Infof(" 最后一条: campaignId=%v, creativeId=%v", lastItem.CampaignId, lastItem.CreativeId)
}
} else {
logrus.Info("从真实 API 同步快手广告账户报表")
respBytes, err := s.httpClient.Post(ctx, "/rest/openapi/gw/esp/report/accountReport", req)
if err != nil {
result.Error = fmt.Errorf("调用 API 失败:%w", err)
return result, result.Error
}
responseData = &AccountReportResponse{}
if err := json.Unmarshal(respBytes, responseData); err != nil {
result.Error = fmt.Errorf("解析响应失败:%w", err)
return result, result.Error
}
if responseData.Code != 0 {
result.Error = fmt.Errorf("API 返回错误code=%d, message=%s", responseData.Code, responseData.Message)
return result, result.Error
}
}
if saveSum && responseData.Data.Sum != nil {
sumItem := s.converter.ConvertToSumItem(responseData.Data.Sum, "account_report", req.PageInfo.CurrentPage)
sumResult, saveErr := s.saveSumData(ctx, sumItem)
if saveErr != nil {
logrus.Errorf("保存汇总数据失败:%v", saveErr)
result.Error = fmt.Errorf("保存汇总数据失败:%w", saveErr)
} else {
result.SumSuccess = true
result.SumID = sumResult.Id
logrus.Infof("成功保存汇总数据ID=%d", sumResult.Id)
}
}
if len(responseData.Data.Detail) > 0 {
detailItems := s.converter.ConvertToDetailItems(responseData.Data.Detail, "account_report", req.PageInfo.CurrentPage)
logrus.Infof("▶ 准备插入 %d 条明细数据page=%d", len(detailItems), req.PageInfo.CurrentPage)
detailResult, saveErr := s.saveDetailData(ctx, detailItems)
if saveErr != nil {
logrus.Errorf("保存明细数据失败:%v", saveErr)
result.Error = fmt.Errorf("保存明细数据失败:%w", saveErr)
} else {
result.DetailSuccess = true
result.DetailCount = len(detailItems)
result.DetailSuccessCount = detailResult.SuccessCount
result.DetailFailCount = detailResult.FailCount
logrus.Infof("✓ 成功保存 %d 条明细数据(成功=%d, 失败=%d", len(detailItems), detailResult.SuccessCount, detailResult.FailCount)
}
}
return result, result.Error
}
// SyncAccountReportWithPagination 带分页处理的同步方法(支持全量数据抽取)
func (s *SyncService) SyncAccountReportWithPagination(ctx context.Context, req *AccountReportRequest, useMock bool, maxRetries int) (*SyncResult, error) {
startTime := time.Now()
parentTaskID := fmt.Sprintf("%d_%d_account", req.AdvertiserID, req.StartTime)
logReq := &taskDto.CreateSyncTaskLogReq{
TaskID: parentTaskID,
TaskType: "account_report",
AdvertiserID: req.AdvertiserID,
StartTime: time.UnixMilli(req.StartTime),
EndTime: time.UnixMilli(req.EndTime),
Status: "pending",
MaxRetry: maxRetries,
RequestParams: req,
}
parentLogID, err := dao.SyncTaskLog.Create(ctx, logReq)
if err != nil {
logrus.Errorf("创建主任务日志失败:%v", err)
}
updateParentLog := func(status, errMsg, errorCode string, summary interface{}) {
if parentLogID == 0 {
return
}
duration := time.Since(startTime).Milliseconds()
updateReq := &taskDto.UpdateSyncTaskLogReq{
ID: parentLogID,
Status: status,
ErrorMessage: errMsg,
ErrorCode: errorCode,
DurationMs: &duration,
}
if status == "success" || status == "manual_review" {
completedAt := time.Now()
updateReq.CompletedAt = completedAt
}
if summary != nil {
updateReq.ResultSummary = summary
}
if err := dao.SyncTaskLog.Update(ctx, updateReq); err != nil {
logrus.Errorf("更新主任务日志失败:%v", err)
}
}
updateParentLog("running", "", "", nil)
aggregatedResult := &SyncResult{
SumSuccess: false,
SumID: 0,
TaskLogID: parentLogID,
PageResults: make([]*PageSyncResult, 0),
}
totalCount := 0
currentPage := 1
pageSize := 10
if req.PageInfo == nil {
req.PageInfo = &PageInfo{}
}
if req.PageInfo.PageSize > 0 {
pageSize = req.PageInfo.PageSize
}
successPages := 0
failedPages := 0
var totalPages int
for {
logrus.Infof(">>> 正在同步第 %d 页数据...", currentPage)
req.PageInfo.CurrentPage = currentPage
req.PageInfo.PageSize = pageSize
pageTaskID := fmt.Sprintf("%s_page_%d", parentTaskID, currentPage)
pageStartTime := time.Now()
pageResult := &PageSyncResult{
PageNumber: currentPage,
Success: false,
RecordCount: 0,
RetryCount: 0,
}
result, pageLogID, err := s.SyncSinglePageWithTask(ctx, req, useMock, maxRetries, pageTaskID, currentPage)
pageDuration := time.Since(pageStartTime).Milliseconds()
pageResult.DurationMs = pageDuration
pageResult.PageTaskLogID = pageLogID
if err != nil {
logrus.Errorf("第 %d 页同步失败:%v", currentPage, err)
pageResult.ErrorMessage = err.Error()
failedPages++
aggregatedResult.PageResults = append(aggregatedResult.PageResults, pageResult)
if failedPages > maxRetries {
logrus.Warnf("失败页数超过阈值 %d终止同步", maxRetries)
break
}
currentPage++
time.Sleep(500 * time.Millisecond)
continue
}
if result.SumSuccess && aggregatedResult.SumID == 0 {
aggregatedResult.SumSuccess = true
aggregatedResult.SumID = result.SumID
logrus.Infof("✓ 汇总数据已保存ID=%d", result.SumID)
}
if result.DetailSuccess && result.DetailCount > 0 {
totalCount += result.DetailCount
pageResult.Success = true
pageResult.RecordCount = result.DetailCount
successPages++
logrus.Infof("✓ 第 %d 页获取到 %d 条明细数据,累计 %d 条", currentPage, result.DetailCount, totalCount)
}
aggregatedResult.PageResults = append(aggregatedResult.PageResults, pageResult)
currentData := s.fetchCurrentData(req, useMock)
if currentData != nil && currentData.TotalCount > 0 {
totalPages = (currentData.TotalCount + pageSize - 1) / pageSize
logrus.Infof("总记录数:%d, 总页数:%d, 当前页:%d/%d",
currentData.TotalCount, totalPages, currentPage, totalPages)
if currentPage >= totalPages {
logrus.Infof("✓ 已同步所有页面数据,共 %d 页,%d 条记录", totalPages, currentData.TotalCount)
break
}
}
if result.DetailCount < pageSize {
logrus.Infof("✓ 当前页数据不足 %d 条,已到达最后一页", pageSize)
break
}
currentPage++
time.Sleep(300 * time.Millisecond)
}
logrus.Infof("分页同步完成 - 成功:%d页, 失败:%d页, 总明细:%d条",
successPages, failedPages, totalCount)
// 统计所有子任务的结果
totalDetailCount := 0
var totalSuccessCount int64
var totalFailCount int64
for _, pageResult := range aggregatedResult.PageResults {
if pageResult.Success {
totalDetailCount += pageResult.RecordCount
totalSuccessCount++
} else {
totalFailCount++
}
}
aggregatedResult.DetailCount = totalDetailCount
aggregatedResult.DetailSuccessCount = totalSuccessCount
aggregatedResult.DetailFailCount = totalFailCount
if failedPages > 0 {
logrus.Warnf("存在 %d 个失败的页面,主任务标记为部分失败", failedPages)
summary := map[string]interface{}{
"sum_id": aggregatedResult.SumID,
"detail_count": totalDetailCount,
"total_pages": totalPages,
"success_pages": successPages,
"failed_pages": failedPages,
"page_results": aggregatedResult.PageResults,
}
updateParentLog("partial_failed", fmt.Sprintf("%d 个页面同步失败", failedPages), "PAGE_SYNC_FAILED", summary)
} else {
logrus.Info("✓ 所有页面同步成功")
summary := map[string]interface{}{
"sum_id": aggregatedResult.SumID,
"detail_count": totalDetailCount,
"total_pages": totalPages,
"success_pages": successPages,
"failed_pages": 0,
"page_results": aggregatedResult.PageResults,
}
updateParentLog("success", "", "", summary)
}
return aggregatedResult, aggregatedResult.Error
}
func (s *SyncService) SyncSinglePageWithTask(ctx context.Context, req *AccountReportRequest, useMock bool, maxRetries int, pageTaskID string, pageNumber int) (*SyncResult, int64, error) {
pageStartTime := time.Now()
pageLogReq := &taskDto.CreateSyncTaskLogReq{
TaskID: pageTaskID,
TaskType: "account_report_page",
AdvertiserID: req.AdvertiserID,
StartTime: time.UnixMilli(req.StartTime),
EndTime: time.UnixMilli(req.EndTime),
Status: "pending",
MaxRetry: maxRetries,
PageInfo: req.PageInfo,
RequestParams: map[string]interface{}{
"page_number": pageNumber,
"page_size": req.PageInfo.PageSize,
},
}
pageLogID, err := dao.SyncTaskLog.Create(ctx, pageLogReq)
if err != nil {
logrus.Errorf("创建分页任务日志失败:%v", err)
}
updatePageLog := func(status, errMsg, errorCode string, retryCount int) {
if pageLogID == 0 {
return
}
duration := time.Since(pageStartTime).Milliseconds()
updateReq := &taskDto.UpdateSyncTaskLogReq{
ID: pageLogID,
Status: status,
ErrorMessage: errMsg,
ErrorCode: errorCode,
DurationMs: &duration,
}
if retryCount > 0 {
updateReq.RetryCount = &retryCount
}
if status == "success" || status == "failed" || status == "partial_failed" {
completedAt := time.Now()
updateReq.CompletedAt = completedAt
}
if err := dao.SyncTaskLog.Update(ctx, updateReq); err != nil {
logrus.Errorf("更新分页任务日志失败:%v", err)
}
}
updatePageLog("running", "", "", 0)
logrus.Infof(">>> 开始同步第 %d 页数据...", pageNumber)
var lastResult *SyncResult
var lastErr error
for attempt := 0; attempt <= maxRetries; attempt++ {
saveSum := (attempt == 0 && pageNumber == 1)
result, err := s.SyncAccountReport(ctx, req, useMock, saveSum)
lastResult = result
lastErr = err
if err == nil {
logrus.Infof("第 %d 页同步成功,尝试次数:%d", pageNumber, attempt+1)
updatePageLog("success", "", "", attempt)
return result, pageLogID, nil
}
logrus.Warnf("第 %d 页同步失败,第 %d 次重试,错误:%v", pageNumber, attempt+1, err)
}
updatePageLog("failed", lastErr.Error(), "PAGE_SYNC_FAILED", maxRetries)
return lastResult, pageLogID, lastErr
}
func (s *SyncService) syncSinglePageWithTaskForConcurrent(ctx context.Context, req *AccountReportRequest, useMock bool, maxRetries int, pageTaskID string, pageNumber int, isFirstPage bool) (*SyncResult, int64, error) {
pageStartTime := time.Now()
pageLogReq := &taskDto.CreateSyncTaskLogReq{
TaskID: pageTaskID,
TaskType: "account_report_page",
AdvertiserID: req.AdvertiserID,
StartTime: time.UnixMilli(req.StartTime),
EndTime: time.UnixMilli(req.EndTime),
Status: "pending",
MaxRetry: maxRetries,
PageInfo: req.PageInfo,
RequestParams: map[string]interface{}{
"page_number": pageNumber,
"page_size": req.PageInfo.PageSize,
},
}
pageLogID, err := dao.SyncTaskLog.Create(ctx, pageLogReq)
if err != nil {
logrus.Errorf("创建分页任务日志失败page=%d%v", pageNumber, err)
return nil, 0, fmt.Errorf("创建分页任务日志失败:%w", err)
}
updatePageLog := func(status, errMsg, errorCode string, retryCount int) {
if pageLogID == 0 {
return
}
duration := time.Since(pageStartTime).Milliseconds()
updateReq := &taskDto.UpdateSyncTaskLogReq{
ID: pageLogID,
Status: status,
ErrorMessage: errMsg,
ErrorCode: errorCode,
DurationMs: &duration,
}
if retryCount > 0 {
updateReq.RetryCount = &retryCount
}
if status == "success" || status == "failed" || status == "partial_failed" {
completedAt := time.Now()
updateReq.CompletedAt = completedAt
}
if err := dao.SyncTaskLog.Update(ctx, updateReq); err != nil {
logrus.Errorf("更新分页任务日志失败:%v", err)
}
}
updatePageLog("running", "", "", 0)
logrus.Infof(">>> 开始同步第 %d 页数据...", pageNumber)
var lastResult *SyncResult
var lastErr error
for attempt := 0; attempt <= maxRetries; attempt++ {
saveSum := isFirstPage && (attempt == 0)
result, err := s.SyncAccountReport(ctx, req, useMock, saveSum)
lastResult = result
lastErr = err
if err == nil {
logrus.Infof("第 %d 页同步成功,尝试次数:%d", pageNumber, attempt+1)
updatePageLog("success", "", "", attempt)
return result, pageLogID, nil
}
logrus.Warnf("第 %d 页同步失败,第 %d 次重试,错误:%v", pageNumber, attempt+1, err)
}
updatePageLog("failed", lastErr.Error(), "PAGE_SYNC_FAILED", maxRetries)
return lastResult, pageLogID, lastErr
}
func (s *SyncService) SyncWithRetry(ctx context.Context, req *AccountReportRequest, useMock bool, maxRetries int) (*SyncResult, error) {
var lastResult *SyncResult
var lastErr error
for attempt := 0; attempt <= maxRetries; attempt++ {
saveSum := (attempt == 0 && req.PageInfo.CurrentPage == 1)
result, err := s.SyncAccountReport(ctx, req, useMock, saveSum)
lastResult = result
lastErr = err
if err == nil {
logrus.Infof("同步成功,尝试次数:%d", attempt+1)
return result, nil
}
logrus.Warnf("同步失败,第 %d 次重试,错误:%v", attempt+1, err)
}
return lastResult, lastErr
}
type ConcurrentSyncConfig struct {
MaxConcurrency int
UseMock bool
MaxRetries int
}
func (s *SyncService) SyncAccountReportConcurrent(ctx context.Context, req *AccountReportRequest, config ConcurrentSyncConfig) (*SyncResult, error) {
startTime := time.Now()
batchID := startTime.UnixNano()
parentTaskID := fmt.Sprintf("%d_%d_%d_account", req.AdvertiserID, req.StartTime, batchID)
logReq := &taskDto.CreateSyncTaskLogReq{
TaskID: parentTaskID,
TaskType: "account_report",
AdvertiserID: req.AdvertiserID,
StartTime: time.UnixMilli(req.StartTime),
EndTime: time.UnixMilli(req.EndTime),
Status: "pending",
MaxRetry: config.MaxRetries,
RequestParams: req,
}
parentLogID, err := dao.SyncTaskLog.Create(ctx, logReq)
if err != nil {
logrus.Errorf("创建主任务日志失败:%v", err)
}
updateParentLog := func(status, errMsg, errorCode string, summary interface{}) {
if parentLogID == 0 {
return
}
duration := time.Since(startTime).Milliseconds()
updateReq := &taskDto.UpdateSyncTaskLogReq{
ID: parentLogID,
Status: status,
ErrorMessage: errMsg,
ErrorCode: errorCode,
DurationMs: &duration,
}
if status == "success" || status == "manual_review" {
completedAt := time.Now()
updateReq.CompletedAt = completedAt
}
if summary != nil {
updateReq.ResultSummary = summary
}
if err := dao.SyncTaskLog.Update(ctx, updateReq); err != nil {
logrus.Errorf("更新主任务日志失败:%v", err)
}
}
updateParentLog("running", "", "", nil)
if req.PageInfo == nil {
req.PageInfo = &PageInfo{}
}
pageSize := 10
if req.PageInfo.PageSize > 0 {
pageSize = req.PageInfo.PageSize
}
firstPageReq := *req
firstPageReq.PageInfo.CurrentPage = 1
firstPageReq.PageInfo.PageSize = pageSize
currentData := s.fetchCurrentData(&firstPageReq, config.UseMock)
if currentData == nil || currentData.TotalCount == 0 {
logrus.Warn("未获取到总记录数,降级为串行同步")
return s.SyncAccountReportWithPagination(ctx, req, config.UseMock, config.MaxRetries)
}
totalPages := (currentData.TotalCount + pageSize - 1) / pageSize
logrus.Infof("开始并发同步 - 批次ID%d, 总记录数:%d, 总页数:%d, 每页大小:%d, 并发数:%d",
batchID, currentData.TotalCount, totalPages, pageSize, config.MaxConcurrency)
updateParentLog("running", "", "", map[string]interface{}{
"total_pages": totalPages,
"total_records": currentData.TotalCount,
"page_size": pageSize,
"concurrency": config.MaxConcurrency,
"batch_id": batchID,
})
pageResults := make([]*PageSyncResult, totalPages)
var pageResultsMu sync.Mutex
var sumSuccess bool
var sumID int64
var sumMu sync.Mutex
var totalDetailCount int32
var successPages int64
var failedPages int64
sem := semaphore.NewWeighted(int64(config.MaxConcurrency))
eg, egCtx := errgroup.WithContext(ctx)
for pageNum := 1; pageNum <= totalPages; pageNum++ {
if err := sem.Acquire(ctx, 1); err != nil {
logrus.Errorf("获取信号量失败:%v", err)
break
}
currentPage := pageNum
eg.Go(func() error {
defer sem.Release(1)
pageTaskID := fmt.Sprintf("%s_page_%d", parentTaskID, currentPage)
pageStartTime := time.Now()
pageReq := *req
pageReq.PageInfo = &PageInfo{
CurrentPage: currentPage,
PageSize: pageSize,
}
result, pageLogID, err := s.syncSinglePageWithTaskForConcurrent(egCtx, &pageReq, config.UseMock, config.MaxRetries, pageTaskID, currentPage, currentPage == 1)
pageDuration := time.Since(pageStartTime).Milliseconds()
pageResult := &PageSyncResult{
PageNumber: currentPage,
Success: false,
RecordCount: 0,
DurationMs: pageDuration,
ErrorMessage: "",
RetryCount: 0,
PageTaskLogID: pageLogID,
}
if err != nil {
logrus.Errorf("第 %d 页同步失败:%v", currentPage, err)
pageResult.ErrorMessage = err.Error()
pageResultsMu.Lock()
pageResults[currentPage-1] = pageResult
pageResultsMu.Unlock()
newFailedCount := atomic.AddInt64(&failedPages, 1)
if int(newFailedCount) > config.MaxRetries {
logrus.Warnf("失败页数超过阈值 %d", config.MaxRetries)
}
return nil
}
if result.SumSuccess {
sumMu.Lock()
if !sumSuccess {
sumSuccess = true
sumID = result.SumID
logrus.Infof("✓ 汇总数据已保存ID=%d来自第 %d 页)", result.SumID, currentPage)
}
sumMu.Unlock()
}
if result.DetailSuccess && result.DetailCount > 0 {
pageResult.Success = true
pageResult.RecordCount = result.DetailCount
atomic.AddInt32(&totalDetailCount, int32(result.DetailCount))
atomic.AddInt64(&successPages, 1)
logrus.Debugf("✓ 第 %d 页完成:%d 条明细,耗时 %dms", currentPage, result.DetailCount, pageDuration)
}
pageResultsMu.Lock()
pageResults[currentPage-1] = pageResult
pageResultsMu.Unlock()
return nil
})
}
if err := eg.Wait(); err != nil {
logrus.Errorf("协程组执行出错:%v", err)
updateParentLog("failed", err.Error(), "CONCURRENT_SYNC_FAILED", nil)
return &SyncResult{
SumSuccess: sumSuccess,
SumID: sumID,
TaskLogID: parentLogID,
PageResults: pageResults,
Error: err,
}, err
}
actualResults := make([]*PageSyncResult, 0, len(pageResults))
for _, pr := range pageResults {
if pr != nil {
actualResults = append(actualResults, pr)
}
}
finalDetailCount := atomic.LoadInt32(&totalDetailCount)
finalSuccessPages := atomic.LoadInt64(&successPages)
finalFailedPages := atomic.LoadInt64(&failedPages)
logrus.Infof("并发同步完成 - 成功:%d页, 失败:%d页, 总明细:%d条",
finalSuccessPages, finalFailedPages, finalDetailCount)
aggregatedResult := &SyncResult{
SumSuccess: sumSuccess,
SumID: sumID,
TaskLogID: parentLogID,
DetailCount: int(finalDetailCount),
DetailSuccessCount: finalSuccessPages,
DetailFailCount: finalFailedPages,
PageResults: actualResults,
}
if finalFailedPages > 0 {
logrus.Warnf("存在 %d 个失败的页面,主任务标记为部分失败", finalFailedPages)
summary := map[string]interface{}{
"sum_id": sumID,
"detail_count": finalDetailCount,
"total_pages": totalPages,
"success_pages": finalSuccessPages,
"failed_pages": finalFailedPages,
"page_results": actualResults,
}
updateParentLog("partial_failed", fmt.Sprintf("%d 个页面同步失败", finalFailedPages), "PAGE_SYNC_FAILED", summary)
} else {
logrus.Info("✓ 所有页面同步成功")
summary := map[string]interface{}{
"sum_id": sumID,
"detail_count": finalDetailCount,
"total_pages": totalPages,
"success_pages": finalSuccessPages,
"failed_pages": 0,
"page_results": actualResults,
}
updateParentLog("success", "", "", summary)
}
return aggregatedResult, nil
}
func (s *SyncService) fetchCurrentData(req *AccountReportRequest, useMock bool) *AccountReportData {
if useMock {
responseData := s.mockGen.GenerateAccountReportResponseWithPage(req.PageInfo.CurrentPage, req.PageInfo.PageSize)
if responseData != nil && responseData.Data != nil {
return responseData.Data
}
return nil
}
respBytes, err := s.httpClient.Post(context.Background(), "/rest/openapi/gw/esp/report/accountReport", req)
if err != nil {
return nil
}
responseData := &AccountReportResponse{}
if err := json.Unmarshal(respBytes, responseData); err != nil {
return nil
}
if responseData.Code == 0 && responseData.Data != nil {
return responseData.Data
}
return nil
}
func (s *SyncService) saveSumData(ctx context.Context, item *dto.CidAccountReportSumItem) (*dto.CreateCidAccountReportSumRes, error) {
return copydata.CidAccountReportDetail.CreateSum(ctx, item)
}
func (s *SyncService) saveDetailData(ctx context.Context, items []*dto.CidAccountReportDetailItem) (*dto.BatchCreateCidAccountReportDetailRes, error) {
req := &dto.BatchCreateCidAccountReportDetailReq{
Items: items,
}
return copydata.CidAccountReportDetail.BatchCreate(ctx, req)
}

135
syncdata/sync_test.go Normal file
View File

@@ -0,0 +1,135 @@
package syncdata
import (
"fmt"
"testing"
"time"
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
)
func init() {
fmt.Println("=== 初始化测试环境 ===")
ctx := gctx.New()
db := g.DB()
if db != nil {
_, err := db.Query(ctx, "SELECT 1")
if err == nil {
fmt.Println("✓ 数据库连接成功")
} else {
fmt.Printf("⚠️ 数据库连接失败:%v\n", err)
fmt.Println("⚠️ 将跳过数据库相关测试")
}
} else {
fmt.Println("⚠️ 数据库未初始化")
}
fmt.Println("========================")
}
func TestMockDataGeneration(t *testing.T) {
mockGen := NewMockDataGenerator()
req := mockGen.GenerateAccountReportRequest()
if req == nil {
t.Error("请求数据生成失败")
return
}
fmt.Printf("✓ Mock 请求生成成功AdvertiserID=%d\n", req.AdvertiserID)
}
func TestDataConverter(t *testing.T) {
converter := NewDataConverter()
mockGen := NewMockDataGenerator()
responseData := mockGen.GenerateAccountReportResponse()
if responseData == nil || responseData.Data.Sum == nil {
t.Fatal("Mock 数据生成失败")
}
sumItem := converter.ConvertToSumItem(responseData.Data.Sum, "account_report", 1)
if sumItem == nil {
t.Fatal("转换为汇总数据失败")
}
fmt.Printf("✓ 汇总数据转换成功:计划=%s\n", sumItem.CampaignName)
detailItems := converter.ConvertToDetailItems(responseData.Data.Detail, "account_report", 1)
if len(detailItems) == 0 {
t.Fatal("转换为明细数据失败")
}
fmt.Printf("✓ 明细数据转换成功:数量=%d\n", len(detailItems))
}
func TestSyncAccountReportWithDB(t *testing.T) {
ctx := gctx.New()
syncService := NewSyncService()
req := &AccountReportRequest{
AdvertiserID: 10001,
StartTime: time.Now().AddDate(0, 0, -30).UnixNano() / 1e6,
EndTime: time.Now().UnixNano() / 1e6,
SelectColumns: []string{"impression", "click", "cost", "t0GMV"},
GroupType: 1,
QueryVersion: 1,
}
result, err := syncService.SyncAccountReport(ctx, req, true)
if err != nil {
t.Logf("同步失败(可能是数据库问题): %v", err)
return
}
fmt.Printf("✓ 同步结果:汇总成功=%v, 汇总 ID=%d, 明细数量=%d\n",
result.SumSuccess, result.SumID, result.DetailCount)
}
//
//// TestScheduledSyncTask 测试定时同步任务(每小时执行一次,全量分页抽取)
//func TestScheduledSyncTask(t *testing.T) {
// ctx := gctx.New()
// syncService := NewSyncService()
//
// req := &AccountReportRequest{
// AdvertiserID: 10001,
// StartTime: time.Now().AddDate(0, 0, -30).UnixNano() / 1e6,
// EndTime: time.Now().UnixNano() / 1e6,
// SelectColumns: []string{"impression", "click", "cost", "t0GMV"},
// GroupType: 1,
// QueryVersion: 1,
// }
//
// logrus.Info("=== 开始执行定时同步任务 ===")
// result, err := syncService.SyncAccountReportWithPagination(ctx, req, true, 3)
// if err != nil {
// t.Logf("定时同步任务失败:%v", err)
// return
// }
//
// fmt.Printf("✓ 定时同步完成:\n")
// fmt.Printf(" 汇总数据:成功=%v, ID=%d\n", result.SumSuccess, result.SumID)
// fmt.Printf(" 明细数据:总数=%d, 成功=%d, 失败=%d\n",
// result.DetailCount, result.DetailSuccessCount, result.DetailFailCount)
//}
func BenchmarkSyncAccountReport(b *testing.B) {
ctx := gctx.New()
syncService := NewSyncService()
req := &AccountReportRequest{
AdvertiserID: 10001,
StartTime: time.Now().AddDate(0, 0, -30).UnixNano() / 1e6,
EndTime: time.Now().UnixNano() / 1e6,
SelectColumns: []string{"impression", "click", "cost"},
GroupType: 1,
QueryVersion: 1,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = syncService.SyncAccountReport(ctx, req, true)
}
}