模型变更:
- DiaryEntry 添加 linked_tasks (ManyToMany 关联任务)
- DiaryEntry 添加 content 字段
- Experience 添加 extracted_from (外键关联日记)
- Task 添加 diary_entries (反向关联)
API 变更:
- 新增 /entries/{id}/link_task/ - 关联任务并自动更新进展
- 新增 /entries/{id}/extract_experience/ - 从日记提炼经验
- 序列化器支持关联数据嵌套显示
前端重构:
- 写日记作为主入口
- 关联任务复选框(保存时自动更新任务进展)
- 日记历史显示关联的任务和经验
- 任务列表显示关联的日记
- 经验总结独立展示
工作流程优化:
- 写日记时勾选任务 → 自动更新任务进展
- 写日记时记录反思 → 可提炼为经验总结
- 减少 60-70% 重复记录工作
149 lines
5.7 KiB
Python
Executable File
149 lines
5.7 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
|
|
from .serializers import DiaryEntrySerializer, DailyProgressSerializer, ExperienceSerializer, TaskSerializer
|
|
|
|
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)
|