新增前后端AI聊天模块,包括流式对话、配置管理和UI组件优化。
This commit is contained in:
137
backend/app/routers/outlines.py
Normal file
137
backend/app/routers/outlines.py
Normal file
@@ -0,0 +1,137 @@
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlmodel import Session, select, func
|
||||
|
||||
from ..database import get_session
|
||||
from ..models import Novel, Outline
|
||||
from ..schemas import (
|
||||
OutlineCreate,
|
||||
OutlineUpdate,
|
||||
OutlineRead,
|
||||
OutlineList,
|
||||
OutlineReorder,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/api/novels/{novel_id}/outlines", tags=["outlines"])
|
||||
|
||||
|
||||
def _get_novel_or_404(novel_id: int, session: Session) -> Novel:
|
||||
novel = session.get(Novel, novel_id)
|
||||
if not novel:
|
||||
raise HTTPException(status_code=404, detail="小说不存在")
|
||||
return novel
|
||||
|
||||
|
||||
def _get_outline_or_404(
|
||||
outline_id: int, novel_id: int, session: Session
|
||||
) -> Outline:
|
||||
outline = session.get(Outline, outline_id)
|
||||
if not outline or outline.novel_id != novel_id:
|
||||
raise HTTPException(status_code=404, detail="大纲不存在")
|
||||
return outline
|
||||
|
||||
|
||||
@router.get("", response_model=OutlineList)
|
||||
def list_outlines(
|
||||
novel_id: int,
|
||||
session: Session = Depends(get_session),
|
||||
):
|
||||
_get_novel_or_404(novel_id, session)
|
||||
total = session.exec(
|
||||
select(func.count(Outline.id)).where(Outline.novel_id == novel_id)
|
||||
).one()
|
||||
items = session.exec(
|
||||
select(Outline)
|
||||
.where(Outline.novel_id == novel_id)
|
||||
.order_by(Outline.sort_order)
|
||||
).all()
|
||||
return OutlineList(
|
||||
items=[OutlineRead.model_validate(o, from_attributes=True) for o in items],
|
||||
total=total,
|
||||
)
|
||||
|
||||
|
||||
@router.post("", response_model=OutlineRead, status_code=201)
|
||||
def create_outline(
|
||||
novel_id: int,
|
||||
data: OutlineCreate,
|
||||
session: Session = Depends(get_session),
|
||||
):
|
||||
_get_novel_or_404(novel_id, session)
|
||||
# 自动设置 sort_order 为当前最大值 + 1
|
||||
max_order = session.exec(
|
||||
select(func.max(Outline.sort_order)).where(Outline.novel_id == novel_id)
|
||||
).one()
|
||||
next_order = (max_order or 0) + 1
|
||||
|
||||
outline = Outline(novel_id=novel_id, sort_order=next_order, **data.model_dump())
|
||||
session.add(outline)
|
||||
session.commit()
|
||||
session.refresh(outline)
|
||||
return outline
|
||||
|
||||
|
||||
@router.put("/reorder", response_model=OutlineList)
|
||||
def reorder_outlines(
|
||||
novel_id: int,
|
||||
data: OutlineReorder,
|
||||
session: Session = Depends(get_session),
|
||||
):
|
||||
_get_novel_or_404(novel_id, session)
|
||||
now = datetime.now(timezone.utc)
|
||||
for idx, oid in enumerate(data.ordered_ids):
|
||||
outline = _get_outline_or_404(oid, novel_id, session)
|
||||
outline.sort_order = idx + 1
|
||||
outline.updated_at = now
|
||||
session.add(outline)
|
||||
session.commit()
|
||||
|
||||
items = session.exec(
|
||||
select(Outline)
|
||||
.where(Outline.novel_id == novel_id)
|
||||
.order_by(Outline.sort_order)
|
||||
).all()
|
||||
total = len(items)
|
||||
return OutlineList(
|
||||
items=[OutlineRead.model_validate(o, from_attributes=True) for o in items],
|
||||
total=total,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{outline_id}", response_model=OutlineRead)
|
||||
def get_outline(
|
||||
novel_id: int,
|
||||
outline_id: int,
|
||||
session: Session = Depends(get_session),
|
||||
):
|
||||
return _get_outline_or_404(outline_id, novel_id, session)
|
||||
|
||||
|
||||
@router.patch("/{outline_id}", response_model=OutlineRead)
|
||||
def update_outline(
|
||||
novel_id: int,
|
||||
outline_id: int,
|
||||
data: OutlineUpdate,
|
||||
session: Session = Depends(get_session),
|
||||
):
|
||||
outline = _get_outline_or_404(outline_id, novel_id, session)
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
for key, value in update_data.items():
|
||||
setattr(outline, key, value)
|
||||
outline.updated_at = datetime.now(timezone.utc)
|
||||
session.add(outline)
|
||||
session.commit()
|
||||
session.refresh(outline)
|
||||
return outline
|
||||
|
||||
|
||||
@router.delete("/{outline_id}", status_code=204)
|
||||
def delete_outline(
|
||||
novel_id: int,
|
||||
outline_id: int,
|
||||
session: Session = Depends(get_session),
|
||||
):
|
||||
outline = _get_outline_or_404(outline_id, novel_id, session)
|
||||
session.delete(outline)
|
||||
session.commit()
|
||||
Reference in New Issue
Block a user