Files
diary-family/core/history_views.py
xiaji d0fa855388 feat(历史记录): 添加历史记录查询功能及PDF导出
新增历史记录查询页面,支持按时间范围筛选阅读记录、感悟记录、汇总记录、家庭事项和今日计划
添加历史记录PDF导出功能,生成包含所有记录的格式化PDF报告
2026-02-01 18:24:18 +08:00

151 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.shortcuts import render
from django.http import HttpResponse
from django.utils import timezone
from django.contrib.auth.decorators import login_required
from django.conf import settings
from datetime import datetime, timedelta
from loguru import logger
import os
from .models import (
ReadingRecord,
InsightRecord,
Summary,
FamilyTask,
TodayPlan,
)
from .views import is_weasyprint_available
@login_required
def history_records(request):
"""历史记录查询页面"""
logger.info("用户访问历史记录查询页面")
start_date_str = request.GET.get('start_date')
end_date_str = request.GET.get('end_date')
if not start_date_str or not end_date_str:
today = timezone.now().date()
start_date = datetime(today.year, 1, 1).date()
end_date = today
else:
start_date = datetime.strptime(start_date_str, '%Y-%m-%d').date()
end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
# 查询各个类型的记录
reading_records = ReadingRecord.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
insight_records = InsightRecord.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
summary_records = Summary.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
family_tasks = FamilyTask.objects.filter(
created_at__date__range=[start_date, end_date]
).order_by('-created_at')
today_plans = TodayPlan.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
context = {
'start_date': start_date,
'end_date': end_date,
'reading_records': reading_records,
'insight_records': insight_records,
'summary_records': summary_records,
'family_tasks': family_tasks,
'today_plans': today_plans,
}
return render(request, 'core/history_records.html', context)
@login_required
def history_pdf(request):
"""导出历史记录PDF"""
if not is_weasyprint_available():
logger.error("WeasyPrint库不可用无法生成PDF报告")
return HttpResponse("PDF功能不可用请检查WeasyPrint库是否正确安装", status=500)
start_date_str = request.GET.get('start_date')
end_date_str = request.GET.get('end_date')
if not start_date_str or not end_date_str:
return HttpResponse("请提供开始时间和结束时间", status=400)
try:
start_date = datetime.strptime(start_date_str, '%Y-%m-%d').date()
end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
except ValueError:
return HttpResponse("日期格式错误", status=400)
if start_date > end_date:
return HttpResponse("开始时间不能晚于结束时间", status=400)
logger.info(f"用户导出历史记录PDF: {start_date}{end_date}")
try:
# 查询各个类型的记录
reading_records = ReadingRecord.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
insight_records = InsightRecord.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
summary_records = Summary.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
family_tasks = FamilyTask.objects.filter(
created_at__date__range=[start_date, end_date]
).order_by('-created_at')
today_plans = TodayPlan.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
context = {
'start_date': start_date,
'end_date': end_date,
'reading_records': reading_records,
'insight_records': insight_records,
'summary_records': summary_records,
'family_tasks': family_tasks,
'today_plans': today_plans,
}
# 渲染HTML模板
html_string = render(request, 'core/history_pdf.html', context).content.decode('utf-8')
# 生成PDF
pdf_file = f"history_{start_date_str}_to_{end_date_str}.pdf"
pdf_path = os.path.join(settings.REPORTS_ROOT, pdf_file)
# 确保报告目录存在
os.makedirs(settings.REPORTS_ROOT, exist_ok=True)
# 动态导入WeasyPrint
from weasyprint import HTML
HTML(string=html_string).write_pdf(pdf_path)
logger.info(f"历史记录PDF生成成功: {pdf_path}")
# 返回PDF文件
with open(pdf_path, 'rb') as f:
response = HttpResponse(f.read(), content_type='application/pdf')
response['Content-Disposition'] = f'attachment; filename="{pdf_file}"'
return response
except Exception as e:
logger.error(f"生成历史记录PDF失败: {str(e)}")
return HttpResponse(f"生成PDF失败: {str(e)}", status=500)