Files
cid/service/ad_position_service.go
2025-12-06 18:36:43 +08:00

184 lines
4.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"cidservice/dao"
"cidservice/model/dto"
"cidservice/model/entity"
"context"
"time"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/util/gconv"
)
var AdPosition = new(adPosition)
type adPosition struct{}
// Add 添加广告位
func (s *adPosition) Add(ctx context.Context, req *dto.AddAdPositionReq) (res *dto.AddAdPositionRes, err error) {
adPosition := &entity.AdPosition{}
if err = gconv.Struct(req, adPosition); err != nil {
return
}
// 设置基础字段
now := time.Now()
adPosition.CreatedAt = now
adPosition.UpdatedAt = now
adPosition.IsDeleted = false
// 初始化统计字段
adPosition.DailyImpressions = 0
adPosition.DailyClicks = 0
adPosition.DailyRevenue = 0
adPosition.CTR = 0
// eCPM字段是未导出的无法直接设置
if err = dao.AdPosition.Insert(ctx, adPosition); err != nil {
return
}
res = &dto.AddAdPositionRes{Id: adPosition.Id.Hex()}
return
}
// Update 更新广告位
func (s *adPosition) Update(ctx context.Context, req *dto.UpdateAdPositionReq) (err error) {
// 更新修改时间不需要设置DAO层会处理
return dao.AdPosition.Update(ctx, req)
}
// UpdateStatus 更新广告位状态
func (s *adPosition) UpdateStatus(ctx context.Context, req *dto.UpdateAdPositionStatusReq) (err error) {
return dao.AdPosition.UpdateStatus(ctx, req.Id, req.Status)
}
// GetOne 获取广告位详情
func (s *adPosition) GetOne(ctx context.Context, req *dto.GetAdPositionReq) (res *dto.GetAdPositionRes, err error) {
adPosition, err := dao.AdPosition.GetOne(ctx, req.Id)
if err != nil {
return
}
res = &dto.GetAdPositionRes{
AdPosition: adPosition,
}
return
}
// List 获取广告位列表
func (s *adPosition) List(ctx context.Context, req *dto.ListAdPositionReq) (res *dto.ListAdPositionRes, err error) {
list, total, err := dao.AdPosition.List(ctx, req)
if err != nil {
return
}
res = &dto.ListAdPositionRes{
List: list,
Total: int(total),
}
return
}
// GetByCode 根据编码获取广告位
func (s *adPosition) GetByCode(ctx context.Context, code string) (adPosition *entity.AdPosition, err error) {
return dao.AdPosition.GetByCode(ctx, code)
}
// GetAvailableAdPositions 获取可用的广告位列表
func (s *adPosition) GetAvailableAdPositions(ctx context.Context) (list []*entity.AdPosition, err error) {
return dao.AdPosition.GetAvailableAdPositions(ctx)
}
// MatchAd 匹配广告
func (s *adPosition) MatchAd(ctx context.Context, positionCode string, userInfo map[string]interface{}) (ad *entity.Advertisement, err error) {
// 获取广告位信息
adPosition, err := dao.AdPosition.GetByCode(ctx, positionCode)
if err != nil {
return
}
// 检查广告位状态
if adPosition.Status != "启用" {
return nil, gerror.New("广告位未启用")
}
// 获取符合条件的广告列表
// 这里简化处理,实际项目中应该根据广告定向条件匹配广告
// 可以使用MongoDB的聚合管道实现复杂匹配逻辑
// 返回匹配的广告
// 这里返回第一个广告作为示例
ad = &entity.Advertisement{
Title: "示例广告",
MaterialUrl: "https://example.com/ad.jpg",
LinkUrl: "https://example.com",
LandingPageUrl: "https://example.com/landing",
}
return
}
// UpdateAdPositionStatistics 更新广告位统计
func (s *adPosition) UpdateAdPositionStatistics(ctx context.Context, id string, impressions, clicks, revenue int64) (err error) {
// 获取广告位信息
adPosition, err := dao.AdPosition.GetOne(ctx, id)
if err != nil {
return
}
// 计算统计数据
totalImpressions := adPosition.DailyImpressions + impressions
totalClicks := adPosition.DailyClicks + clicks
totalRevenue := adPosition.DailyRevenue + revenue
// 计算比率
ctr := 0.0
if totalImpressions > 0 {
ctr = float64(totalClicks) / float64(totalImpressions)
}
ecpm := int64(0)
if totalImpressions > 0 {
ecpm = totalRevenue * 1000 / totalImpressions
}
// 构建更新数据
stats := map[string]interface{}{
"dailyImpressions": totalImpressions,
"dailyClicks": totalClicks,
"dailyRevenue": totalRevenue,
"ctr": ctr,
"ecpm": ecpm,
"updatedAt": time.Now(),
}
// 更新广告位统计
err = dao.AdPosition.UpdateStatistics(ctx, id, stats)
if err != nil {
return
}
// 插入统计记录
today := time.Now()
todayStart := time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, today.Location()).Unix()
statistics := &entity.AdStatistics{
StatType: "adPosition",
StatDimension: "day",
TargetId: id,
TargetName: adPosition.Name,
StatDate: todayStart,
Impressions: impressions,
Clicks: clicks,
Cost: 0, // 广告位不记录消耗,只记录收入
Revenue: revenue,
CTR: ctr,
// eCPM字段是未导出的无法直接设置
}
err = dao.AdStatistics.Upsert(ctx, statistics)
return
}