f868414966
- 新增反馈审核字段和迁移,支持 pending/adopted/rejected、未采纳原因和采纳金币 - 增加用户端反馈历史 records 接口和 admin 采纳/拒绝接口 - 采纳时同事务写状态、金币流水和审计日志,拦截重复审核 - 验证:pytest tests/test_feedback.py tests/test_admin_write.py tests/test_admin_read.py --------- Co-authored-by: lowmaster-chen <1119780489@qq.com> Reviewed-on: #66 Co-authored-by: chenshuobo <chenshuobo@wonderable.ai> Co-committed-by: chenshuobo <chenshuobo@wonderable.ai>
126 lines
4.9 KiB
Python
126 lines
4.9 KiB
Python
"""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.ad_feed_reward import AdFeedRewardRecord
|
|
from app.models.ad_reward import AdRewardRecord
|
|
from app.models.comparison import ComparisonRecord
|
|
from app.models.feedback import Feedback
|
|
from app.models.signin import SigninBoostRecord, SigninRecord
|
|
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),
|
|
"reward_video_coin_total": _sum(
|
|
CoinTransaction.amount,
|
|
CoinTransaction.amount > 0,
|
|
CoinTransaction.biz_type.in_(("reward_video", "ad_reward")),
|
|
),
|
|
"reward_video_watch_count": _count(
|
|
AdRewardRecord,
|
|
AdRewardRecord.reward_scene == "reward_video",
|
|
AdRewardRecord.status == "granted",
|
|
),
|
|
"feed_ad_coin_total": _sum(
|
|
CoinTransaction.amount,
|
|
CoinTransaction.amount > 0,
|
|
CoinTransaction.biz_type == "feed_ad_reward",
|
|
),
|
|
"feed_ad_watch_count": _count(
|
|
AdFeedRewardRecord,
|
|
AdFeedRewardRecord.status == "granted",
|
|
),
|
|
"signin_coin_total": _sum(
|
|
CoinTransaction.amount,
|
|
CoinTransaction.amount > 0,
|
|
CoinTransaction.biz_type == "signin",
|
|
),
|
|
"signin_count": _count(SigninRecord),
|
|
"signin_boost_coin_total": _sum(
|
|
CoinTransaction.amount,
|
|
CoinTransaction.amount > 0,
|
|
CoinTransaction.biz_type == "signin_boost",
|
|
),
|
|
"signin_boost_watch_count": _count(SigninBoostRecord),
|
|
},
|
|
"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.in_(("pending", "new")))},
|
|
# CPS 收入数据源未接(referral-link 只换链接,转化/佣金未回收)→ 前端显示"待接入"。
|
|
"cps": {"available": False, "note": "CPS 转化数据未接入(P2)"},
|
|
}
|