diff --git a/app/admin/repositories/ad_revenue.py b/app/admin/repositories/ad_revenue.py index 062fa75..ec6bd4a 100644 --- a/app/admin/repositories/ad_revenue.py +++ b/app/admin/repositories/ad_revenue.py @@ -87,6 +87,7 @@ def ad_revenue_report( user_id: int | None = None, ad_type: str | None = None, feed_scene: str | None = None, + app_env: str | None = None, granularity: str = "day", limit: int = 500, offset: int = 0, @@ -156,8 +157,12 @@ def ad_revenue_report( "has_impression": True, "impressions": 1, "ecpm": rec.ecpm_raw, - # 单次展示收益(元)= eCPM元 ÷ 1000(每千次→单次);与发奖同源解析,口径一致。 - "revenue_yuan": round(rewards.parse_ecpm_yuan(rec.ecpm_raw) / 1000.0, 6), + # 单次展示收益(元)= eCPM元 ÷ 1000(每千次→单次)。eCPM 先钳到 AD_ECPM_MAX_FEN(¥500 CPM) + # 再折收益,与发奖口径 [rewards.calculate_ad_reward_coin] 一致(2026-06-29 修:原裸 parse_ecpm_yuan + # 不钳,伪造/异常天价 eCPM 会把报表预估收益冲到任意大;金币侧已钳、收益侧漏钳)。 + "revenue_yuan": round( + min(rewards.parse_ecpm_yuan(rec.ecpm_raw), rewards.AD_ECPM_MAX_FEN / 100.0) / 1000.0, 6, + ), "adn": rec.adn, "slot_id": rec.slot_id, } @@ -213,6 +218,14 @@ def ad_revenue_report( if feed_scene is not None: events = [e for e in events if e.get("feed_scene") == feed_scene] + # app_env 过滤(2026-06-29 新增能力,修隐患:测试应用上报的假 eCPM 如 ¥678 CPM 会污染正式收益合计/平均): + # 显式传 "prod"/"test" 只看该环境;不传=全部(维持现状)。**不擅自把默认改成排除 test**——本地 dev 库多为 + # test 数据、默认排除会使本地报表空,且「正式报表是否含 test」属产品口径。建议前端报表页加 app_env 筛选器 + # (默认选 prod),或产品确认后再把默认改成排除 test。注:穿山甲后台收益列(total_pangle_*)暂未联动此过滤 + # (它是独立对照列,且 pangle 的 test 是真实小额、非客户端那种假值)。 + if app_env is not None: + events = [e for e in events if e.get("app_env") == app_env] + # 排序:time=按时间倒序(新→旧);ecpm=按 eCPM 数值倒序(eCPM 原值是字符串「分」,转数值排; # 纯发奖行用其发奖采用的 eCPM,缺失/非法计 0 排末尾)。 if sort == "ecpm": diff --git a/app/admin/routers/ad_revenue.py b/app/admin/routers/ad_revenue.py index e9d81a9..dc6129f 100644 --- a/app/admin/routers/ad_revenue.py +++ b/app/admin/routers/ad_revenue.py @@ -56,6 +56,13 @@ def get_ad_revenue_report( "全局筛选,同时影响明细 / 合计 / 趋势" ), ] = None, + app_env: Annotated[ + str | None, + Query( + description="prod(正式应用) / test(测试应用);不传=全部。" + "建议正式收益报表选 prod,避免测试应用的假 eCPM 污染收益合计/平均" + ), + ] = None, granularity: Annotated[ str, Query(description="day=按天 / hour=按小时(北京时间);区间>1 天建议用 day") ] = "day", @@ -75,7 +82,7 @@ def get_ad_revenue_report( result = ad_revenue.ad_revenue_report( db, date_from=d_from.isoformat(), date_to=d_to.isoformat(), - user_id=user_id, ad_type=ad_type, feed_scene=feed_scene, + user_id=user_id, ad_type=ad_type, feed_scene=feed_scene, app_env=app_env, granularity=granularity, limit=limit, offset=offset, sort=sort, ) return AdRevenueReportOut(