feat(report): 添加定时生成PDF报告功能并重构邮件发送任务
将PDF生成逻辑从邮件发送任务中分离,新增独立定时任务 更新README文档说明PDF生成配置和使用方法
This commit is contained in:
81
README.md
81
README.md
@@ -423,6 +423,87 @@ def setup_daily_report_task():
|
|||||||
- 配置监控系统(如 Prometheus + Grafana)
|
- 配置监控系统(如 Prometheus + Grafana)
|
||||||
- 启用 Celery 监控工具(如 Flower)
|
- 启用 Celery 监控工具(如 Flower)
|
||||||
|
|
||||||
|
## 定时生成PDF文件配置
|
||||||
|
|
||||||
|
除了定时发送邮件外,系统还支持单独定时生成PDF文件,便于在服务器上保存历史报告。
|
||||||
|
|
||||||
|
### 1. 配置定时生成PDF任务
|
||||||
|
|
||||||
|
#### 方式一:通过 Django 管理后台(推荐)
|
||||||
|
|
||||||
|
1. 登录 Django 管理后台(/houtai)
|
||||||
|
2. 找到 **Periodic tasks**(周期性任务)
|
||||||
|
3. 点击 **Add** 按钮添加新任务
|
||||||
|
4. 配置任务:
|
||||||
|
- **Name**: 任务名称(如:每日PDF报告生成)
|
||||||
|
- **Task (registered)**: 选择 `core.tasks.generate_daily_pdf_report`
|
||||||
|
- **Interval**: 设置执行间隔(如:每天)
|
||||||
|
- **Enabled**: 勾选启用
|
||||||
|
5. 点击 **Save** 保存
|
||||||
|
|
||||||
|
#### 方式二:通过代码配置
|
||||||
|
|
||||||
|
在 `core/tasks.py` 中添加定时任务配置:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from celery import shared_task
|
||||||
|
from django_celery_beat.models import PeriodicTask, IntervalSchedule
|
||||||
|
|
||||||
|
# 创建或更新PDF生成定时任务
|
||||||
|
def setup_daily_pdf_task():
|
||||||
|
# 创建每天执行的间隔
|
||||||
|
schedule, created = IntervalSchedule.objects.get_or_create(
|
||||||
|
every=1,
|
||||||
|
period=IntervalSchedule.DAYS,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 创建或更新定时任务
|
||||||
|
task, created = PeriodicTask.objects.update_or_create(
|
||||||
|
name='Daily PDF Generation Task',
|
||||||
|
defaults={
|
||||||
|
'interval': schedule,
|
||||||
|
'task': 'core.tasks.generate_daily_pdf_report',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return task
|
||||||
|
```
|
||||||
|
|
||||||
|
然后在 Django 启动时调用此函数(如在 `core/apps.py` 中)。
|
||||||
|
|
||||||
|
### 2. PDF文件存储位置
|
||||||
|
|
||||||
|
生成的PDF文件默认存储在项目的 `reports` 目录下,命名格式为 `report_YYYY-MM-DD.pdf`。
|
||||||
|
|
||||||
|
可以在 `settings.py` 中修改存储位置:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Reports files configuration
|
||||||
|
REPORTS_URL = '/reports/'
|
||||||
|
REPORTS_ROOT = BASE_DIR / 'reports' # 可以修改为其他路径
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 验证PDF生成任务
|
||||||
|
|
||||||
|
- 查看 Celery 日志:`tail -f /var/log/celery/worker.log`
|
||||||
|
- 检查PDF文件是否生成:`ls -la /path/to/diary-family/reports/`
|
||||||
|
- 在 Django 管理后台查看任务执行记录
|
||||||
|
|
||||||
|
### 4. 常见问题排查
|
||||||
|
|
||||||
|
1. **PDF生成失败**
|
||||||
|
- 检查 WeasyPrint 库是否正确安装:`pip list | grep weasyprint`
|
||||||
|
- 检查系统字体是否完整:PDF生成需要系统字体支持
|
||||||
|
- 查看 Celery 日志中的错误信息
|
||||||
|
|
||||||
|
2. **任务执行但没有生成文件**
|
||||||
|
- 检查 `REPORTS_ROOT` 目录权限:确保 Celery 进程有写入权限
|
||||||
|
- 检查磁盘空间是否充足
|
||||||
|
- 查看 Celery 日志中的详细信息
|
||||||
|
|
||||||
|
3. **PDF内容不完整**
|
||||||
|
- 检查模板文件 `core/templates/core/report_pdf.html` 是否完整
|
||||||
|
- 确保所有依赖的 CSS 和图像资源都能正常访问
|
||||||
|
|
||||||
## Celery 监控(可选)
|
## Celery 监控(可选)
|
||||||
|
|
||||||
使用 Flower 监控 Celery 任务:
|
使用 Flower 监控 Celery 任务:
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ from .models import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def send_daily_report():
|
def generate_daily_pdf_report():
|
||||||
"""发送每日报告"""
|
"""生成每日PDF报告"""
|
||||||
logger.info("开始执行每日报告发送任务")
|
logger.info("开始执行每日PDF报告生成任务")
|
||||||
|
|
||||||
# 检查WeasyPrint是否可用
|
# 检查WeasyPrint是否可用
|
||||||
if not is_weasyprint_available():
|
if not is_weasyprint_available():
|
||||||
@@ -44,14 +44,6 @@ def send_daily_report():
|
|||||||
today = timezone.now().date()
|
today = timezone.now().date()
|
||||||
today_str = today.strftime('%Y-%m-%d')
|
today_str = today.strftime('%Y-%m-%d')
|
||||||
|
|
||||||
# 获取系统配置
|
|
||||||
config = SystemConfig.get_config()
|
|
||||||
|
|
||||||
# 检查邮件配置是否完整
|
|
||||||
if not all([config.smtp_server, config.smtp_username, config.smtp_password, config.recipient_email]):
|
|
||||||
logger.error("邮件配置不完整,无法发送邮件")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 生成报告数据
|
# 生成报告数据
|
||||||
report_date = today
|
report_date = today
|
||||||
yesterday = report_date - timedelta(days=1)
|
yesterday = report_date - timedelta(days=1)
|
||||||
@@ -92,16 +84,43 @@ def send_daily_report():
|
|||||||
from weasyprint import HTML
|
from weasyprint import HTML
|
||||||
HTML(string=html_string).write_pdf(pdf_path)
|
HTML(string=html_string).write_pdf(pdf_path)
|
||||||
logger.info(f"PDF报告生成成功: {pdf_path}")
|
logger.info(f"PDF报告生成成功: {pdf_path}")
|
||||||
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"PDF报告生成失败: {str(e)}")
|
logger.error(f"PDF报告生成失败: {str(e)}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@shared_task
|
||||||
|
def send_daily_report():
|
||||||
|
"""发送每日报告"""
|
||||||
|
logger.info("开始执行每日报告发送任务")
|
||||||
|
|
||||||
|
# 先生成PDF报告
|
||||||
|
pdf_generated = generate_daily_pdf_report()
|
||||||
|
if not pdf_generated:
|
||||||
|
logger.error("PDF报告生成失败,无法发送邮件")
|
||||||
|
return False
|
||||||
|
|
||||||
|
today = timezone.now().date()
|
||||||
|
today_str = today.strftime('%Y-%m-%d')
|
||||||
|
|
||||||
|
# 获取系统配置
|
||||||
|
config = SystemConfig.get_config()
|
||||||
|
|
||||||
|
# 检查邮件配置是否完整
|
||||||
|
if not all([config.smtp_server, config.smtp_username, config.smtp_password, config.recipient_email]):
|
||||||
|
logger.error("邮件配置不完整,无法发送邮件")
|
||||||
|
return False
|
||||||
|
|
||||||
# 发送邮件
|
# 发送邮件
|
||||||
subject = f"家庭日报 - {today_str}"
|
subject = f"家庭日报 - {today_str}"
|
||||||
message = f"这是您的家庭日报,日期:{today_str}"
|
message = f"这是您的家庭日报,日期:{today_str}"
|
||||||
from_email = config.smtp_username
|
from_email = config.smtp_username
|
||||||
recipient_list = [config.recipient_email]
|
recipient_list = [config.recipient_email]
|
||||||
|
|
||||||
|
# PDF文件路径
|
||||||
|
pdf_file = f"report_{today_str}.pdf"
|
||||||
|
pdf_path = os.path.join(settings.REPORTS_ROOT, pdf_file)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
email = EmailMessage(
|
email = EmailMessage(
|
||||||
subject=subject,
|
subject=subject,
|
||||||
|
|||||||
Reference in New Issue
Block a user