2026-01-18 18:57:45 +08:00
|
|
|
|
import re
|
2026-01-04 19:17:33 +08:00
|
|
|
|
from django import forms
|
|
|
|
|
|
from django.utils import timezone
|
|
|
|
|
|
from .models import (
|
|
|
|
|
|
ReadingRecord,
|
|
|
|
|
|
InsightRecord,
|
2026-01-24 19:48:40 +08:00
|
|
|
|
Summary,
|
2026-01-04 19:17:33 +08:00
|
|
|
|
FamilyTask,
|
|
|
|
|
|
TodayPlan,
|
2026-01-23 20:35:30 +08:00
|
|
|
|
SystemConfig,
|
2026-03-09 15:11:45 +08:00
|
|
|
|
FamilyMember,
|
2026-05-25 22:04:57 +08:00
|
|
|
|
PublicContent,
|
|
|
|
|
|
TempMessage
|
2026-01-04 19:17:33 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class ReadingRecordForm(forms.ModelForm):
|
|
|
|
|
|
"""阅读记录表单"""
|
|
|
|
|
|
class Meta:
|
|
|
|
|
|
model = ReadingRecord
|
2026-01-05 23:11:41 +08:00
|
|
|
|
fields = ['type', 'title', 'source', 'progress', 'note', 'file']
|
2026-01-04 19:17:33 +08:00
|
|
|
|
widgets = {
|
|
|
|
|
|
'type': forms.Select(attrs={'class': 'form-select'}),
|
|
|
|
|
|
'title': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入标题'}),
|
|
|
|
|
|
'source': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入来源'}),
|
|
|
|
|
|
'progress': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入进度'}),
|
2026-01-05 23:11:41 +08:00
|
|
|
|
'note': forms.Textarea(attrs={'class': 'form-control', 'rows': 4, 'placeholder': '请输入阅读笔记'}),
|
2026-01-04 19:17:33 +08:00
|
|
|
|
'file': forms.FileInput(attrs={'class': 'form-control'}),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class InsightRecordForm(forms.ModelForm):
|
|
|
|
|
|
"""感悟记录表单"""
|
|
|
|
|
|
class Meta:
|
|
|
|
|
|
model = InsightRecord
|
2026-01-23 20:35:30 +08:00
|
|
|
|
fields = ['speaker', 'content', 'file']
|
2026-01-04 19:17:33 +08:00
|
|
|
|
widgets = {
|
2026-01-23 20:35:30 +08:00
|
|
|
|
'speaker': forms.Select(attrs={'class': 'form-select'}),
|
2026-01-07 22:11:07 +08:00
|
|
|
|
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 5, 'placeholder': '请输入感悟'}),
|
2026-01-04 19:17:33 +08:00
|
|
|
|
'file': forms.FileInput(attrs={'class': 'form-control'}),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 19:48:40 +08:00
|
|
|
|
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'}),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-04 19:17:33 +08:00
|
|
|
|
class FamilyTaskForm(forms.ModelForm):
|
|
|
|
|
|
"""家庭事项表单"""
|
|
|
|
|
|
class Meta:
|
|
|
|
|
|
model = FamilyTask
|
|
|
|
|
|
fields = ['type', 'content', 'priority', 'status', 'deadline']
|
|
|
|
|
|
widgets = {
|
|
|
|
|
|
'type': forms.Select(attrs={'class': 'form-select'}),
|
|
|
|
|
|
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': '请输入事项内容'}),
|
|
|
|
|
|
'priority': forms.Select(attrs={'class': 'form-select'}),
|
|
|
|
|
|
'status': forms.Select(attrs={'class': 'form-select'}),
|
|
|
|
|
|
'deadline': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class TodayPlanForm(forms.ModelForm):
|
|
|
|
|
|
"""今日计划表单"""
|
|
|
|
|
|
class Meta:
|
|
|
|
|
|
model = TodayPlan
|
2026-01-23 20:35:30 +08:00
|
|
|
|
fields = ['date', 'speaker', 'content', 'priority', 'type', 'status']
|
2026-01-04 19:17:33 +08:00
|
|
|
|
widgets = {
|
|
|
|
|
|
'date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
|
2026-01-23 20:35:30 +08:00
|
|
|
|
'speaker': forms.Select(attrs={'class': 'form-select'}),
|
2026-01-04 19:17:33 +08:00
|
|
|
|
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': '请输入计划内容'}),
|
|
|
|
|
|
'priority': forms.Select(attrs={'class': 'form-select'}),
|
|
|
|
|
|
'type': forms.Select(attrs={'class': 'form-select'}),
|
|
|
|
|
|
'status': forms.Select(attrs={'class': 'form-select'}),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class SystemConfigForm(forms.ModelForm):
|
|
|
|
|
|
"""系统配置表单"""
|
2026-01-18 18:57:45 +08:00
|
|
|
|
|
2026-01-04 19:17:33 +08:00
|
|
|
|
class Meta:
|
|
|
|
|
|
model = SystemConfig
|
2026-01-18 18:35:09 +08:00
|
|
|
|
fields = ['smtp_server', 'smtp_port', 'smtp_username', 'smtp_password', 'sender_email', 'send_time', 'recipient_email']
|
2026-01-04 19:17:33 +08:00
|
|
|
|
widgets = {
|
|
|
|
|
|
'smtp_server': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入SMTP服务器'}),
|
|
|
|
|
|
'smtp_port': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': '请输入SMTP端口'}),
|
|
|
|
|
|
'smtp_username': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入SMTP用户名'}),
|
|
|
|
|
|
'smtp_password': forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请输入SMTP密码'}),
|
2026-01-18 18:58:52 +08:00
|
|
|
|
'sender_email': forms.EmailInput(attrs={'class': 'form-control', 'placeholder': '请输入发件人的邮箱'}),
|
2026-01-04 19:17:33 +08:00
|
|
|
|
'send_time': forms.TimeInput(attrs={'type': 'time', 'class': 'form-control'}),
|
|
|
|
|
|
'recipient_email': forms.EmailInput(attrs={'class': 'form-control', 'placeholder': '请输入收件人邮箱'}),
|
2026-01-18 18:57:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def clean_sender_email(self):
|
|
|
|
|
|
sender_email = self.cleaned_data.get('sender_email')
|
|
|
|
|
|
if sender_email:
|
|
|
|
|
|
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
|
|
|
|
|
if not re.match(email_pattern, sender_email):
|
|
|
|
|
|
logger.warning(f"发件人邮箱格式不正确: {sender_email}")
|
|
|
|
|
|
raise forms.ValidationError("请输入有效的邮箱地址,格式如:example@domain.com")
|
|
|
|
|
|
return sender_email
|
|
|
|
|
|
|
|
|
|
|
|
def clean_recipient_email(self):
|
|
|
|
|
|
recipient_email = self.cleaned_data.get('recipient_email')
|
|
|
|
|
|
if recipient_email:
|
|
|
|
|
|
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
|
|
|
|
|
if not re.match(email_pattern, recipient_email):
|
|
|
|
|
|
logger.warning(f"收件人邮箱格式不正确: {recipient_email}")
|
|
|
|
|
|
raise forms.ValidationError("请输入有效的邮箱地址,格式如:example@domain.com")
|
2026-03-09 15:11:45 +08:00
|
|
|
|
return recipient_email
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PublicContentForm(forms.ModelForm):
|
|
|
|
|
|
"""公开内容表单"""
|
|
|
|
|
|
class Meta:
|
|
|
|
|
|
model = PublicContent
|
|
|
|
|
|
fields = ['type', 'title', 'content', 'file', 'url', 'sort_order', 'is_published']
|
|
|
|
|
|
widgets = {
|
|
|
|
|
|
'type': forms.Select(attrs={'class': 'form-select'}),
|
|
|
|
|
|
'title': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入标题'}),
|
|
|
|
|
|
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 5, 'placeholder': '请输入内容'}),
|
|
|
|
|
|
'file': forms.FileInput(attrs={'class': 'form-control'}),
|
|
|
|
|
|
'url': forms.URLInput(attrs={'class': 'form-control', 'placeholder': '请输入链接地址'}),
|
|
|
|
|
|
'sort_order': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': '请输入排序值'}),
|
2026-05-25 21:08:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TempUploadForm(forms.ModelForm):
|
|
|
|
|
|
"""临时文件上传表单"""
|
|
|
|
|
|
expire_type = forms.ChoiceField(
|
|
|
|
|
|
choices=[
|
|
|
|
|
|
('expire_1h', '1小时'),
|
|
|
|
|
|
('expire_1d', '1天'),
|
|
|
|
|
|
('expire_7d', '7天'),
|
|
|
|
|
|
],
|
|
|
|
|
|
widget=forms.Select(attrs={'class': 'form-select'}),
|
|
|
|
|
|
label='过期时间'
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
|
model = PublicContent
|
2026-05-25 22:04:57 +08:00
|
|
|
|
fields = ['title', 'file']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TempMessageForm(forms.ModelForm):
|
|
|
|
|
|
"""临时留言表单"""
|
|
|
|
|
|
class Meta:
|
|
|
|
|
|
model = TempMessage
|
|
|
|
|
|
fields = ['username', 'content']
|
|
|
|
|
|
widgets = {
|
|
|
|
|
|
'username': forms.TextInput(attrs={'class': 'form-control', 'maxlength': '20', 'placeholder': '用户名(可选,最多20字节)'}),
|
|
|
|
|
|
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'maxlength': '1000', 'placeholder': '说点什么...(最多1000字节)'}),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def clean_content(self):
|
|
|
|
|
|
content = self.cleaned_data.get('content', '')
|
|
|
|
|
|
if len(content.encode('utf-8')) > 1000:
|
|
|
|
|
|
raise forms.ValidationError("内容不能超过1000字节")
|
|
|
|
|
|
return content
|