Compare commits

..

1 Commits

Author SHA1 Message Date
linkeyu 71b4d84d5a feat(admin): group monitoring and audit navigation 2026-07-22 14:59:10 +08:00
2 changed files with 8 additions and 18 deletions
+7 -17
View File
@@ -76,28 +76,16 @@ const REWARD_STATUS_HINT: Record<string, string> = {
const PLAYBACK_STATUS_TAG: Record<string, { color: string; label: string }> = { const PLAYBACK_STATUS_TAG: Record<string, { color: string; label: string }> = {
completed: { color: 'green', label: '已完成' }, completed: { color: 'green', label: '已完成' },
too_short: { color: 'gold', label: '观看时长不足' }, too_short: { color: 'gold', label: '未满10秒' },
closed_early: { color: 'default', label: '提前关闭' }, closed_early: { color: 'default', label: '提前关闭' },
unknown: { color: 'default', label: '未知' }, unknown: { color: 'default', label: '未知' },
}; };
const ZERO_REVENUE_REWARD_VIDEO_STATUSES = new Set(['closed_early', 'too_short']);
function rewardStatuses(row: AdRevenueRow): string[] { function rewardStatuses(row: AdRevenueRow): string[] {
if (row.sub_rewards?.length) return row.sub_rewards.map((reward) => reward.status); if (row.sub_rewards?.length) return row.sub_rewards.map((reward) => reward.status);
return row.status ? [row.status] : []; return row.status ? [row.status] : [];
} }
function effectiveRevenueYuan(row: AdRevenueRow): number {
if (
row.ad_type === 'reward_video'
&& rewardStatuses(row).some((status) => ZERO_REVENUE_REWARD_VIDEO_STATUSES.has(status))
) {
return 0;
}
return row.row_revenue_yuan ?? row.revenue_yuan;
}
function rewardStatusTag(row: AdRevenueRow) { function rewardStatusTag(row: AdRevenueRow) {
const statuses = rewardStatuses(row); const statuses = rewardStatuses(row);
if (!row.has_reward || statuses.length === 0) { if (!row.has_reward || statuses.length === 0) {
@@ -159,7 +147,7 @@ function playbackStatusTag(row: AdRevenueRow) {
const hint = entries const hint = entries
.map(([status, count]) => `${PLAYBACK_STATUS_TAG[status].label} ${count}`) .map(([status, count]) => `${PLAYBACK_STATUS_TAG[status].label} ${count}`)
.join(''); .join('');
return { color: 'purple', label: '部分完成', hint: `${hint}` }; return { color: 'purple', label: '混合状态', hint: `${hint}` };
} }
const fmtFactorRange = (a: number | null, b: number | null) => { const fmtFactorRange = (a: number | null, b: number | null) => {
@@ -558,8 +546,10 @@ export default function AdRevenueReportPage() {
width: 110, width: 110,
align: 'right', align: 'right',
// 一次比价/领券聚合行用 row_revenue_yuan(该次发奖广告 eCPM 折算之和),其它行用展示侧 revenue_yuan // 一次比价/领券聚合行用 row_revenue_yuan(该次发奖广告 eCPM 折算之和),其它行用展示侧 revenue_yuan
// 激励视频提前关闭/时长不足时防御性显示 0,与后端有效收益口径一致。 render: (v: number, r: AdRevenueRow) => {
render: (_v: number, r: AdRevenueRow) => effectiveRevenueYuan(r).toFixed(4), const rev = r.row_revenue_yuan ?? v;
return rev.toFixed(4);
},
}, },
{ {
title: '发奖状态', title: '发奖状态',
@@ -705,7 +695,7 @@ export default function AdRevenueReportPage() {
<br /> <br />
<br /> <br />
广(onAdShow) eCPM ( ÷1000 广(onAdShow) eCPM ( ÷1000
);<b> 0 </b>, eCPM 穿, ),<b>广</b>;穿/,,
<b>穿</b> 0广ID / , <b>穿</b> 0广ID / ,
<br /> <br />
<br /> <br />
+1 -1
View File
@@ -488,7 +488,7 @@ export interface AdRevenueRow {
has_impression: boolean; // 是否有广告展示(信息流逐条展示=true,纯发奖行=false) has_impression: boolean; // 是否有广告展示(信息流逐条展示=true,纯发奖行=false)
impressions: number; // 本行展示条数 1/0(供日汇总、趋势图复用) impressions: number; // 本行展示条数 1/0(供日汇总、趋势图复用)
ecpm: string | null; // 分/千次;展示行取展示值,纯发奖行取发奖采用值 ecpm: string | null; // 分/千次;展示行取展示值,纯发奖行取发奖采用值
revenue_yuan: number; // 本次有效展示预估收益(元);纯发奖、激励视频提前关闭/时长不足=0 revenue_yuan: number; // 本次展示预估收益(元);纯发奖=0
row_revenue_yuan?: number | null; // 主表逐行显示用:一次比价/领券聚合行=该次发奖广告 eCPM 折算之和;其它行空(回退 revenue_yuan) row_revenue_yuan?: number | null; // 主表逐行显示用:一次比价/领券聚合行=该次发奖广告 eCPM 折算之和;其它行空(回退 revenue_yuan)
adn: string | null; // 实际填充 ADN;纯发奖行为空 adn: string | null; // 实际填充 ADN;纯发奖行为空
slot_id: string | null; // 底层 mediation rit;纯发奖行为空 slot_id: string | null; // 底层 mediation rit;纯发奖行为空