feat(报告系统): 添加汇总记录功能
新增汇总记录模型、表单、视图和模板,支持在报告中显示昨日汇总记录
This commit is contained in:
@@ -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')
|
||||
|
||||
@@ -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:
|
||||
|
||||
47
core/migrations/0006_add_summary.py
Normal file
47
core/migrations/0006_add_summary.py
Normal file
@@ -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'],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -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服务器")
|
||||
|
||||
@@ -201,4 +201,36 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 昨日汇总记录 -->
|
||||
<div class="card">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="card-title mb-0">昨日汇总记录</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if yesterday_summary %}
|
||||
<div class="row">
|
||||
{% for summary in yesterday_summary %}
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><span class="badge bg-primary">{{ summary.category.name }}</span></span>
|
||||
<small class="text-muted">{{ summary.speaker.name }}</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">{{ summary.content }}</p>
|
||||
{% if summary.source %}
|
||||
<small class="text-muted">来源:{{ summary.source }}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-muted">昨日没有汇总记录</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -141,6 +141,35 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- 昨日汇总记录 -->
|
||||
<div class="section">
|
||||
<h2>昨日汇总记录</h2>
|
||||
{% if yesterday_summary %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>分类</th>
|
||||
<th>发言人</th>
|
||||
<th>内容</th>
|
||||
<th>来源</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for summary in yesterday_summary %}
|
||||
<tr>
|
||||
<td>{{ summary.category.name }}</td>
|
||||
<td>{{ summary.speaker.name }}</td>
|
||||
<td>{{ summary.content }}</td>
|
||||
<td>{{ summary.source|default:"-" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="no-data">昨日没有汇总记录</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- 今日计划 -->
|
||||
<div class="section">
|
||||
<h2>今日计划</h2>
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user