小程序后端增强绑定能力并支持多设备列表

This commit is contained in:
stu2not
2026-04-16 18:20:56 +08:00
parent 0683de528a
commit fb78863ee6
3 changed files with 79 additions and 1 deletions

View File

@@ -252,6 +252,40 @@ class BindingDAO(BaseDAO):
.first()
)
def list_by_user(self, user_id: int, limit: int = 20, cursor: int = None) -> list[Mapping]:
params = {"user_id": user_id, "limit": limit + 1}
where = "db.owner_user_id = :user_id AND db.status = 1"
if cursor is not None:
where += " AND db.id < :cursor"
params["cursor"] = cursor
rows = (
self.db.execute(
text(
f"""
SELECT
db.id,
db.device_id,
db.child_id,
c.child_name,
db.status,
db.bound_at
FROM device_bindings AS db
LEFT JOIN children AS c
ON c.child_id = db.child_id
AND c.status = 1
WHERE {where}
ORDER BY db.id DESC
LIMIT :limit
"""
),
params,
)
.mappings()
.all()
)
return rows
def get_by_device(self, device_id: str, user_id: int) -> Optional[Mapping]:
return (
self.db.execute(

View File

@@ -1,7 +1,7 @@
import logging
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
from pydantic import BaseModel
try:
@@ -45,6 +45,20 @@ class BindingGetResponse(BaseModel):
bound_at: datetime
class BindingListItem(BaseModel):
device_id: str
child_id: int | None
child_name: str | None = None
status: int
bound_at: datetime
class BindingListResponse(BaseModel):
items: list[BindingListItem]
total: int
next_cursor: int | None = None
class BindHistoryItem(BaseModel):
device_id: str
child_id: int | None
@@ -140,6 +154,30 @@ def get_current_binding(
return binding
@router.get("", response_model=BindingListResponse)
def list_bindings(
request: Request,
cursor: int | None = Query(default=None, ge=1),
limit: int = Query(default=20, ge=1, le=100),
current_user_id: int = Depends(get_current_user_id),
db=Depends(get_db_session),
) -> BindingListResponse:
service = BindingService(db)
rows, has_more = service.list_bindings(current_user_id, limit, cursor)
next_cursor = int(rows[-1]["id"]) if has_more and rows else None
items = [
BindingListItem(
device_id=row["device_id"],
child_id=row["child_id"],
child_name=row["child_name"],
status=row["status"],
bound_at=row["bound_at"],
)
for row in rows
]
return BindingListResponse(items=items, total=len(items), next_cursor=next_cursor)
@router.get("/{device_id}", response_model=BindingGetResponse)
def get_binding(
device_id: str,

View File

@@ -31,6 +31,12 @@ class BindingService:
def get_current_binding(self, user_id: int) -> Optional[Mapping]:
return self.dao.get_current_by_user(user_id)
def list_bindings(self, user_id: int, limit: int = 20, cursor: int = None) -> tuple[list, bool]:
rows = self.dao.list_by_user(user_id, limit, cursor)
has_more = len(rows) > limit
rows = rows[:limit]
return rows, has_more
def direct_bind(self, device_id: str, child_id: int | None, user_id: int) -> Mapping:
self.dao.direct_bind(device_id, child_id, user_id)
return {"device_id": device_id, "child_id": child_id}