Commit 8d68ce9a by 彭芳

[feat]: add return filed

parent e4755882
...@@ -8,8 +8,8 @@ const ( ...@@ -8,8 +8,8 @@ const (
) )
type PageRequest struct { type PageRequest struct {
Page int `form:"page" json:"page" binding:"required"` // 页码 Page int `form:"page" json:"page"` // 页码
PageSize int `form:"page_size" json:"page_size" binding:"required"` // 每页大小 PageSize int `form:"page_size" json:"page_size" ` // 每页大小
OrderBy string // 排序字段 OrderBy string // 排序字段
OrderByMode string // 排序方式 desc asc OrderByMode string // 排序方式 desc asc
} }
......
package errs
import "fmt"
var (
ErrorArgs = New(40001, "请求参数错误")
ServiceError = New(50000, "系统错误请稍后再试。")
)
type Error struct {
Code int // 错误码
Msg string // 错误信息
}
func (e *Error) Error() string {
return e.Msg
}
func (e *Error) WithMessage(msg string) *Error {
out := &Error{
Code: e.Code,
Msg: e.Msg,
}
if out.Msg == "" {
out.Msg = msg
} else {
out.Msg = fmt.Sprintf("%s: %s", e.Msg, msg)
}
return out
}
func New(code int, msg string) *Error {
return &Error{Code: code, Msg: msg}
}
...@@ -2,16 +2,29 @@ package biz ...@@ -2,16 +2,29 @@ package biz
import ( import (
"context" "context"
"time"
"github.com/go-kratos/kratos/v2/log" "github.com/go-kratos/kratos/v2/log"
"demo/internal/biz/common" "demo/internal/biz/common"
"demo/internal/biz/errs"
"demo/internal/util"
)
type TimeGranularity string
const (
StatTimeGranularityDaily TimeGranularity = "STAT_TIME_GRANULARITY_DAILY" // 按天维度
StatTimeGranularityHourly TimeGranularity = "STAT_TIME_GRANULARITY_HOURLY" // 按小时维度
) )
type ListCampaignRequest struct { type ListCampaignRequest struct {
common.PageRequest common.PageRequest
StartDate string `form:"start_date" json:"start_date"` // 开始时间 TimeGranularity TimeGranularity `form:"time_granularity" json:"time_granularity"` // 时间粒度(0:按天维度;1:按小时维度)
EndDate string `form:"end_date" json:"end_date"` // 结束时间 StartDate string `form:"start_date" json:"start_date"` // 开始时间(格式YYYY-MM-DD)
EndDate string `form:"end_date" json:"end_date"` // 结束时间(格式YYYY-MM-DD)
StartDateLong util.Second `json:"-"` // 开始时间
EndDateLong util.Second `json:"-"` // 结束时间
} }
type ListCampaignResponse struct { type ListCampaignResponse struct {
...@@ -22,8 +35,75 @@ type ListCampaignResponse struct { ...@@ -22,8 +35,75 @@ type ListCampaignResponse struct {
type CampaignList []*Campaign type CampaignList []*Campaign
type Campaign struct { type Campaign struct {
CampaignId string `json:"campaign_id"` // 广告组ID CampaignId string `json:"campaign_id"` // 广告组ID
CampaignName string `json:"campaign_name"` // 广告主组名称 CampaignName string `json:"campaign_name"` // 广告主组名称
AdvertiserId string `json:"advertiser_id"` // 广告主id
StatDatetime string `json:"stat_datetime"` // 数据起始时间(yyyy-MM-dd HH:mm:ss)
Cost float64 `json:"cost"` // 花费
Show int `json:"show"` // 展示量
AvgShowCost float64 `json:"avg_show_cost"` // 千次展示成本
Click int `json:"click"` // 点击量
AvgClickCost float64 `json:"avg_click_cost"` // 点击成本
Ctr float64 `json:"ctr"` // 点击率
Convert int `json:"convert"` // 转化数
ConvertCost float64 `json:"convert_cost"` // 转化成本
ConvertRate float64 `json:"convert_rate"` // 转化率
DeepConvert int `json:"deep_convert"` // 深度转化数
DeepConvertCost float64 `json:"deep_convert_cost"` // 深度转化成本
DeepConvertRate float64 `json:"deep_convert_rate"` // 深度转化率
AttributionConvert int `json:"attribution_convert"` // 转化数(计费时间)
AttributionConvertCost float64 `json:"attribution_convert_cost"` // 转化成本(计费时间)
AttributionDeepConvert int `json:"attribution_deep_convert"` // 深度转化数(计费时间)
AttributionDeepConvertCost float64 `json:"attribution_deep_convert_cost"` // 深度转化成本(计费时间)
DownloadStart int `json:"download_start"` // 安卓下载开始数
DownloadStartCost float64 `json:"download_start_cost"` // 安卓下载开始成本
DownloadStartRate float64 `json:"download_start_rate"` // 安卓下载开始率
DownloadFinish int `json:"download_finish"` // 安卓下载完成数
DownloadFinishCost float64 `json:"download_finish_cost"` // 安卓下载完成成本
DownloadFinishRate float64 `json:"download_finish_rate"` // 安卓下载完成率
ClickInstall int `json:"click_install"` // 点击安装数
InstallFinish int `json:"install_finish"` // 安卓安装完成数
InstallFinishCost float64 `json:"install_finish_cost"` // 安卓安装完成成本
InstallFinishRate float64 `json:"install_finish_rate"` // 安卓安装完成率
Active int `json:"active"` // 激活数
ActiveCost float64 `json:"active_cost"` // 激活成本
ActiveRate float64 `json:"active_rate"` // 激活率
Register int `json:"register"` // 注册数
ActiveRegisterCost float64 `json:"active_register_cost"` // 注册成本
ActiveRegisterRate float64 `json:"active_register_rate"` // 注册率
NextDayOpen int `json:"next_day_open"` // 次留数
NextDayOpenCost float64 `json:"next_day_open_cost"` // 次留成本
NextDayOpenRate float64 `json:"next_day_open_rate"` // 次留率
AttributionNextDayOpenCnt int `json:"attribution_next_day_open_cnt"` // 次留回传数
AttributionNextDayOpenCost float64 `json:"attribution_next_day_open_cost"` // 次留成本
AttributionNextDayOpenRate float64 `json:"attribution_next_day_open_rate"` // 次留率
GameAddiction int `json:"game_addiction"` // 关键行为数
GameAddictionCost float64 `json:"game_addiction_cost"` // 关键行为成本
GameAddictionRate float64 `json:"game_addiction_rate"` // 关键行为率
PayCount int `json:"pay_count"` // 首次付费次数
ActivePayCost float64 `json:"active_pay_cost"` // 首次付费成本
ActivePayRate float64 `json:"active_pay_rate"` // 首次付费率
InAppUv int `json:"in_app_uv"` // APP内访问
InAppDetailUv int `json:"in_app_detail_uv"` // APP内访问详情页
InAppCart int `json:"in_app_cart"` // APP内加入购物车
InAppPay int `json:"in_app_pay"` // APP内付费
InAppOrder int `json:"in_app_order"` // APP内下单
AttributionGamePay7DCount int `json:"attribution_game_pay_7d_count"` // 7日付费次数(激活时间)
GamePayCount int `json:"game_pay_count"` // 付费次数
TotalPlay int `json:"total_play"` // 视频数据-播放数
ValidPlay int `json:"valid_play"` // 视频数据-有效播放数
ValidPlayCost float64 `json:"valid_play_cost"` // 有效播放成本
ValidPlayRate float64 `json:"valid_play_rate"` // 有效播放率
Play25FeedBreak int `json:"play_25_feed_break"` // 视频数据-25%进度播放数
Play50FeedBreak int `json:"play_50_feed_break"` // 视频数据-50%进度播放数
Play75FeedBreak int `json:"play_75_feed_break"` // 视频数据-75%进度播放数
Play100FeedBreak int `json:"play_100_feed_break"` // 视频数据-99%进度播放数
AveragePlayTimePerPlay float64 `json:"average_play_time_per_play"` // 视频数据-平均单次播放时长,单位:秒
PlayOverRate float64 `json:"play_over_rate"` // 播完率
PlayDurationSum int `json:"play_duration_sum"` // 视频数据-播放时长,单位ms
AttributionActivePayIntraOneDayCount int `json:"attribution_active_pay_intra_one_day_count"` // 游戏行业-激活后24h首次付费数
AttributionActivePayIntraOneDayAmount float64 `json:"attribution_active_pay_intra_one_day_amount"` // 游戏行业-激活后24h付费金额
Timestamp time.Time `json:"timestamp"` // 创建时间
} }
// CampaignRepo is a Report camRepo. // CampaignRepo is a Report camRepo.
...@@ -45,7 +125,21 @@ func NewReportUsecase(repo CampaignRepo, logger log.Logger) *ReportUsecase { ...@@ -45,7 +125,21 @@ func NewReportUsecase(repo CampaignRepo, logger log.Logger) *ReportUsecase {
// ListCampaignData list campaign data. // ListCampaignData list campaign data.
func (p *ReportUsecase) ListCampaignData(ctx context.Context, customerId int64, req *ListCampaignRequest) (*ListCampaignResponse, error) { func (p *ReportUsecase) ListCampaignData(ctx context.Context, customerId int64, req *ListCampaignRequest) (*ListCampaignResponse, error) {
p.log.WithContext(ctx).Infof("req: %v", req) p.log.WithContext(ctx).Infof("req: %v", req)
// todo 参数校验 if req.StartDate != "" {
parse, err := time.Parse("2006-01-02", req.StartDate)
if err != nil {
return nil, errs.ErrorArgs.WithMessage("开始时间格式错误")
}
req.StartDateLong = util.NewSecond(parse)
}
if req.EndDate != "" {
parse, err := time.Parse("2006-01-02", req.EndDate)
if err != nil {
return nil, errs.ErrorArgs.WithMessage("结束时间格式错误")
}
req.EndDateLong = util.NewSecond(parse)
}
total, list, err := p.camRepo.List(ctx, customerId, req) total, list, err := p.camRepo.List(ctx, customerId, req)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -21,16 +21,35 @@ func NewReportRepo(data *Data, logger log.Logger) biz.CampaignRepo { ...@@ -21,16 +21,35 @@ func NewReportRepo(data *Data, logger log.Logger) biz.CampaignRepo {
} }
func (p *campaignRepo) List(ctx context.Context, customerId int64, req *biz.ListCampaignRequest) (int64, biz.CampaignList, error) { func (p *campaignRepo) List(ctx context.Context, customerId int64, req *biz.ListCampaignRequest) (int64, biz.CampaignList, error) {
var list biz.CampaignList tableName := "ads_report_campaign_day"
db := p.data.db.Table("ads_report_campaign_day"). if req.TimeGranularity == biz.StatTimeGranularityHourly {
Select("campaign_id, campaign_name"). tableName = "ads_report_campaign_hour"
Where("customer_id = ?", customerId) }
db := p.data.db.Table(tableName).
Select("campaign_id, campaign_name, advertiser_id, date_long AS stat_datetime, cost, `show`, click, `convert`, "+
"deep_convert, attribution_convert, attribution_deep_convert, download_start, download_finish, click_install, "+
"install_finish, active, register, next_day_open, next_day_open_cost, next_day_open_rate, attribution_next_day_open_cnt,"+
" game_addiction, pay_count, in_app_uv, in_app_detail_uv, in_app_cart, in_app_pay, in_app_order, attribution_game_pay_7d_count,"+
" game_pay_count, total_play, valid_play, play_25_feed_break, play_50_feed_break, play_75_feed_break, play_100_feed_break, "+
"play_duration_sum, attribution_active_pay_intra_one_day_count, attribution_active_pay_intra_one_day_amount, gmt_modified AS timestamp").
Where("customer_id = ?", customerId).
Where("is_delete = ?", 0)
// add start_date and end_date condition
if req.StartDate != "" {
db = db.Where("date_long >= ?", req.StartDateLong)
}
if req.EndDate != "" {
db = db.Where("date_long <= ?", req.EndDateLong)
}
var total int64 var total int64
if err := db.Count(&total).Error; err != nil { if err := db.Count(&total).Error; err != nil {
return 0, nil, err return 0, nil, err
} }
if err := db.Limit(req.Limit()).Offset(req.Offset()).Scan(&list).Error; err != nil { var list biz.CampaignList
if err := db.Order(req.GetOrderBy("id") + " " + req.GetOrderByMode()).
Limit(req.Limit()).Offset(req.Offset()).Scan(&list).Error; err != nil {
return total, nil, err return total, nil, err
} }
return total, list, nil return total, list, nil
......
...@@ -5,16 +5,28 @@ import ( ...@@ -5,16 +5,28 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"demo/internal/biz/errs"
"demo/internal/util" "demo/internal/util"
) )
// ResponseError 公共返回错误处理 // ResponseError 公共返回错误处理
func ResponseError(c *gin.Context, err error) { func ResponseError(c *gin.Context, err error) {
c.AbortWithStatusJSON(http.StatusOK, gin.H{ if v, ok := err.(*errs.Error); ok {
util.RequestKey: c.GetString(util.RequestKey), if v.Code == errs.ServiceError.Code {
"code": http.StatusInternalServerError, v.Msg = errs.ServiceError.Msg
"message": err.Error(), }
}) c.AbortWithStatusJSON(http.StatusOK, gin.H{
util.RequestKey: c.GetString(util.RequestKey),
"code": v.Code,
"message": v.Msg,
})
} else {
c.AbortWithStatusJSON(http.StatusOK, gin.H{
util.RequestKey: c.GetString(util.RequestKey),
"code": errs.ServiceError.Code,
"message": errs.ServiceError.Msg,
})
}
} }
// ResponseSuccess 返回成功参数 // ResponseSuccess 返回成功参数
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"github.com/go-kratos/kratos/v2/log" "github.com/go-kratos/kratos/v2/log"
"demo/internal/biz" "demo/internal/biz"
"demo/internal/biz/errs"
"demo/internal/util" "demo/internal/util"
) )
...@@ -24,17 +25,20 @@ func NewReportService(uc *biz.ReportUsecase, logger log.Logger) *ReportService { ...@@ -24,17 +25,20 @@ func NewReportService(uc *biz.ReportUsecase, logger log.Logger) *ReportService {
func (p *ReportService) ListCampaignData(ctx *gin.Context) { func (p *ReportService) ListCampaignData(ctx *gin.Context) {
var req biz.ListCampaignRequest var req biz.ListCampaignRequest
if err := ctx.ShouldBind(&req); err != nil { if err := ctx.ShouldBind(&req); err != nil {
ResponseError(ctx, err) p.log.Error("ShouldBind err:", err)
ResponseError(ctx, errs.ErrorArgs)
return return
} }
customerIdStr := ctx.GetString(util.CustomerId) customerIdStr := ctx.GetString(util.CustomerId)
customerId, err := strconv.Atoi(customerIdStr) customerId, err := strconv.Atoi(customerIdStr)
if err != nil { if err != nil {
p.log.Error("Atoi err:", err)
ResponseError(ctx, err) ResponseError(ctx, err)
return return
} }
data, err := p.uc.ListCampaignData(ctx, int64(customerId), &req) data, err := p.uc.ListCampaignData(ctx, int64(customerId), &req)
if err != nil { if err != nil {
p.log.Error("ListCampaignData err:", err)
ResponseError(ctx, err) ResponseError(ctx, err)
return return
} }
......
package util
import (
"strconv"
"time"
)
type Second int64
func NewSecond(ts ...time.Time) Second {
t := time.Now()
if len(ts) > 0 {
t = ts[0]
}
v := t.Format(`20060102150405`)
minute, _ := strconv.Atoi(v)
return Second(minute)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment