// 与后端 app/admin/schemas/* 对齐的类型定义。 export interface AdminInfo { id: number; username: string; role: string; // super_admin / finance / operator / custom(自定义) / 自定义角色名 status: string; created_at: string; last_login_at: string | null; pages?: string[]; // 当前有效可见页 key(登录 / /me 下发);super_admin = 全部页;role==custom = pages_override。左侧导航按此过滤 pages_override?: string[] | null; // 「自定义」勾选的可见页原始集(role==custom 时非空);列表接口下发,供编辑回填勾选 password?: string | null; // 明文登录密码(仅账号列表下发);无留存(脚本建的超管)为 null → 不显示 } // RBAC:页面权限目录(= 左侧导航项,后端 /admin/api/roles/catalog 下发) export interface PermissionPage { key: string; label: string; } export interface PermissionGroup { group: string; pages: PermissionPage[]; } // RBAC:角色(可见页集合) export interface AdminRole { id: number; name: string; // 角色 key(承重,admin_user.role 引用) label: string; // 展示名(UI 显示,如 管理员/运营/财务/技术) pages: string[]; // 该角色有效可见页 key(super_admin = 全部) is_builtin: boolean; // 内建(super_admin):不可编辑/删除 in_use: number; // 使用该角色的管理员数 } export interface LoginResponse { access_token: string; token_type: string; expires_in: number; admin: AdminInfo; } export interface CursorPage { items: T[]; next_cursor: number | null; total?: number | null; // offset 分页时为符合筛选条件的总条数(页码分页用);加载更多接口可能没有 } export interface UserListItem { id: number; phone: string; nickname: string | null; register_channel: string; status: string; // 调试链接权限:开了的用户在 App 比价结果页/记录页可复制 price.shaguabijia.com 的 trace 调试链接 debug_trace_enabled: boolean; // 运营「一键开启新手引导」:true = 该用户下次打开 App 会被强制重走新手引导,走完自动取消 force_onboarding: boolean; wechat_openid: string | null; created_at: string; last_login_at: string; // 最近活跃 = max(最近登录, 最近发起比价, 最近发起领券);与大盘 DAU/留存活跃口径一致 last_active_at: string | null; } // 设备维度新手引导:一台设备(ANDROID_ID)聚合,走过引导的账号数 + 最近完成时间。 export interface DeviceOnboardingItem { device_id: string; account_count: number; last_completed_at: string; } // 设备存活监控:device_liveness 表一行 + 后端按心跳阈值派生的在线/掉线/掉线时长。 export interface DeviceLivenessItem { id: number; user_id: number; phone: string | null; nickname: string | null; device_id: string; device_model: string | null; // 由 device_id 解析的机型 platform: string; app_version: string | null; registration_id: string | null; // 非空 = 可极光推送 ever_protected: boolean; first_protected_at: string | null; // 首次开无障碍时刻(老设备为 null) last_heartbeat_at: string | null; last_report_protection_on: boolean; liveness_state: string; // unknown / alive / silent(当前未用) / notified notified_at: string | null; kill_alert_pending: boolean; // 掉线召回待客户端 ack created_at: string; updated_at: string; // 后端派生 online: boolean; display_state: string; // online 在线 / offline 已掉线 / never 未启用 offline_seconds: number | null; // 掉线时长(秒);仅 offline 有值 } export interface DeviceLivenessStats { total: number; online: number; offline: number; never: number; } export interface UserOverview { user: UserListItem; coin_balance: number; cash_balance_cents: number; invite_cash_balance_cents: number; // 邀请奖励金余额(与 cash_balance_cents 物理隔离) total_coin_earned: number; comparison_total: number; comparison_success: number; withdraw_total: number; withdraw_success_cents: number; feedback_total: number; } export interface CoinTxn { id: number; user_id: number; amount: number; balance_after: number; biz_type: string; ref_id: string | null; remark: string | null; created_at: string; } export interface CashTxn { id: number; user_id: number; amount_cents: number; balance_after_cents: number; biz_type: string; ref_id: string | null; remark: string | null; created_at: string; } export interface WithdrawOrder { id: number; user_id: number; out_bill_no: string; amount_cents: number; // 提现类型:coin_cash(福利页提现,金币兑换现金) / invite_cash(邀请提现,邀请奖励金) source: string; user_name: string | null; status: string; // reviewing / pending / success / failed / rejected wechat_state: string | null; transfer_bill_no: string | null; fail_reason: string | null; created_at: string; updated_at: string; } // 提现列表项:WithdrawOrder + 列表接口联表带出的用户字段。 // 详情抽屉的 recent_withdraws 仍是裸 WithdrawOrder(无这些字段)。 export interface WithdrawListItem extends WithdrawOrder { phone: string | null; nickname: string | null; cumulative_success_cents: number; // 累计成功提现(分) } export interface WithdrawSummary { reviewing_count: number; reviewing_amount_cents: number; pending_count: number; failed_count: number; today_success_count: number; today_success_amount_cents: number; today_rejected_count: number; } export interface WithdrawUserSnapshot { id: number; phone: string; nickname: string | null; status: string; wechat_nickname: string | null; wechat_avatar_url: string | null; created_at: string; last_login_at: string; cash_balance_cents: number; withdraw_total: number; withdraw_success_cents: number; } export interface WithdrawDetail { order: WithdrawOrder; user: WithdrawUserSnapshot | null; risk_flags: string[]; risk_score: number; recent_withdraws: WithdrawOrder[]; recent_cash_transactions: CashTxn[]; audit_logs: AuditLog[]; } // 提现详情抽屉「用户统计区」:按时间窗口算的提现 + 看广告行为统计。 // *_cash_cents = 该来源累计金币折算成可提现现金(分);现金余额是当前快照不随窗口。 export interface UserRewardStats { withdraw_success_cents: number; // 累计提现 cash_balance_cents: number; // 现金余额(快照) withdraw_total: number; // 提现总次数(全部状态) traditional_task_cash_cents: number; // 传统任务提现 reward_video_count: number; // 累计激励视频数 reward_video_avg_ecpm: number; // 平均激励视频 eCPM(分/千次) reward_video_cash_cents: number; // 激励视频提现 feed_count: number; // 累计信息流广告数(份) feed_avg_ecpm: number; // 平均信息流广告 eCPM(分/千次) feed_cash_cents: number; // 信息流广告提现 } // 金币发放记录(提现详情底部表)。ecpm 为原始分/千次,非广告来源为 null。 export interface UserCoinRecord { source: string; // reward_video / signin_boost / feed / signin source_label: string; // 激励视频 / 签到膨胀 / 信息流广告 / 签到 created_at: string; ecpm: string | null; coin: number; } export interface WithdrawBulkItemResult { out_bill_no: string; ok: boolean; status: string | null; error: string | null; } export interface WithdrawBulkResult { total: number; success: number; failed: number; items: WithdrawBulkItemResult[]; } export interface WithdrawLedgerCheck { ok: boolean; // 普通现金账(coin_cash) cash_balance_total_cents: number; cash_transaction_total_cents: number; balance_diff_cents: number; missing_withdraw_txn_count: number; missing_refund_txn_count: number; duplicate_refund_txn_count: number; refund_txn_on_non_terminal_count: number; // 邀请奖励金账(invite_cash:与普通现金物理隔离,各自对账) invite_cash_balance_total_cents: number; invite_cash_transaction_total_cents: number; invite_balance_diff_cents: number; invite_missing_withdraw_txn_count: number; invite_missing_refund_txn_count: number; invite_duplicate_refund_txn_count: number; invite_refund_txn_on_non_terminal_count: number; } export interface WxpayHealthCheck { ok: boolean; wxpay_configured: boolean; wxpay_auth_configured: boolean; private_key_path: string; private_key_exists: boolean; private_key_loadable: boolean; public_key_path: string; public_key_exists: boolean; public_key_loadable: boolean; auth_notify_url_configured: boolean; auto_reconcile_enabled: boolean; auto_reconcile_interval_sec: number; auto_reconcile_older_than_minutes: number; issues: string[]; } export interface Feedback { id: number; user_id: number; content: string; contact: string; // 反馈来源入口:profile(「我的」页=普通反馈) / comparison(比价结果页=比价反馈) source: string; // 比价反馈的问题场景(找错商品/优惠不对…);普通反馈为 null scene: string | null; images: string[] | null; // pending(审核中) / adopted(已采纳) / rejected(未采纳);历史数据可能为 new status: string; reject_reason: string | null; // 未采纳原因(用户端可见) reward_coins: number | null; // 采纳后发放金币 review_note: string | null; // 审核批注(采纳要点 / 内部备注,用户不可见) admin_reply: string | null; // 运营给用户的回复留言(用户端可见) reviewed_by_admin_id: number | null; reviewed_at: string | null; created_at: string; // 提交端环境快照:提交版本号 / 机型OS版本;改版前的历史反馈为 null app_version: string | null; device_model: string | null; rom_name: string | null; android_version: string | null; // 联表瞬态:展示完整手机号(点手机号查该用户全部反馈) phone: string | null; nickname: string | null; } // 反馈审核台顶部各状态计数(pending 含历史 new 态)。后端 GET /admin/api/feedbacks/summary。 export interface FeedbackSummary { pending: number; adopted: number; rejected: number; total: number; } // 反馈页「加群二维码」卡配置(运营后台改 → App 意见反馈页同步)。 // image_url 为后端 /media 相对路径(留空=App 走本地兜底图);其余为卡片三行文案与显隐开关。 export interface FeedbackQrConfig { enabled: boolean; image_url: string | null; title: string; // 第一行(操作提示),如「长按图片保存二维码」 group_name: string; // 第二行加粗群名,App 渲染为 直通「{group_name}」 subtitle: string; // 第三行(标语) updated_at: string | null; } export interface AuditLog { id: number; admin_id: number; admin_username: string; action: string; target_type: string; target_id: string | null; detail: Record | null; ip: string | null; created_at: string; } // 广告收益报表聚合行下钻的单条展示明细 // ===== 比价记录(admin debug 页)===== export interface ComparisonRecordListItem { id: number; user_id: number; phone: string | null; nickname: string | null; business_type: string; trace_id: string; trace_url: string | null; status: string; information: string | null; store_name: string | null; product_names: string | null; // 下单商品名派生串(顿号分隔),「商品」列展示 source_platform_name: string | null; best_platform_name: string | null; source_price_cents: number | null; best_price_cents: number | null; saved_amount_cents: number | null; total_ms: number | null; step_count: number | null; llm_call_count: number | null; retry_count: number | null; input_tokens: number | null; output_tokens: number | null; device_model: string | null; rom_vendor: string | null; rom_name: string | null; android_version: string | null; app_version: string | null; created_at: string; } // 单次 LLM 调用明细(pricebot chat() 收口落盘,server 按 trace 拉来) export interface LlmCall { ts?: number; scene: string; model: string; input_messages: { role: string; content: string }[]; output: string | null; usage: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number } | null; latency_ms: number | null; error: string | null; } export interface ComparisonRecordDetail extends ComparisonRecordListItem { source_platform_id: string | null; source_package: string | null; best_platform_id: string | null; best_deeplink: string | null; is_source_best: boolean | null; total_dish_count: number | null; skipped_dish_count: number | null; device_id: string | null; items: { name: string; qty?: number; specs?: string[] }[]; comparison_results: Record[]; skipped_dish_names: string[]; device_manufacturer: string | null; rom_version: number | null; android_sdk: number | null; app_version_code: number | null; source_app_version: string | null; longitude: number | null; latitude: number | null; llm_calls: LlmCall[] | null; raw_payload: Record | null; } export interface AdRevenueImpression { id: number; created_at: string; ecpm: string; // 分/千次展示 revenue_yuan: number; // 本次展示预估收益(元) adn: string | null; slot_id: string | null; // 底层 mediation rit } // 广告收益报表聚合行下钻的单条发奖复算明细 export interface AdRevenueRecord { record_id: number; created_at: string; status: string; // granted / capped / ecpm_missing / too_short / closed_early ecpm: string | null; ecpm_factor: number | null; // 因子1 units: number; // 份数 lt_index_start: number | null; lt_index_end: number | null; lt_factor_start: number | null; // 因子2 lt_factor_end: number | null; expected_coin: number; actual_coin: number; matched: boolean; } // 广告收益报表:按日期汇总的一天(按天趋势图用;全量,不受分页影响) export interface AdRevenueDaily { date: string; // 北京时间 YYYY-MM-DD impressions: number; revenue_yuan: number; // 客户端预估收益(eCPM 折算) pangle_revenue_yuan: number | null; // 穿山甲后台预估收益(GroMore revenue);非全量视图/无数据为 null pangle_api_revenue_yuan: number | null; // 穿山甲收益API(更接近结算);未配/当天/无数据为 null expected_coin: number; actual_coin: number; } // 广告收益报表:按北京小时(0–23)汇总的一小时(按小时趋势图用;全量,不受分页影响;按天查询时为空) export interface AdRevenueHourly { hour: number; // 北京时间小时 0–23 impressions: number; revenue_yuan: number; expected_coin: number; actual_coin: number; } // 广告收益报表:按广告类型(ad_type)的小计(展示条数 + 预估收益;eCPM 前端用 收益÷展示×1000 算) export interface AdRevenueTypeStat { impressions: number; // 该类型展示条数合计 revenue_yuan: number; // 该类型预估收益合计(元) } // 广告收益报表:一次广告事件(逐条一行)。激励视频展示+发奖按 ad_session_id 合并;信息流展示/发奖各自成行。 export interface AdRevenueRow { event_key: string; // 事件稳定唯一键(前端 rowKey) report_date: string; // 该事件所属日期 北京时间 YYYY-MM-DD user_id: number; user_phone: string | null; // 用户手机号(admin 展示;查不到为空) ad_type: string; // reward_video / feed / draw feed_scene?: string | null; // Draw 信息流投放场景 comparison(比价) / coupon(领券) / welfare(福利);非信息流或旧数据为 null app_env: string | null; // prod(傻瓜比价) / test(测试);旧数据为空 our_code_id: string | null; // 我们配置的代码位 104xxx;旧数据为空 hour: number | null; // 北京时间小时 0–23(按小时粒度时有值;按天为 null) created_at: string; // 事件时间(有展示=展示时间,纯发奖=发奖时间) // ── 展示侧 ── has_impression: boolean; // 是否有广告展示(信息流逐条展示=true,纯发奖行=false) impressions: number; // 本行展示条数 1/0(供日汇总、趋势图复用) ecpm: string | null; // 分/千次;展示行取展示值,纯发奖行取发奖采用值 revenue_yuan: number; // 本次展示预估收益(元);纯发奖行=0 row_revenue_yuan?: number | null; // 主表逐行显示用:一次比价/领券聚合行=该次发奖广告 eCPM 折算之和;其它行空(回退 revenue_yuan) adn: string | null; // 实际填充 ADN;纯发奖行为空 slot_id: string | null; // 底层 mediation rit;纯发奖行为空 // ── 发奖侧 ── has_reward: boolean; // 是否有发奖(激励视频合并行/信息流整场发奖行=true;纯展示=false) status: string | null; // 发奖状态 granted/closed_early/…;纯展示为空 expected_coin: number; // 应发金币;纯展示=0 actual_coin: number; // 实发金币;纯展示=0 matched: boolean; // 本条应发==实发;纯展示恒 true(不计对账) reward_detail: AdRevenueRecord | null; // 发奖复算明细(点行展开下钻);纯展示为空 sub_rewards?: AdRevenueRecord[]; // 一次比价/领券聚合行的组内逐条明细(同整场 ad_session_id 的多条广告);展开渲染多行 sub_count?: number; // 本行聚合的发奖条数:一次比价/领券=该次广告条数(≥1);激励视频/纯展示=1 } export interface AdRevenueReport { date_from: string; // 起始日 北京时间 YYYY-MM-DD date_to: string; // 结束日 北京时间 YYYY-MM-DD(闭区间;单日时与 date_from 相同) daily: AdRevenueDaily[]; // 按日期汇总序列(全量,供按天趋势图) hourly: AdRevenueHourly[]; // 按小时汇总序列(全量,供按小时趋势图;按天查询时为空) type_stats: Record; // 按广告类型小计;前端取 draw / reward_video // 按信息流场景小计(comparison/coupon/welfare;全量,不受分页截断)。数据大盘「领券广告/比价广告」卡 // 优先读它:2026-07-02 后端起 items 不再含信息流逐条展示行(唯一带收益+场景的行),按 items 现算恒 0。 // 可选(`?.` 探测)以兼容未升级后端,缺失时回退 items 现算。 scene_stats?: Record; // 可选:后端预聚合的「按广告类型」富小计(含发放金币明细)。当前后端未下发 → 数据大盘页 // (dashboard adTypeSummary)用 `?.` 探测、缺失时按 items 现算兜底;后端补上即自动启用。 by_ad_type?: Record< string, { ad_type: string; impressions: number; revenue_yuan: number; expected_coin: number; actual_coin: number } >; dau: number | null; // 区间去重活跃用户(口径同数据大盘 period.users.active:登录+开始比价+开始领券);按查询区间统计、含今日,全局口径不随筛选变化 total: number; // 当前筛选下的分页总条数(全量,不受分页影响) truncated: boolean; // 当前页之后是否还有更多事件(分页后前端不再据此报警) total_impressions: number; total_revenue_yuan: number; // 客户端预估收益合计(eCPM 折算) total_pangle_revenue_yuan: number | null; // 穿山甲后台预估收益合计(GroMore revenue);非全量视图/无数据为 null total_pangle_api_revenue_yuan: number | null; // 穿山甲收益API合计(更接近结算);未配/当天/非全量视图为 null pangle_revenue_available: boolean; // 本次结果是否带穿山甲后台收益(全量视图且已同步到数据) total_expected_coin: number; total_actual_coin: number; mismatch_count: number; // 应发≠实发的发奖条数 items: AdRevenueRow[]; } export interface DashboardOverview { users: { total: number; active: number; disabled: number; deleted: number; new_today: number; dau: number; }; coins: { reward_video_coin_total: number; reward_video_watch_count: number; feed_ad_coin_total: number; feed_ad_watch_count: number; signin_coin_total: number; signin_count: number; signin_boost_coin_total: number; signin_boost_watch_count: number; granted_total: number; }; cash: { withdraw_success_cents: number; withdraw_pending_count: number; withdraw_success_count: number; withdraw_failed_count: number; }; comparison: { total: number; success: number; success_rate: number }; // 时段大盘(对应后端 app/admin/schemas/dashboard.py DashboardPeriod);新版数据大盘页用 period: { date_from: string; date_to: string; users: { new: number; active: number; retained_new_users: number; // 次日留存基数:窗口内逐日「前一日新增用户数」之和(retention_rate 的分母;旧后端无此字段) retention_cohort?: number; retention_rate: number | null; retention_note: string; }; comparison: { total: number; success: number; success_rate: number; ordered: number; average_duration_ms: number | null; average_saved_cents: number | null; }; // 领券核心数据(2026-07-05 新增;旧后端无此字段,前端 `?.` 探测)。 // 点位=一张券;成功口径 success+already_claimed;点位成功率分母=发起数×应领点位数(未跑到视为失败)。 coupon?: { started: number; all_success: number; // 全部点位领成功的完成场次数 success_rate: number | null; point_success: number; points_per_session: number | null; // 应领点位数(本期完成场点位数众数) point_success_rate: number | null; median_elapsed_ms: number | null; // 仅 completed,同「领券数据」页口径 }; coins: { granted_total: number; reward_video_coin_total: number; feed_ad_coin_total: number; signin_coin_total: number; signin_boost_coin_total: number; task_coin_total: number; coupon_reward_coin_total: number; comparison_reward_coin_total: number; regular_task_coin_total: number; }; cash: { withdraw_success_cents: number }; trend: { date: string; active_users: number; new_users: number; comparisons: number; }[]; }; feedback: { new: number }; cps: { available: boolean; note: string; meituan_order_count: number; meituan_commission_cents: number; meituan_hit_count: number; meituan_miss_count: number; meituan_unknown_rate_count: number; meituan_hit_rate: number | null; jd_order_count?: number; jd_commission_cents?: number; jd_actual_commission_cents?: number; jd_estimated_commission_cents?: number; jd_invalid_count?: number; }; } export interface PriceReport { id: number; user_id: number; comparison_record_id: number | null; store_name: string | null; dish_summary: string | null; original_platform_id: string | null; original_platform_name: string | null; original_price_cents: number | null; reported_platform_id: string; reported_platform_name: string; reported_price_cents: number; images: string[]; status: string; // pending / approved / rejected reject_reason: string | null; reward_coins: number | null; reviewed_at: string | null; created_at: string; // 联表瞬态:phone/nickname 展示完整手机号(点手机号查该用户全部上报); // 其余取自关联比价记录(无关联记录时为 null):trace 调试链接、机型OS版本、提交版本号 phone: string | null; nickname: string | null; trace_id: string | null; trace_url: string | null; device_model: string | null; // 机型,如 PEEM00 rom_name: string | null; // ROM/OS 名,如 ColorOS / MIUI / HarmonyOS android_version: string | null; // Android 版本号,如 13 app_version: string | null; // 提交时我们 app 的 versionName,如 1.2.3 } export interface PriceReportSummary { pending: number; approved: number; rejected: number; total: number; } // ===== CPS 分发与对账 ===== export interface CpsGroup { id: number; sid: string | null; // 仅美团群有(渠道追踪位) name: string; platforms: string[]; // meituan/taobao/jd 多选 member_count: number | null; status: string; // active / archived remark: string | null; created_at: string; } export interface CpsActivity { id: number; platform: string; // meituan / taobao / jd name: string; act_id: string | null; // 美团活动物料 ID product_view_sign: string | null; payload: string | null; // 淘宝整段淘口令 / 京东链接 image_url: string | null; // 淘宝落地页主视觉图(绝对 URL) status: string; remark: string | null; created_at: string; } export interface CpsOrder { id: number; order_id: string; sid: string | null; act_id: string | null; pay_price_cents: number | null; commission_cents: number | null; commission_rate: string | null; // "300"=3% "10"=0.1% mt_status: string | null; // 2付款 3完成 4取消 5风控 6结算 invalid_reason: string | null; product_name: string | null; pay_time: string | null; } export interface CpsReferralLinkItem { activity_id: number; activity_name: string; platform: string; redirect_url: string; // 我们的落地页 /c/{code}(发群用) code: string; } export interface CpsReferralLinks { group_name: string; results: CpsReferralLinkItem[]; } export interface CpsReconcileResult { fetched: number; inserted: number; updated: number; pages: number; } export interface CpsGroupStat { group_id: number | null; sid: string | null; name: string; platforms: string[]; member_count: number | null; click_pv: number; click_uv: number; copy_pv: number; // 淘宝"复制口令"次数 copy_uv: number; // 对账类:淘宝/京东无法对账 → null(前端显示 "-") order_count: number | null; settled_count: number | null; canceled_count: number | null; gmv_cents: number | null; est_commission_cents: number | null; settled_commission_cents: number | null; } export interface CpsStats { groups: CpsGroupStat[]; total_order_count: number; total_est_commission_cents: number; total_settled_commission_cents: number; } // ===== 埋点 / 上报成功率大盘(analytics_selfstat 快照差分聚合)===== // 后端 feat/analytics-success-rate 分支的三个只读端点(/admin/api/analytics-health/*)。 // rate 分母为 0 时后端给 null(前端显示 "-",不是 0%)。 /** 一组区间聚合指标:两大率 + 四原子量。 */ export interface HealthMetrics { attempted: number; // track 被调用次数(埋点段分母) drop_capture: number; // 采集时异常丢弃(队列/序列化失败) delivered: number; // 成功送达后端 drop_undelivered: number; // 已落盘但久未送达被队列淘汰 track_success_rate: number | null; // 埋点成功率 ∈ [0,1]:(attempted − drop_capture) / attempted report_success_rate: number | null; // 上报成功率 ∈ [0,1]:delivered / (delivered + drop_undelivered) } /** 趋势点:某北京天的指标(trend 端点,按北京天升序)。 */ export interface HealthTrendPoint extends HealthMetrics { day: string; // 北京日期 "YYYY-MM-DD" } /** 下钻行:某维度值的指标(breakdown 端点,已按上报率升序,最差在前)。 */ export interface HealthBreakdownRow extends HealthMetrics { key: string; // 维度值(event 名 / app_ver / oem);缺失为 "(unknown)" }