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 } // GetStatistics 获取广告位统计数据 func (s *adPosition) GetStatistics(ctx context.Context, req *dto.GetAdPositionStatisticsReq) (res *dto.GetAdPositionStatisticsRes, err error) { statReq := &dto.GetAdStatisticsReq{ StatType: "adPosition", StatDimension: req.StatType, TargetId: req.Id, StartDate: req.StartDate, EndDate: req.EndDate, DeviceType: "", Platform: "", Region: "", Gender: "", AgeGroup: "", SortBy: "", SortDirection: "", } list, total, err := dao.AdStatistics.GetStatistics(ctx, statReq) if err != nil { return } res = &dto.GetAdPositionStatisticsRes{ Statistics: 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 }