Files
diary-system/backend/diary/views.py
maoshen 00a6aef16b feat: 添加批注功能
后端:
- Comment 模型(支持日记/任务/经验三种内容类型)
- CommentSerializer 和 CommentViewSet
- API: /api/comments/ - 批注 CRUD
- API: /api/comments/by_content/?content_type=diary&object_id=1 - 按内容获取批注
- 日记/任务/经验序列化器嵌套显示批注

前端:
- 批注样式(comments-section, comment-item)
- 添加批注输入框

使用方式:
- 北极星可以在任何日记/任务/经验下添加批注
- 批注会显示在内容下方
- 支持查看历史批注
2026-04-14 11:46:52 +00:00

173 lines
6.5 KiB
Python
Executable File

from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from django.utils import timezone
from .models import DiaryEntry, DailyProgress, Experience, Task, Comment
from .serializers import (
DiaryEntrySerializer, DailyProgressSerializer, ExperienceSerializer,
TaskSerializer, CommentSerializer
)
class DiaryEntryViewSet(viewsets.ModelViewSet):
queryset = DiaryEntry.objects.all()
serializer_class = DiaryEntrySerializer
@action(detail=False, methods=['get'])
def today(self, request):
"""获取今天的日记"""
today = timezone.now().date()
entry, created = DiaryEntry.objects.get_or_create(date=today)
serializer = self.get_serializer(entry)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def recent(self, request):
"""获取最近 7 天的日记"""
entries = DiaryEntry.objects.order_by('-date')[:7]
serializer = self.get_serializer(entries, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def stats(self, request):
"""获取统计信息"""
total_entries = DiaryEntry.objects.count()
total_tasks = Task.objects.count()
total_experiences = Experience.objects.count()
return Response({
'total_entries': total_entries,
'first_entry': DiaryEntry.objects.order_by('date').first().date if total_entries > 0 else None,
'latest_entry': DiaryEntry.objects.order_by('-date').first().date if total_entries > 0 else None,
'total_tasks': total_tasks,
'total_experiences': total_experiences,
})
@action(detail=True, methods=['post'])
def link_task(self, request, pk=None):
"""关联任务到日记"""
entry = self.get_object()
task_id = request.data.get('task_id')
progress_percent = request.data.get('progress_percent')
notes = request.data.get('notes', '')
task = Task.objects.get(id=task_id)
entry.link_task(task, progress_percent, notes)
return Response(DiaryEntrySerializer(entry).data)
@action(detail=True, methods=['post'])
def extract_experience(self, request, pk=None):
"""从日记提炼经验"""
entry = self.get_object()
exp = entry.extract_experience(
title=request.data.get('title'),
category=request.data.get('category'),
problem=request.data.get('problem'),
solution=request.data.get('solution'),
lesson_learned=request.data.get('lesson_learned', '')
)
return Response(ExperienceSerializer(exp).data)
class DailyProgressViewSet(viewsets.ModelViewSet):
queryset = DailyProgress.objects.all()
serializer_class = DailyProgressSerializer
class ExperienceViewSet(viewsets.ModelViewSet):
queryset = Experience.objects.all()
serializer_class = ExperienceSerializer
@action(detail=False, methods=['get'])
def by_category(self, request):
"""按类别分组获取经验"""
categories = {}
for exp in Experience.objects.all():
cat = exp.get_category_display()
if cat not in categories:
categories[cat] = []
categories[cat].append(ExperienceSerializer(exp).data)
return Response(categories)
@action(detail=False, methods=['get'])
def recent(self, request):
"""获取最近 10 条经验"""
experiences = Experience.objects.order_by('-date', '-created_at')[:10]
serializer = self.get_serializer(experiences, many=True)
return Response(serializer.data)
class TaskViewSet(viewsets.ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
@action(detail=False, methods=['get'])
def by_status(self, request):
"""按状态分组获取任务"""
statuses = {}
for task in Task.objects.all():
status = task.get_status_display()
if status not in statuses:
statuses[status] = []
statuses[status].append(TaskSerializer(task).data)
return Response(statuses)
@action(detail=False, methods=['get'])
def active(self, request):
"""获取活跃任务(未完成和未取消)"""
tasks = Task.objects.exclude(status__in=['completed', 'cancelled'])
serializer = self.get_serializer(tasks, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def stats(self, request):
"""获取任务统计"""
total = Task.objects.count()
completed = Task.objects.filter(status='completed').count()
in_progress = Task.objects.filter(status='in_progress').count()
pending = Task.objects.filter(status='pending').count()
blocked = Task.objects.filter(status='blocked').count()
return Response({
'total': total,
'completed': completed,
'in_progress': in_progress,
'pending': pending,
'blocked': blocked,
'completion_rate': round(completed / total * 100, 1) if total > 0 else 0
})
@action(detail=True, methods=['post'])
def update_progress(self, request, pk=None):
"""更新任务进展"""
task = self.get_object()
percent = request.data.get('percent', task.progress_percent)
notes = request.data.get('notes', '')
task.update_progress(int(percent), notes)
return Response(TaskSerializer(task).data)
@action(detail=True, methods=['post'])
def complete(self, request, pk=None):
"""标记任务为完成"""
task = self.get_object()
task.mark_completed()
return Response(TaskSerializer(task).data)
class CommentViewSet(viewsets.ModelViewSet):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
@action(detail=False, methods=['get'])
def by_content(self, request):
"""按内容类型和 ID 获取批注"""
content_type = request.query_params.get('content_type')
object_id = request.query_params.get('object_id')
if content_type and object_id:
comments = Comment.objects.filter(
content_type=content_type,
object_id=object_id
)
serializer = self.get_serializer(comments, many=True)
return Response(serializer.data)
return Response([])