# Admin 看广告金币审计 > 所属:Admin 组(前缀 `/admin/api/ad-coin-audit`) | 鉴权:Admin Bearer(任意已登录 admin,只读) | [← 返回 API 索引](../../README.md) 把「看视频赚金币」(`ad_reward_record`)和「比价信息流广告」(`ad_feed_reward_record`)两类发奖记录,用与**正式发奖完全相同**的公式 [`app/core/rewards.py` `calculate_ad_reward_coin`](../../app/core/rewards.py) 复算一遍 `expected_coin`,与实际入账的 `actual_coin` 对比,核对金币公式是否生效。**纯只读对账**,不发币、不改任何数据。 相关表:[ad_reward_record](../database/ad_reward_record.md)、[ad_feed_reward_record](../database/ad_feed_reward_record.md)。 ## 金币公式(展示参照) ``` eCPM元 = getEcpm分 ÷ 100 单份金币 = round( eCPM元 ÷ 1000 × 因子1 × 因子2 × coin_per_yuan ) # coin_per_yuan=10000 ``` - **eCPM 口径**:`getEcpm()` 原值单位是分/千次展示;先 ÷100 转元,**因子判档与收益换算都用元**。 - **因子1(eCPM 档,阈值单位=元/千次)**:≤100→0.1,101–200→0.3,201–400→0.4,>400→0.6(即 ¥100/¥200/¥400 CPM 分界。**真实 eCPM 多 <¥100 CPM,故常落最低档 0.1,高档基本不触发——产品有意取舍**)。 - **因子2(LT,当日第 N 份)**:第1→2.0,第2→1.5,第3→1.3,第4–10→1.1,≥11→1.0。 - **第 N 份的计数**:看视频每条 granted 记 1 份;信息流每满 10 秒记 1 份。**两个点位各自独立计数**(看视频的份数不影响信息流的份数,反之亦然)。 ## GET /admin/api/ad-coin-audit — 复算对比 - 入参(均 query,可选): | 参数 | 类型 | 默认 | 说明 | |---|---|---|---| | `date` | string | 今天 | 北京时间 `YYYY-MM-DD`,审计某天 | | `user_id` | int | 全部 | 只看某用户;不传=所有用户 | | `scene` | string | 两类 | `reward_video` / `feed`;不传=两类都返回 | | `limit` | int(1~500) | 100 | **展示**明细条数(按时间倒序截断;**份序号在截断前已按全天数据算好**,不影响复算正确性) | | `only_mismatch` | bool | false | 只展示不一致(✗)行;统计数仍按全量,不受影响 | - 出参 `200`:`AdCoinAuditOut` | 字段 | 类型 | 说明 | |---|---|---| | `date` | string | 审计日期 | | `formula` | object | 当前公式参数快照(见下) | | `total` | int | 该筛选下复算**总条数**(全量,不受 `limit`/`only_mismatch` 影响) | | `mismatch_count` | int | **全量**不一致条数(截断前统计,可信);**=0 说明全部按公式发放** | | `truncated` | bool | 展示集是否被 `limit` 截断(true=还有未返回的明细,请缩小范围或调大 `limit`) | | `items` | `AdCoinAuditRow[]` | 展示明细(见下);`only_mismatch=true` 时只含 ✗ 行 | ### AdCoinFormulaOut(`formula`) | 字段 | 类型 | 说明 | |---|---|---| | `description` | string | 公式文字说明 | | `coin_per_yuan` | int | 金币:元 汇率(10000) | | `ecpm_unit` | string | eCPM 口径(分/千次展示,SDK getEcpm 原值) | | `feed_unit_seconds` | int | 信息流每多少秒折 1 份(10) | | `ecpm_factor_tiers` | `[因子, 下限, 上限\|null][]` | 因子1 档位表(直接读发奖常量,与发奖同源) | | `lt_factor_tiers` | `[因子, 下限, 上限\|null][]` | 因子2 LT 档位表 | ### AdCoinAuditRow(`items[]`) | 字段 | 类型 | 说明 | |---|---|---| | `scene` | string | `reward_video` / `feed` | | `record_id` | int | 对应记录表主键 | | `user_id` | int | | | `created_at` | datetime | | | `status` | string | `granted` / `capped`(超每日上限未发) / `ecpm_missing`(缺 eCPM 未发) | | `ecpm` | string \| null | 本次采用的 eCPM 原始值 | | `ecpm_factor` | float \| null | 因子1;非 granted 为 null | | `units` | int | 折算份数:看视频恒 1;信息流 = 满 10 秒份数 | | `lt_index_start` / `lt_index_end` | int \| null | 本条占用「当日第几份」的起止(看视频起=止;信息流一条可跨多份) | | `lt_factor_start` / `lt_factor_end` | float \| null | 因子2 的起止值(信息流跨份时会衰减,故给区间) | | `expected_coin` | int | 按公式复算应发金币(非 granted 恒 0) | | `actual_coin` | int | 实际入账金币 | | `matched` | bool | 复算与实发是否一致;非 granted 校验实发是否确为 0 | ## 说明 - **非 granted 行**(capped/ecpm_missing)不占用份序号、应发恒 0,`matched` 用于校验「该不发的确实没发」。 - 用法建议:**按 `user_id`+`date` 定位某次具体核对**最直观;不带 `user_id` 是全用户当天概览。 - 本地联调造数:debug 包看完激励视频会调 [`/api/v1/ad/test-grant`](./ad-test-grant.md),它会用客户端按 `ad_session_id` 上报的真实 eCPM 发奖(取不到兜底 200),所以本审计能看到真实 eCPM 对应的金币。