XinXiKuaiBaoYuan/django-backend/tasks/models.py

184 lines
7.2 KiB
Python
Raw Permalink Normal View History

from django.db import models
from django.contrib.auth.models import User
import json
class Task(models.Model):
"""任务模型"""
TASK_TYPES = [
('single', '单次任务'),
('scheduled', '周期任务'),
]
TASK_STATUSES = [
('running', '运行中'), # 当前任务在运行
('generating', '生成中'), # 当前任务有报告正在生成
('error', '异常'), # 报告生成异常
('paused', '暂停'), # 任务暂停
]
title = models.CharField(max_length=255, verbose_name='任务标题')
description = models.TextField(blank=True, verbose_name='任务描述')
requirement = models.TextField(verbose_name='用户需求描述')
type = models.CharField(max_length=20, choices=TASK_TYPES, verbose_name='任务类型')
status = models.CharField(max_length=20, choices=TASK_STATUSES, default='running', verbose_name='任务状态')
# JSON字段存储配置
schedule_config = models.JSONField(null=True, blank=True, verbose_name='周期任务配置')
sources_config = models.JSONField(default=dict, verbose_name='信息源配置')
web_search_enabled = models.BooleanField(default=True, verbose_name='是否启用联网搜索')
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户')
# 时间字段
last_report_time = models.DateTimeField(null=True, blank=True, verbose_name='最新报告生成时间')
next_run_time = models.DateTimeField(null=True, blank=True, verbose_name='下次执行时间')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'tasks'
verbose_name = '任务'
verbose_name_plural = '任务'
ordering = ['-last_report_time', '-created_at']
indexes = [
models.Index(fields=['user', 'status']),
models.Index(fields=['last_report_time']),
models.Index(fields=['status']),
]
def __str__(self):
return f"{self.title} ({self.get_type_display()})"
@property
def report_count(self):
"""获取报告数量"""
return self.reports.count()
@property
def has_new_report(self):
"""是否有新报告(用于排序)"""
if not self.last_report_time:
return False
# 如果最新报告是24小时内生成的认为是新报告
from django.utils import timezone
from datetime import timedelta
return timezone.now() - self.last_report_time < timedelta(hours=24)
class Report(models.Model):
"""报告模型"""
REPORT_STATUSES = [
('generating', '生成中'),
('completed', '已完成'),
('failed', '失败'),
]
task = models.ForeignKey(Task, on_delete=models.CASCADE, related_name='reports', verbose_name='任务')
title = models.CharField(max_length=255, verbose_name='报告标题')
summary = models.TextField(blank=True, verbose_name='报告摘要')
content = models.TextField(verbose_name='报告内容')
source_tag = models.CharField(max_length=100, blank=True, verbose_name='信息来源标签')
word_count = models.IntegerField(default=0, verbose_name='字数统计')
status = models.CharField(max_length=20, choices=REPORT_STATUSES, default='generating', verbose_name='生成状态')
generated_at = models.DateTimeField(null=True, blank=True, verbose_name='生成完成时间')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'reports'
verbose_name = '报告'
verbose_name_plural = '报告'
ordering = ['-generated_at', '-created_at']
indexes = [
models.Index(fields=['task', 'generated_at']),
models.Index(fields=['status']),
models.Index(fields=['generated_at']),
]
def __str__(self):
return f"{self.title} - {self.task.title}"
def save(self, *args, **kwargs):
# 自动计算字数
if self.content:
self.word_count = len(self.content.replace(' ', '').replace('\n', ''))
# 如果状态变为完成,更新生成时间和任务的最新报告时间
if self.status == 'completed' and not self.generated_at:
from django.utils import timezone
self.generated_at = timezone.now()
self.task.last_report_time = self.generated_at
self.task.save(update_fields=['last_report_time'])
super().save(*args, **kwargs)
class ReportSource(models.Model):
"""报告来源数据模型"""
SOURCE_TYPES = [
('wechat', '微信'),
('official-account', '公众号'),
('feishu', '飞书'),
('dingtalk', '钉钉'),
('email', '邮箱'),
('website', '网页'),
('baidu-pan', '百度网盘'),
('web-search', '联网搜索'),
]
report = models.ForeignKey(Report, on_delete=models.CASCADE, related_name='sources', verbose_name='报告')
source_type = models.CharField(max_length=20, choices=SOURCE_TYPES, verbose_name='信息源类型')
source_name = models.CharField(max_length=255, verbose_name='信息源名称')
source_url = models.URLField(blank=True, verbose_name='原始链接')
raw_content = models.TextField(blank=True, verbose_name='原始内容')
extracted_content = models.TextField(blank=True, verbose_name='提取的关键内容')
collected_at = models.DateTimeField(auto_now_add=True, verbose_name='采集时间')
class Meta:
db_table = 'report_sources'
verbose_name = '报告来源数据'
verbose_name_plural = '报告来源数据'
indexes = [
models.Index(fields=['report']),
models.Index(fields=['source_type']),
]
def __str__(self):
return f"{self.source_name} - {self.report.title}"
class TaskLog(models.Model):
"""任务执行日志模型"""
ACTION_TYPES = [
('created', '创建'),
('started', '开始'),
('paused', '暂停'),
('resumed', '恢复'),
('completed', '完成'),
('error', '错误'),
]
task = models.ForeignKey(Task, on_delete=models.CASCADE, related_name='logs', verbose_name='任务')
action_type = models.CharField(max_length=20, choices=ACTION_TYPES, verbose_name='操作类型')
message = models.TextField(blank=True, verbose_name='日志信息')
error_details = models.JSONField(null=True, blank=True, verbose_name='错误详情')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
class Meta:
db_table = 'task_logs'
verbose_name = '任务执行日志'
verbose_name_plural = '任务执行日志'
ordering = ['-created_at']
indexes = [
models.Index(fields=['task', 'created_at']),
models.Index(fields=['action_type']),
]
def __str__(self):
return f"{self.task.title} - {self.get_action_type_display()}"