36d00a9d68
Co-authored-by: zzhyyyyy <2685922758@qq.com> Reviewed-on: #13 Co-authored-by: zhuzihao <zhuzihao@wonderable.ai> Co-committed-by: zhuzihao <zhuzihao@wonderable.ai>
500 lines
14 KiB
TypeScript
500 lines
14 KiB
TypeScript
// 与后端 app/admin/schemas/* 对齐的类型定义。
|
|
|
|
export interface AdminInfo {
|
|
id: number;
|
|
username: string;
|
|
role: string; // super_admin / finance / operator
|
|
status: string;
|
|
created_at: string;
|
|
last_login_at: string | null;
|
|
}
|
|
|
|
export interface LoginResponse {
|
|
access_token: string;
|
|
token_type: string;
|
|
expires_in: number;
|
|
admin: AdminInfo;
|
|
}
|
|
|
|
export interface CursorPage<T> {
|
|
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;
|
|
}
|
|
|
|
// 设备维度新手引导:一台设备(ANDROID_ID)聚合,走过引导的账号数 + 最近完成时间。
|
|
export interface DeviceOnboardingItem {
|
|
device_id: string;
|
|
account_count: number;
|
|
last_completed_at: string;
|
|
}
|
|
|
|
export interface UserOverview {
|
|
user: UserListItem;
|
|
coin_balance: number;
|
|
cash_balance_cents: number;
|
|
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;
|
|
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;
|
|
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;
|
|
}
|
|
|
|
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;
|
|
images: string[] | null;
|
|
status: string; // new / handled
|
|
created_at: string;
|
|
}
|
|
|
|
// 反馈页「加群二维码」卡配置(运营后台改 → 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<string, unknown> | 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;
|
|
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;
|
|
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<string, unknown>[];
|
|
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<string, unknown> | 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;
|
|
}
|
|
|
|
// 广告收益报表:按日期汇总的一天(按天趋势图用;全量,不受 limit 影响)
|
|
export interface AdRevenueDaily {
|
|
date: string; // 北京时间 YYYY-MM-DD
|
|
impressions: number;
|
|
revenue_yuan: number;
|
|
expected_coin: number;
|
|
actual_coin: number;
|
|
}
|
|
|
|
// 广告收益报表:按 日期 × 用户 × 广告类型 × 应用 × 代码位 聚合
|
|
export interface AdRevenueRow {
|
|
report_date: string; // 该组所属日期 北京时间 YYYY-MM-DD
|
|
user_id: number;
|
|
ad_type: string; // reward_video / feed / draw
|
|
app_env: string | null; // prod(傻瓜比价) / test(测试);旧数据为空
|
|
our_code_id: string | null; // 我们配置的代码位 104xxx;旧数据为空
|
|
hour: number | null; // 北京时间小时 0–23(按小时粒度时有值;按天为 null)
|
|
impressions: number; // 展示条数(轮播每条各计一次)
|
|
revenue_yuan: number; // 收益(元),预估口径
|
|
expected_coin: number; // 应发金币(公式复算,与金币审计同源)
|
|
actual_coin: number; // 实发金币(实际入账)
|
|
matched: boolean; // 该组应发==实发
|
|
adns: string[]; // 底层填充 ADN 子渠道集合
|
|
impression_records: AdRevenueImpression[]; // 该组逐条展示明细(展开下钻)
|
|
records: AdRevenueRecord[]; // 该组逐条发奖复算明细(展开下钻)
|
|
}
|
|
|
|
export interface AdRevenueReport {
|
|
date_from: string; // 起始日 北京时间 YYYY-MM-DD
|
|
date_to: string; // 结束日 北京时间 YYYY-MM-DD(闭区间;单日时与 date_from 相同)
|
|
daily: AdRevenueDaily[]; // 按日期汇总序列(全量,供按天趋势图)
|
|
total: number; // 聚合组总数(全量,不受 limit 影响)
|
|
truncated: boolean;
|
|
total_impressions: number;
|
|
total_revenue_yuan: number;
|
|
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: { 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 };
|
|
feedback: { new: number };
|
|
cps: { available: boolean; note: string };
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|