"""admin 大盘聚合查询(全局 count/sum/DAU/成功率)。全部只读、不改任何数据。 ⚠️ 性能:这些是全表 count/sum,P0 数据量小够用;用户量上来后热点字段(user.created_at / user.last_login_at / comparison_record.status / withdraw_order.status)要加索引,或改增量统计表。 """ from __future__ import annotations from datetime import datetime, timedelta, timezone from sqlalchemy import func, select from sqlalchemy.orm import Session from app.models.comparison import ComparisonRecord from app.models.feedback import Feedback from app.models.user import User from app.models.wallet import CoinTransaction, WithdrawOrder _BEIJING = timezone(timedelta(hours=8)) def _beijing_today_start_utc() -> datetime: """北京时间今天 0 点对应的 UTC 时刻(DAU / 今日新增按北京时区切天)。""" now_bj = datetime.now(_BEIJING) start_bj = now_bj.replace(hour=0, minute=0, second=0, microsecond=0) return start_bj.astimezone(timezone.utc) def dashboard_overview(db: Session) -> dict: today_start = _beijing_today_start_utc() def _count(model, *conds) -> int: stmt = select(func.count(model.id)) if conds: stmt = stmt.where(*conds) return db.execute(stmt).scalar_one() def _sum(col, *conds) -> int: stmt = select(func.coalesce(func.sum(col), 0)) if conds: stmt = stmt.where(*conds) return db.execute(stmt).scalar_one() # ===== 用户 ===== by_status = dict( db.execute(select(User.status, func.count(User.id)).group_by(User.status)).all() ) # ===== 提现状态分布 ===== wd_by_status = dict( db.execute( select(WithdrawOrder.status, func.count(WithdrawOrder.id)).group_by( WithdrawOrder.status ) ).all() ) # ===== 比价 ===== comparison_total = _count(ComparisonRecord) comparison_success = _count(ComparisonRecord, ComparisonRecord.status == "success") success_rate = round(comparison_success / comparison_total, 4) if comparison_total else 0.0 return { "users": { "total": _count(User), "active": by_status.get("active", 0), "disabled": by_status.get("disabled", 0), "deleted": by_status.get("deleted", 0), "new_today": _count(User, User.created_at >= today_start), "dau": _count(User, User.last_login_at >= today_start), }, "coins": { # 累计发放金币(coin_transaction 里所有 amount>0 之和;负数是兑换/扣减不计) "granted_total": _sum(CoinTransaction.amount, CoinTransaction.amount > 0), }, "cash": { "withdraw_success_cents": _sum( WithdrawOrder.amount_cents, WithdrawOrder.status == "success" ), "withdraw_pending_count": wd_by_status.get("pending", 0), "withdraw_success_count": wd_by_status.get("success", 0), "withdraw_failed_count": wd_by_status.get("failed", 0), }, "comparison": { "total": comparison_total, "success": comparison_success, "success_rate": success_rate, }, "feedback": {"new": _count(Feedback, Feedback.status == "new")}, # CPS 收入数据源未接(referral-link 只换链接,转化/佣金未回收)→ 前端显示"待接入"。 "cps": {"available": False, "note": "CPS 转化数据未接入(P2)"}, }