修改页面分页情况

This commit is contained in:
2026-06-15 17:50:47 +08:00
parent 3aa6c7cf2f
commit d71b50c200
12 changed files with 187 additions and 64 deletions
+10 -6
View File
@@ -1,4 +1,4 @@
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
@@ -17,14 +17,18 @@ router = APIRouter(prefix="/credits", tags=["credits"])
@router.get("", response_model=CreditBalanceOut)
async def get_credits(
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
records = await get_records(db, current_user.id)
return CreditBalanceOut(
credits=round(current_user.credits, 2),
records=[CreditRecordOut.model_validate(r) for r in records],
)
records, total = await get_records(db, current_user.id, page, page_size)
from fastapi.responses import JSONResponse
return JSONResponse(content={
"credits": round(current_user.credits, 2),
"records": [CreditRecordOut.model_validate(r) for r in records],
"total": total,
})
@router.get(
+5 -4
View File
@@ -8,7 +8,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.dependencies import get_db, get_current_user
from app.models.user import User
from app.models.notification import Notification
from app.schemas.notification import NotificationOut, UnreadCountOut
from app.schemas.notification import NotificationOut, NotificationListOut, UnreadCountOut
from app.services.auth import decode_access_token
from app.services.notification import (
get_notifications,
@@ -103,15 +103,16 @@ async def notifications_ws(websocket: WebSocket):
_active_connections.pop(user_id, None)
@router.get("", response_model=list[NotificationOut])
@router.get("", response_model=NotificationListOut)
async def list_notifications(
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
is_read: bool = Query(None),
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
items, _ = await get_notifications(db, current_user.id, page, page_size)
return items
items, total = await get_notifications(db, current_user.id, page, page_size, is_read)
return {"items": items, "total": total}
@router.put("/{notification_id}/read")
+11 -2
View File
@@ -290,20 +290,29 @@ async def alipay_callback(request: Request, db: AsyncSession = Depends(get_db)):
@router.get("/orders", response_model=list[PaymentOrderOut])
async def list_orders(
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
# Auto-expire stale pending orders before returning
from app.services.payment import _check_and_expire_order
count_query = select(func.count(PaymentOrder.id)).where(PaymentOrder.user_id == current_user.id)
total = (await db.execute(count_query)).scalar() or 0
result = await db.execute(
select(PaymentOrder)
.where(PaymentOrder.user_id == current_user.id)
.order_by(PaymentOrder.created_at.desc())
.offset((page - 1) * page_size)
.limit(page_size)
)
orders = result.scalars().all()
for o in orders:
await _check_and_expire_order(db, o)
return orders
from fastapi.responses import JSONResponse
return JSONResponse(content={"items": orders, "total": total})
@router.get("/orders/{order_no}", response_model=PaymentOrderOut)
@@ -14,5 +14,10 @@ class NotificationOut(BaseModel):
model_config = {"from_attributes": True}
class NotificationListOut(BaseModel):
items: list[NotificationOut]
total: int
class UnreadCountOut(BaseModel):
count: int
+7 -2
View File
@@ -282,10 +282,15 @@ async def refund_credits(
)
async def get_records(db: AsyncSession, user_id: str) -> list[CreditRecord]:
async def get_records(db: AsyncSession, user_id: str, page: int = 1, page_size: int = 20) -> tuple[list[CreditRecord], int]:
count_query = select(func.count(CreditRecord.id)).where(CreditRecord.user_id == user_id)
total = (await db.execute(count_query)).scalar() or 0
result = await db.execute(
select(CreditRecord)
.where(CreditRecord.user_id == user_id)
.order_by(CreditRecord.created_at.desc())
.offset((page - 1) * page_size)
.limit(page_size)
)
return list(result.scalars().all())
return list(result.scalars().all()), total
+18 -6
View File
@@ -74,16 +74,18 @@ async def create_notification(
async def get_notifications(
db: AsyncSession, user_id: str, page: int = 1, page_size: int = 20
db: AsyncSession, user_id: str, page: int = 1, page_size: int = 20, is_read: bool = None
) -> tuple[list[dict], int]:
"""Get notifications for a user (personal + broadcast), with per-user read state."""
user_is_read_expr = case(
(Notification.user_id.is_(None), NotificationRead.id.is_not(None)),
else_=Notification.is_read,
).label("user_is_read")
query = (
select(
Notification,
case(
(Notification.user_id.is_(None), NotificationRead.id.is_not(None)),
else_=Notification.is_read,
).label("user_is_read"),
user_is_read_expr,
)
.outerjoin(
NotificationRead,
@@ -96,11 +98,15 @@ async def get_notifications(
Notification.user_id.is_(None),
)
)
.order_by(Notification.created_at.desc())
)
count_query = (
select(func.count(Notification.id))
.outerjoin(
NotificationRead,
(Notification.id == NotificationRead.notification_id)
& (NotificationRead.user_id == user_id),
)
.where(
or_(
Notification.user_id == user_id,
@@ -109,6 +115,12 @@ async def get_notifications(
)
)
if is_read is not None:
query = query.where(user_is_read_expr == is_read)
count_query = count_query.where(user_is_read_expr == is_read)
query = query.order_by(Notification.created_at.desc())
total = (await db.execute(count_query)).scalar() or 0
result = await db.execute(query.offset((page - 1) * page_size).limit(page_size))
rows = result.all()