""" 故事模块视图 - App端 """ from django.db.models import Count from rest_framework import viewsets from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from drf_spectacular.utils import extend_schema from utils.response import success, error from utils.exceptions import ErrorCode from apps.admins.authentication import AppJWTAuthentication from .models import StoryShelf, Story from .serializers import ( StoryShelfSerializer, CreateShelfSerializer, StoryListSerializer, GenerateStorySerializer, ) @extend_schema(tags=['故事']) class StoryViewSet(viewsets.ViewSet): """故事视图集(App端)""" authentication_classes = [AppJWTAuthentication] permission_classes = [IsAuthenticated] def list(self, request): """ 获取故事列表 GET /api/v1/stories/?shelf_id=1&page=1&page_size=20 """ queryset = Story.objects.filter(user=request.user) shelf_id = request.query_params.get('shelf_id') if shelf_id: queryset = queryset.filter(shelf_id=shelf_id) # 分页 page = int(request.query_params.get('page', 1)) page_size = int(request.query_params.get('page_size', 20)) start = (page - 1) * page_size total = queryset.count() items = queryset[start:start + page_size] return success(data={ 'total': total, 'items': StoryListSerializer(items, many=True).data, }) def destroy(self, request, pk=None): """ 删除故事 DELETE /api/v1/stories/{id}/ """ try: story = Story.objects.get(id=pk, user=request.user) except Story.DoesNotExist: return error(code=ErrorCode.STORY_NOT_FOUND, message='故事不存在') story.delete() return success(message='删除成功') @action(detail=False, methods=['post'], url_path='generate') def generate(self, request): """ 生成故事 (SSE 流式 - 占位) POST /api/v1/stories/generate/ """ serializer = GenerateStorySerializer(data=request.data) if not serializer.is_valid(): return error(message=str(serializer.errors)) # TODO: 接入 LLM API 实现 SSE 流式生成 shelf_id = serializer.validated_data.get('shelf_id') shelf = None if shelf_id: try: shelf = StoryShelf.objects.get(id=shelf_id, user=request.user) except StoryShelf.DoesNotExist: return error(code=ErrorCode.SHELF_NOT_FOUND, message='书架不存在') story = Story.objects.create( user=request.user, shelf=shelf, title='生成中...', content='', generation_mode=serializer.validated_data.get('mode', 'random'), prompt=serializer.validated_data.get('prompt', ''), ) return success(data={ 'id': story.id, 'message': '故事生成功能待接入 LLM API', }) @extend_schema(tags=['故事']) class ShelfViewSet(viewsets.ViewSet): """书架视图集(App端)""" authentication_classes = [AppJWTAuthentication] permission_classes = [IsAuthenticated] def list(self, request): """ 书架列表 GET /api/v1/stories/shelves/ """ shelves = StoryShelf.objects.filter( user=request.user ).annotate(story_count=Count('stories')) return success(data=StoryShelfSerializer(shelves, many=True).data) def create(self, request): """ 创建书架 POST /api/v1/stories/shelves/ """ serializer = CreateShelfSerializer(data=request.data) if not serializer.is_valid(): return error(message=str(serializer.errors)) shelf = StoryShelf.objects.create( user=request.user, name=serializer.validated_data['name'], ) return success(data=StoryShelfSerializer(shelf).data, message='创建成功') def destroy(self, request, pk=None): """ 删除书架(故事保留,shelf_id 置 null) DELETE /api/v1/stories/shelves/{id}/ """ try: shelf = StoryShelf.objects.get(id=pk, user=request.user) except StoryShelf.DoesNotExist: return error(code=ErrorCode.SHELF_NOT_FOUND, message='书架不存在') Story.objects.filter(shelf=shelf).update(shelf=None) shelf.delete() return success(message='删除成功')