feat: add support for pagination responses

also fix check-in error messages not displaying
This commit is contained in:
2026-01-06 21:30:19 +08:00
parent 63b4935fce
commit 2626477b0d
7 changed files with 142 additions and 41 deletions
+25 -9
View File
@@ -7,6 +7,7 @@ from backend.schemas.check_in import (
ManualCheckInRequest,
CheckInRecordResponse,
CheckInResultResponse,
PaginatedResponse,
)
from backend.services.check_in_service import CheckInService
from backend.services.task_service import TaskService
@@ -91,7 +92,7 @@ async def get_check_in_record_status(
}
@router.get("/task/{task_id}/records", response_model=List[CheckInRecordResponse], summary="查看任务的打卡记录")
@router.get("/task/{task_id}/records", response_model=PaginatedResponse[CheckInRecordResponse], summary="查看任务的打卡记录")
async def get_task_check_in_records(
task_id: int,
skip: int = Query(0, ge=0, description="跳过记录数"),
@@ -120,10 +121,15 @@ async def get_task_check_in_records(
)
try:
records = CheckInService.get_task_records(
records, total = CheckInService.get_task_records(
task_id, db, skip, limit, status_filter, trigger_type
)
return records
return PaginatedResponse(
records=records,
total=total,
skip=skip,
limit=limit
)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
@@ -131,7 +137,7 @@ async def get_task_check_in_records(
)
@router.get("/my-records", response_model=List[CheckInRecordResponse], summary="查看当前用户的所有打卡记录")
@router.get("/my-records", response_model=PaginatedResponse[CheckInRecordResponse], summary="查看当前用户的所有打卡记录")
async def get_my_check_in_records(
skip: int = Query(0, ge=0, description="跳过记录数"),
limit: int = Query(100, ge=1, le=500, description="限制记录数"),
@@ -149,10 +155,15 @@ async def get_my_check_in_records(
- **trigger_type**: 过滤触发类型 (scheduler/manual)
"""
try:
records = CheckInService.get_user_records(
records, total = CheckInService.get_user_records(
current_user.id, db, skip, limit, status_filter, trigger_type
)
return records
return PaginatedResponse(
records=records,
total=total,
skip=skip,
limit=limit
)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
@@ -161,7 +172,7 @@ async def get_my_check_in_records(
@router.get("/records", response_model=List[CheckInRecordResponse], summary="查看所有打卡记录(管理员)")
@router.get("/records", response_model=PaginatedResponse[CheckInRecordResponse], summary="查看所有打卡记录(管理员)")
async def get_all_check_in_records(
skip: int = Query(0, ge=0, description="跳过记录数"),
limit: int = Query(100, ge=1, le=500, description="限制记录数"),
@@ -179,10 +190,15 @@ async def get_all_check_in_records(
- **status**: 过滤指定状态的记录
"""
try:
records = CheckInService.get_all_records(db, skip, limit, task_id, status_filter)
records, total = CheckInService.get_all_records(db, skip, limit, task_id, status_filter)
# 为每条记录添加用户和任务信息
enriched_records = [CheckInService.enrich_record_with_user_task_info(record, db) for record in records]
return enriched_records
return PaginatedResponse(
records=enriched_records,
total=total,
skip=skip,
limit=limit
)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+11 -1
View File
@@ -1,7 +1,9 @@
from datetime import datetime
from typing import Optional
from typing import Optional, List, Generic, TypeVar
from pydantic import BaseModel, Field, ConfigDict
T = TypeVar('T')
class ManualCheckInRequest(BaseModel):
"""手动打卡请求 Schema(已废弃,现在使用路径参数 task_id)"""
@@ -46,3 +48,11 @@ class CheckInResultResponse(BaseModel):
message: str
record_id: Optional[int] = None
error: Optional[str] = None
class PaginatedResponse(BaseModel, Generic[T]):
"""分页响应 Schema"""
records: List[T] = Field(..., description="记录列表")
total: int = Field(..., description="总记录数")
skip: int = Field(..., description="跳过的记录数")
limit: int = Field(..., description="每页记录数")
+27 -9
View File
@@ -432,7 +432,7 @@ class CheckInService:
limit: int = 100,
status: Optional[str] = None,
trigger_type: Optional[str] = None
) -> List[CheckInRecord]:
) -> tuple[List[CheckInRecord], int]:
"""
获取任务的打卡记录
@@ -445,7 +445,7 @@ class CheckInService:
trigger_type: 过滤触发类型 (scheduler/manual)
Returns:
打卡记录列表
(打卡记录列表, 总记录数)
"""
query = db.query(CheckInRecord).filter(CheckInRecord.task_id == task_id)
@@ -455,10 +455,16 @@ class CheckInService:
if trigger_type:
query = query.filter(CheckInRecord.trigger_type == trigger_type)
return query.order_by(
# 获取总数
total = query.count()
# 获取分页数据
records = query.order_by(
CheckInRecord.check_in_time.desc()
).offset(skip).limit(limit).all()
return records, total
@staticmethod
def get_user_records(
user_id: int,
@@ -467,7 +473,7 @@ class CheckInService:
limit: int = 100,
status: Optional[str] = None,
trigger_type: Optional[str] = None
) -> List[CheckInRecord]:
) -> tuple[List[CheckInRecord], int]:
"""
获取用户的所有打卡记录
@@ -480,7 +486,7 @@ class CheckInService:
trigger_type: 过滤触发类型 (scheduler/manual)
Returns:
打卡记录列表
(打卡记录列表, 总记录数)
"""
# 获取用户的所有任务ID
user_task_ids = db.query(CheckInTask.id).filter(CheckInTask.user_id == user_id).all()
@@ -495,10 +501,16 @@ class CheckInService:
if trigger_type:
query = query.filter(CheckInRecord.trigger_type == trigger_type)
return query.order_by(
# 获取总数
total = query.count()
# 获取分页数据
records = query.order_by(
CheckInRecord.check_in_time.desc()
).offset(skip).limit(limit).all()
return records, total
@staticmethod
def get_all_records(
db: Session,
@@ -506,7 +518,7 @@ class CheckInService:
limit: int = 100,
task_id: Optional[int] = None,
status: Optional[str] = None
) -> List[CheckInRecord]:
) -> tuple[List[CheckInRecord], int]:
"""
获取所有打卡记录(管理员)- 使用联表查询优化性能
@@ -518,7 +530,7 @@ class CheckInService:
status: 过滤状态
Returns:
打卡记录列表
(打卡记录列表, 总记录数)
"""
from sqlalchemy.orm import joinedload
@@ -533,10 +545,16 @@ class CheckInService:
if status:
query = query.filter(CheckInRecord.status == status)
return query.order_by(
# 获取总数
total = query.count()
# 获取分页数据
records = query.order_by(
CheckInRecord.check_in_time.desc()
).offset(skip).limit(limit).all()
return records, total
@staticmethod
def enrich_record_with_user_task_info(record: CheckInRecord, db: Session) -> dict:
"""