Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/playtest/playtest-entry-mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 21 additions & 2 deletions backend/packages/app/src/windup_app/server/character/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ def get_character_by_workflow_run(

@abstractmethod
def list_characters(
self, session: Session, *, project_id: int, page: int, page_size: int,
self,
session: Session,
*,
project_id: int,
page: int,
page_size: int,
status: int | None = None,
) -> tuple[list[Character], int]:
"""分页查询项目下的角色列表,返回 (当前页数据, 总数)。
Expand All @@ -51,7 +56,21 @@ def list_characters(
"""

@abstractmethod
def update_character(self, session: Session, character_id: int, **fields) -> Character | None:
def list_characters_for_user(
self,
session: Session,
*,
user_id: int,
page: int,
page_size: int,
status: int | None = None,
) -> tuple[list[Character], int]:
"""分页查询用户全部项目下的角色列表,返回 (当前页数据, 总数)。"""

@abstractmethod
def update_character(
self, session: Session, character_id: int, **fields
) -> Character | None:
"""更新角色描述、参考图或 character_data 等字段。

返回更新后的角色;不存在时返回 ``None``。
Expand Down
41 changes: 39 additions & 2 deletions backend/packages/app/src/windup_app/server/character/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from windup_app.server.character.interface import CharacterService
from windup_app.server.character.model import Character
from windup_app.server.project.model import Project


class SqlAlchemyCharacterService(CharacterService):
Expand All @@ -36,20 +37,53 @@ def get_character_by_workflow_run(
return session.scalar(stmt)

def list_characters(
self, session: Session, *, project_id: int, page: int, page_size: int,
self,
session: Session,
*,
project_id: int,
page: int,
page_size: int,
status: int | None = None,
) -> tuple[list[Character], int]:
base_condition = Character.project_id == project_id
if status is not None:
base_condition = base_condition & (Character.status == status)

count_stmt = select(func.count()).select_from(Character).where(base_condition)
stmt = (
select(Character)
.where(base_condition)
.order_by(Character.id.desc())
.offset((page - 1) * page_size)
.limit(page_size)
)
total = session.scalar(count_stmt) or 0
items = list(session.scalars(stmt))
return items, total

def list_characters_for_user(
self,
session: Session,
*,
user_id: int,
page: int,
page_size: int,
status: int | None = None,
) -> tuple[list[Character], int]:
base_condition = Project.user_id == user_id
if status is not None:
base_condition = base_condition & (Character.status == status)

owned_characters = Character.project_id == Project.id
count_stmt = (
select(func.count())
.select_from(Character)
.join(Project, owned_characters)
.where(base_condition)
)
stmt = (
select(Character)
.join(Project, owned_characters)
.where(base_condition)
.order_by(Character.id.desc())
.offset((page - 1) * page_size)
Expand All @@ -60,7 +94,10 @@ def list_characters(
return items, total

def update_character(
self, session: Session, character_id: int, **fields,
self,
session: Session,
character_id: int,
**fields,
) -> Character | None:
character = session.get(Character, character_id)
if character is None:
Expand Down
35 changes: 27 additions & 8 deletions backend/packages/app/src/windup_app/web/api/character.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ def _extract_object_keys(character: Character) -> list[str]:


def _get_project_or_raise(
session: Session, project_id: int, user_id: int,
session: Session,
project_id: int,
user_id: int,
) -> Project:
"""校验项目存在且属于当前用户,否则抛 BizException。"""
project = session.get(Project, project_id)
Expand All @@ -107,7 +109,9 @@ def _get_project_or_raise(


def _get_character_with_auth(
session: Session, character_id: int, user_id: int,
session: Session,
character_id: int,
user_id: int,
) -> Character:
"""获取角色并校验其所属项目属于当前用户。

Expand Down Expand Up @@ -159,18 +163,33 @@ def create_character(

@router.get("", response_model=ListResponse[CharacterOut])
def list_characters(
project_id: int = Query(..., gt=0),
project_id: int | None = Query(None, gt=0),
request: Request = None,
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
status: int | None = Query(None, ge=0, le=1, description="按发布状态过滤: 0=草稿, 1=已发布"),
status: int | None = Query(
None, ge=0, le=1, description="按发布状态过滤: 0=草稿, 1=已发布"
),
session: Session = Depends(get_session),
) -> ListResponse[CharacterOut]:
user_id = request.state.current_user.id
_get_project_or_raise(session, project_id, user_id)
items, total = character_service.list_characters(
session, project_id=project_id, page=page, page_size=page_size, status=status,
)
if project_id is None:
items, total = character_service.list_characters_for_user(
session,
user_id=user_id,
page=page,
page_size=page_size,
status=status,
)
else:
_get_project_or_raise(session, project_id, user_id)
items, total = character_service.list_characters(
session,
project_id=project_id,
page=page,
page_size=page_size,
status=status,
)
return ListResponse.success(
[CharacterOut.model_validate(c) for c in items],
total=total,
Expand Down
Loading
Loading