"""admin 大盘 schemas(对应 stats.dashboard_overview 的嵌套结构)。""" from __future__ import annotations from datetime import date from pydantic import BaseModel class DashboardUsers(BaseModel): total: int active: int disabled: int deleted: int new_today: int dau: int class DashboardCoins(BaseModel): reward_video_coin_total: int = 0 reward_video_watch_count: int = 0 feed_ad_coin_total: int = 0 feed_ad_watch_count: int = 0 signin_coin_total: int = 0 signin_count: int = 0 signin_boost_coin_total: int = 0 signin_boost_watch_count: int = 0 granted_total: int class DashboardCash(BaseModel): withdraw_success_cents: int withdraw_pending_count: int withdraw_success_count: int withdraw_failed_count: int class DashboardComparison(BaseModel): total: int success: int success_rate: float class DashboardPeriodUsers(BaseModel): new: int active: int # 次日留存(2026-07-05 起):retained_new_users = 窗口内逐日「前一日新增且当日活跃」用户数之和, # retention_cohort = 对应的前一日新增基数之和,retention_rate = 两者之比。 retained_new_users: int retention_cohort: int = 0 retention_rate: float | None = None retention_note: str class DashboardPeriodComparison(BaseModel): total: int success: int success_rate: float ordered: int average_duration_ms: int | None = None average_saved_cents: int | None = None class DashboardPeriodCoupon(BaseModel): """领券核心数据(2026-07-05 产品新增)。点位=一张券(coupon_claim_record 一天一条终态); 成功口径 success+already_claimed(与「我的」页累计领券一致)。""" started: int = 0 # 全部领成功的次数:completed 且当日该设备全部点位成功 all_success: int = 0 success_rate: float | None = None # 本期 session 触达的点位中成功的条数(同设备同日去重) point_success: int = 0 # 每次发起的应领点位数(本期完成场实际点位数的众数;无完成场为空) points_per_session: int | None = None # 点位成功率 = point_success / (started × points_per_session);未跑到的点位计入分母视为失败 point_success_rate: float | None = None # 耗时中位数(仅 completed 的 elapsed_ms,同「领券数据」页口径) median_elapsed_ms: int | None = None class DashboardPeriodCoins(BaseModel): granted_total: int reward_video_coin_total: int = 0 feed_ad_coin_total: int = 0 signin_coin_total: int = 0 signin_boost_coin_total: int = 0 task_coin_total: int = 0 coupon_reward_coin_total: int = 0 comparison_reward_coin_total: int = 0 regular_task_coin_total: int = 0 class DashboardPeriodCash(BaseModel): withdraw_success_cents: int class DashboardTrendPoint(BaseModel): date: date active_users: int new_users: int comparisons: int class DashboardPeriod(BaseModel): date_from: date date_to: date users: DashboardPeriodUsers comparison: DashboardPeriodComparison coupon: DashboardPeriodCoupon = DashboardPeriodCoupon() coins: DashboardPeriodCoins cash: DashboardPeriodCash trend: list[DashboardTrendPoint] = [] class DashboardFeedback(BaseModel): new: int class DashboardCps(BaseModel): available: bool note: str meituan_order_count: int = 0 meituan_commission_cents: int = 0 meituan_hit_count: int = 0 meituan_miss_count: int = 0 meituan_unknown_rate_count: int = 0 meituan_hit_rate: float | None = None jd_order_count: int = 0 jd_commission_cents: int = 0 jd_actual_commission_cents: int = 0 jd_estimated_commission_cents: int = 0 jd_invalid_count: int = 0 class DashboardOverview(BaseModel): users: DashboardUsers coins: DashboardCoins cash: DashboardCash comparison: DashboardComparison period: DashboardPeriod feedback: DashboardFeedback cps: DashboardCps