From ab24c120e1f83662f1d02fa90821e4d2a093f0c3 Mon Sep 17 00:00:00 2001 From: xiaji Date: Sat, 24 Jan 2026 19:48:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=8A=A5=E5=91=8A=E7=B3=BB=E7=BB=9F):=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B1=87=E6=80=BB=E8=AE=B0=E5=BD=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增汇总记录模型、表单、视图和模板,支持在报告中显示昨日汇总记录 --- core/admin.py | 15 ++++++ core/forms.py | 15 ++++++ core/migrations/0006_add_summary.py | 47 +++++++++++++++++ core/models.py | 33 ++++++++++++ core/templates/core/report.html | 32 ++++++++++++ core/templates/core/report_pdf.html | 29 +++++++++++ core/views.py | 78 ++++++++++++++++++++++++++++- 7 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 core/migrations/0006_add_summary.py diff --git a/core/admin.py b/core/admin.py index 6b615da..da9e09b 100644 --- a/core/admin.py +++ b/core/admin.py @@ -6,6 +6,8 @@ from .models import ( Status, PlanType, FamilyMember, + SummaryCategory, + Summary, ReadingRecord, InsightRecord, FamilyTask, @@ -14,6 +16,19 @@ from .models import ( ) +@admin.register(SummaryCategory) +class SummaryCategoryAdmin(admin.ModelAdmin): + list_display = ('name', 'created_at', 'updated_at') + search_fields = ('name',) + + +@admin.register(Summary) +class SummaryAdmin(admin.ModelAdmin): + list_display = ('date', 'category', 'speaker', 'source', 'created_at') + list_filter = ('date', 'category', 'speaker') + search_fields = ('content', 'source') + + @admin.register(FamilyMember) class FamilyMemberAdmin(admin.ModelAdmin): list_display = ('name', 'created_at', 'updated_at') diff --git a/core/forms.py b/core/forms.py index dae4164..66e9639 100644 --- a/core/forms.py +++ b/core/forms.py @@ -4,6 +4,7 @@ from django.utils import timezone from .models import ( ReadingRecord, InsightRecord, + Summary, FamilyTask, TodayPlan, SystemConfig, @@ -35,6 +36,20 @@ class InsightRecordForm(forms.ModelForm): 'file': forms.FileInput(attrs={'class': 'form-control'}), } +class SummaryForm(forms.ModelForm): + """汇总记录表单""" + class Meta: + model = Summary + fields = ['date', 'category', 'speaker', 'content', 'source', 'file'] + widgets = { + 'date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}), + 'category': forms.Select(attrs={'class': 'form-select'}), + 'speaker': forms.Select(attrs={'class': 'form-select'}), + 'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 5, 'placeholder': '请输入汇总内容'}), + 'source': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入来源'}), + 'file': forms.FileInput(attrs={'class': 'form-control'}), + } + class FamilyTaskForm(forms.ModelForm): """家庭事项表单""" class Meta: diff --git a/core/migrations/0006_add_summary.py b/core/migrations/0006_add_summary.py new file mode 100644 index 0000000..dc97c97 --- /dev/null +++ b/core/migrations/0006_add_summary.py @@ -0,0 +1,47 @@ +# Generated by Django 5.1.4 on 2026-01-23 15:06 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0005_add_speaker_fields'), + ] + + operations = [ + migrations.CreateModel( + name='SummaryCategory', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=20, unique=True, verbose_name='名称')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')), + ], + options={ + 'verbose_name': '汇总分类', + 'verbose_name_plural': '汇总分类', + 'ordering': ['name'], + }, + ), + migrations.CreateModel( + name='Summary', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField(default=django.utils.timezone.now, verbose_name='日期')), + ('content', models.TextField(verbose_name='内容')), + ('source', models.CharField(max_length=200, blank=True, null=True, verbose_name='来源')), + ('file', models.FileField(blank=True, null=True, upload_to='summary_files/', verbose_name='上传文件')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')), + ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.summarycategory', verbose_name='分类')), + ('speaker', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.familymember', verbose_name='发言人')), + ], + options={ + 'verbose_name': '汇总记录', + 'verbose_name_plural': '汇总记录', + 'ordering': ['-date', '-created_at'], + }, + ), + ] diff --git a/core/models.py b/core/models.py index f6577b5..914b283 100644 --- a/core/models.py +++ b/core/models.py @@ -159,6 +159,39 @@ class TodayPlan(models.Model): def __str__(self): return f"{self.date} - {self.content[:20]}..." +class SummaryCategory(models.Model): + """汇总分类""" + name = models.CharField(max_length=20, unique=True, verbose_name="名称") + created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") + updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间") + + class Meta: + verbose_name = "汇总分类" + verbose_name_plural = "汇总分类" + ordering = ['name'] + + def __str__(self): + return self.name + +class Summary(models.Model): + """汇总记录表""" + date = models.DateField(default=timezone.now, verbose_name="日期") + category = models.ForeignKey(SummaryCategory, on_delete=models.CASCADE, verbose_name="分类") + speaker = models.ForeignKey(FamilyMember, on_delete=models.CASCADE, verbose_name="发言人") + content = models.TextField(verbose_name="内容") + source = models.CharField(max_length=200, blank=True, null=True, verbose_name="来源") + file = models.FileField(upload_to='summary_files/', blank=True, null=True, verbose_name="上传文件") + created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") + updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间") + + class Meta: + verbose_name = "汇总记录" + verbose_name_plural = "汇总记录" + ordering = ['-date', '-created_at'] + + def __str__(self): + return f"{self.category.name} - {self.date}" + class SystemConfig(models.Model): """系统配置表""" smtp_server = models.CharField(max_length=100, blank=True, null=True, verbose_name="SMTP服务器") diff --git a/core/templates/core/report.html b/core/templates/core/report.html index 7e62d3d..84cbc06 100644 --- a/core/templates/core/report.html +++ b/core/templates/core/report.html @@ -201,4 +201,36 @@ + + +
+
+
昨日汇总记录
+
+
+ {% if yesterday_summary %} +
+ {% for summary in yesterday_summary %} +
+
+
+ {{ summary.category.name }} + {{ summary.speaker.name }} +
+
+

{{ summary.content }}

+ {% if summary.source %} + 来源:{{ summary.source }} + {% endif %} +
+
+
+ {% endfor %} +
+ {% else %} +

昨日没有汇总记录

+ {% endif %} +
+
+ {% endblock %} \ No newline at end of file diff --git a/core/templates/core/report_pdf.html b/core/templates/core/report_pdf.html index 85f9a08..f647486 100644 --- a/core/templates/core/report_pdf.html +++ b/core/templates/core/report_pdf.html @@ -141,6 +141,35 @@ {% endif %} + +
+

昨日汇总记录

+ {% if yesterday_summary %} + + + + + + + + + + + {% for summary in yesterday_summary %} + + + + + + + {% endfor %} + +
分类发言人内容来源
{{ summary.category.name }}{{ summary.speaker.name }}{{ summary.content }}{{ summary.source|default:"-" }}
+ {% else %} +
昨日没有汇总记录
+ {% endif %} +
+

今日计划

diff --git a/core/views.py b/core/views.py index 148e1cb..2c9da08 100644 --- a/core/views.py +++ b/core/views.py @@ -37,14 +37,17 @@ def is_weasyprint_available(): from .models import ( ReadingRecord, InsightRecord, + Summary, FamilyTask, TodayPlan, SystemConfig, - FamilyMember + FamilyMember, + SummaryCategory ) from .forms import ( ReadingRecordForm, InsightRecordForm, + SummaryForm, FamilyTaskForm, TodayPlanForm, SystemConfigForm @@ -304,6 +307,69 @@ def delete_today_insight(request, pk): context = {'insight': insight} return render(request, 'core/delete_insight.html', context) +# 汇总记录视图 +def summaries(request): + """汇总记录""" + logger.info("用户访问汇总记录页面") + today = timezone.now().date() + yesterday = today - timedelta(days=1) + + summary_records = Summary.objects.filter(date=yesterday) + + context = { + 'yesterday': yesterday, + 'summary_records': summary_records, + } + + return render(request, 'core/summaries.html', context) + +# 添加汇总记录 +def add_summary(request): + """添加汇总记录""" + family_members = FamilyMember.objects.all() + categories = SummaryCategory.objects.all() + if request.method == 'POST': + form = SummaryForm(request.POST, request.FILES) + if form.is_valid(): + form.save() + logger.info(f"添加汇总记录: {form.cleaned_data['content'][:20]}...") + return redirect('summaries') + else: + form = SummaryForm() + + context = {'form': form, 'family_members': family_members, 'categories': categories} + return render(request, 'core/add_summary.html', context) + +# 编辑汇总记录 +def edit_summary(request, pk): + """编辑汇总记录""" + summary = get_object_or_404(Summary, pk=pk) + family_members = FamilyMember.objects.all() + categories = SummaryCategory.objects.all() + if request.method == 'POST': + form = SummaryForm(request.POST, request.FILES, instance=summary) + if form.is_valid(): + form.save() + logger.info(f"编辑汇总记录: {form.cleaned_data['content'][:20]}...") + return redirect('summaries') + else: + form = SummaryForm(instance=summary) + + context = {'form': form, 'summary': summary, 'family_members': family_members, 'categories': categories} + return render(request, 'core/edit_summary.html', context) + +# 删除汇总记录 +def delete_summary(request, pk): + """删除汇总记录""" + summary = get_object_or_404(Summary, pk=pk) + if request.method == 'POST': + summary.delete() + logger.info(f"删除汇总记录: {summary.content[:20]}...") + return redirect('summaries') + + context = {'summary': summary} + return render(request, 'core/delete_summary.html', context) + # 家庭事项视图 def family_tasks(request): """家庭事项""" @@ -445,6 +511,7 @@ def generate_report(request): # 获取昨日记录 yesterday_reading = ReadingRecord.objects.filter(date=yesterday) yesterday_insight = InsightRecord.objects.filter(date=yesterday) + yesterday_summary = Summary.objects.filter(date=yesterday) # 获取今日计划 today_plan = TodayPlan.objects.filter(date=today) @@ -478,6 +545,7 @@ def generate_report(request): 'yesterday': yesterday, 'yesterday_reading': yesterday_reading, 'yesterday_insight': yesterday_insight, + 'yesterday_summary': yesterday_summary, 'today_plan': today_plan, 'family_task_stats': family_task_stats, 'historical_dates': historical_dates, @@ -496,6 +564,7 @@ def view_report(request, date): # 获取指定日期的记录 yesterday_reading = ReadingRecord.objects.filter(date=yesterday) yesterday_insight = InsightRecord.objects.filter(date=yesterday) + yesterday_summary = Summary.objects.filter(date=yesterday) today_plan = TodayPlan.objects.filter(date=report_date) # 获取家庭事项统计 @@ -506,6 +575,7 @@ def view_report(request, date): 'yesterday': yesterday, 'yesterday_reading': yesterday_reading, 'yesterday_insight': yesterday_insight, + 'yesterday_summary': yesterday_summary, 'today_plan': today_plan, 'family_task_stats': family_task_stats, } @@ -528,6 +598,7 @@ def generate_pdf_report(request, date): # 获取指定日期的记录 yesterday_reading = ReadingRecord.objects.filter(date=yesterday) yesterday_insight = InsightRecord.objects.filter(date=yesterday) + yesterday_summary = Summary.objects.filter(date=yesterday) today_plan = TodayPlan.objects.filter(date=report_date) # 获取家庭事项统计 @@ -538,6 +609,7 @@ def generate_pdf_report(request, date): 'yesterday': yesterday, 'yesterday_reading': yesterday_reading, 'yesterday_insight': yesterday_insight, + 'yesterday_summary': yesterday_summary, 'today_plan': today_plan, 'family_task_stats': family_task_stats, } @@ -579,6 +651,7 @@ def preview_pdf_report(request, date): # 获取指定日期的记录 yesterday_reading = ReadingRecord.objects.filter(date=yesterday) yesterday_insight = InsightRecord.objects.filter(date=yesterday) + yesterday_summary = Summary.objects.filter(date=yesterday) today_plan = TodayPlan.objects.filter(date=report_date) # 获取家庭事项统计 @@ -589,6 +662,7 @@ def preview_pdf_report(request, date): 'yesterday': yesterday, 'yesterday_reading': yesterday_reading, 'yesterday_insight': yesterday_insight, + 'yesterday_summary': yesterday_summary, 'today_plan': today_plan, 'family_task_stats': family_task_stats, } @@ -641,6 +715,7 @@ def send_email_view(request): yesterday_reading = ReadingRecord.objects.filter(date=yesterday) yesterday_insight = InsightRecord.objects.filter(date=yesterday) + yesterday_summary = Summary.objects.filter(date=yesterday) today_plan = TodayPlan.objects.filter(date=report_date) family_task_stats = FamilyTask.objects.values('type').annotate(count=Count('id')) @@ -649,6 +724,7 @@ def send_email_view(request): 'yesterday': yesterday, 'yesterday_reading': yesterday_reading, 'yesterday_insight': yesterday_insight, + 'yesterday_summary': yesterday_summary, 'today_plan': today_plan, 'family_task_stats': family_task_stats, }