from django.db.models import Q from rest_framework.views import APIView from rest_framework.permissions import IsAuthenticated from rest_framework import status from drf_yasg.utils import swagger_auto_schema from drf_yasg import openapi from learn.models import ChapterRead from article.models import Article from learn.models import CourseFavorite from utils.response_codes import create_standardized_response, create_standardized_error_response success_response = openapi.Response('成功', examples={'application/json': {'code': 10000, 'message': 'success'}}) unauthorized_response = openapi.Response('未授权', examples={'application/json': {'code': 40101, 'message': '未登录'}}) class UserActivityView(APIView): permission_classes = [IsAuthenticated] @swagger_auto_schema( tags=['用户'], operation_summary='获取用户活动时间线', operation_description='聚合用户的各种活动(发表文章、收藏、学习进度等),按时间倒序返回', manual_parameters=[ openapi.Parameter('page', openapi.IN_QUERY, description='页码', type=openapi.TYPE_INTEGER, default=1), openapi.Parameter('page_size', openapi.IN_QUERY, description='每页数量', type=openapi.TYPE_INTEGER, default=20), ], responses={200: success_response, 401: unauthorized_response}, ) def get(self, request): user = request.user page = int(request.query_params.get('page', 1)) page_size = int(request.query_params.get('page_size', 20)) activities = [] # 文章活动 articles = Article.objects.filter(author=user, status='published').order_by('-created_at')[:50] for article in articles: activities.append({ 'id': f'article_{article.id}', 'type': 'article', 'title': '发表文章', 'description': f'发布了《{article.title}》', 'target_id': article.id, 'target_type': 'article', 'created_at': article.created_at.strftime('%Y-%m-%d %H:%M:%S'), 'timestamp': int(article.created_at.timestamp()), }) # 收藏活动 favorites = CourseFavorite.objects.filter(user=user).select_related('course').order_by('-created_at')[:50] for fav in favorites: activities.append({ 'id': f'favorite_{fav.id}', 'type': 'favorite', 'title': '收藏课程', 'description': f'收藏了《{fav.course.title}》', 'target_id': fav.course.id, 'target_type': 'course', 'created_at': fav.created_at.strftime('%Y-%m-%d %H:%M:%S'), 'timestamp': int(fav.created_at.timestamp()), }) # 学习进度 reads = ChapterRead.objects.filter(user=user, completed=True).select_related('chapter', 'course').order_by('-completed_at')[:50] for read in reads: activities.append({ 'id': f'study_{read.id}', 'type': 'study', 'title': '完成学习', 'description': f'完成了《{read.course.title}》- {read.chapter.title}', 'target_id': read.chapter.id, 'target_type': 'chapter', 'created_at': read.completed_at.strftime('%Y-%m-%d %H:%M:%S') if read.completed_at else '', 'timestamp': int(read.completed_at.timestamp()) if read.completed_at else 0, }) # 按时间戳倒序排序 activities.sort(key=lambda x: x['timestamp'], reverse=True) # 分页 total = len(activities) start = (page - 1) * page_size end = start + page_size paginated = activities[start:end] return create_standardized_response( data={ 'activities': paginated, 'total': total, 'page': page, 'page_size': page_size, 'has_more': end < total, } )