加上登录和角色权限,并用 Vue 控制台区分用户与管理员。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-10 22:43:31 +08:00
parent 78601aae5e
commit 8b55b9cf55
36 changed files with 2947 additions and 1007 deletions
+90
View File
@@ -0,0 +1,90 @@
"""控制台要看的实时快照。今日积分按产出公式预览,不写入流水。"""
from __future__ import annotations
from decimal import Decimal
from sqlalchemy import func, select
from sqlalchemy.orm import Session, selectinload
from app.clock import utcnow
from app.models import ComputeNode, NodeStatus, NodeYield, User, WithdrawalLog, WithdrawalStatus, YieldStatus
from app.money import money, to_decimal
from app.services.withdrawals import available_balance
from app.services.yield_engine import compute_node_yield
def settled_points(session: Session, user_id: int | None = None) -> Decimal:
query = select(NodeYield.points_delta).where(NodeYield.status == YieldStatus.SETTLED)
if user_id is not None:
query = query.where(NodeYield.user_id == user_id)
rows = session.scalars(query).all()
return money(sum((to_decimal(item) for item in rows), Decimal("0")))
def pending_withdrawal_amount(session: Session) -> Decimal:
rows = session.scalars(
select(WithdrawalLog.amount).where(WithdrawalLog.status == WithdrawalStatus.PENDING)
).all()
return money(sum((to_decimal(item) for item in rows), Decimal("0")))
def authorized_amount(session: Session) -> Decimal:
rows = session.scalars(select(ComputeNode.purchase_amount)).all()
return money(sum((to_decimal(item) for item in rows), Decimal("0")))
def node_counts(session: Session) -> tuple[int, int]:
nodes = session.scalar(select(func.count()).select_from(ComputeNode)) or 0
online = session.scalar(
select(func.count()).select_from(ComputeNode).where(ComputeNode.status == NodeStatus.ONLINE)
) or 0
return nodes, online
def live_nodes(session: Session, user_id: int | None = None) -> list[dict]:
query = select(ComputeNode).options(selectinload(ComputeNode.user)).order_by(ComputeNode.id.desc())
if user_id is not None:
query = query.where(ComputeNode.user_id == user_id)
today = utcnow().date()
snapshots = []
for node in session.scalars(query).all():
computed = compute_node_yield(session, node, today)
snapshots.append(
{
"id": node.id,
"sn": node.sn,
"user_id": node.user_id,
"wallet_address": node.user.wallet_address,
"purchase_amount": node.purchase_amount,
"license_months": node.license_months,
"licensed_at": node.licensed_at,
"license_expires_at": node.license_expires_at,
"status": node.status,
"last_heartbeat_at": node.last_heartbeat_at,
"callback_url": node.callback_url,
"online_rate": computed.online_rate,
"today_points": computed.points_delta if computed.eligible else Decimal("0"),
}
)
return snapshots
def user_rows(session: Session) -> list[dict]:
counts = dict(
session.execute(select(ComputeNode.user_id, func.count()).group_by(ComputeNode.user_id)).all()
)
rows = []
for user in session.scalars(select(User).order_by(User.id.desc())).all():
rows.append(
{
"id": user.id,
"wallet_address": user.wallet_address,
"username": user.username,
"role": user.role,
"created_at": user.created_at,
"node_count": int(counts.get(user.id, 0)),
"available_points": available_balance(session, user.id),
}
)
return rows