Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
423 changes: 144 additions & 279 deletions README.md

Large diffs are not rendered by default.

Empty file added core/__init__.py
Empty file.
87 changes: 87 additions & 0 deletions core/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from django.contrib import admin
from django.utils.html import format_html
from .models import (SiteSettings, Banner, Notification, ActivityLog,
FAQ, ContactMessage, EmailTemplate)

@admin.register(SiteSettings)
class SiteSettingsAdmin(admin.ModelAdmin):
fieldsets = (
('基本信息', {
'fields': ('site_name', 'site_description', 'site_keywords', 'logo', 'favicon')
}),
('联系信息', {
'fields': ('contact_email', 'contact_phone', 'address')
}),
('社交媒体', {
'fields': ('weibo_url', 'wechat_qr')
}),
('SEO设置', {
'fields': ('google_analytics', 'baidu_analytics')
}),
('系统设置', {
'fields': ('maintenance_mode', 'maintenance_message')
}),
)

def has_add_permission(self, request):
return not SiteSettings.objects.exists()

@admin.register(Banner)
class BannerAdmin(admin.ModelAdmin):
list_display = ('title', 'is_active', 'sort_order', 'start_date', 'end_date', 'created_at')
list_filter = ('is_active', 'created_at', 'start_date', 'end_date')
search_fields = ('title', 'subtitle')
ordering = ('sort_order', '-created_at')

@admin.register(Notification)
class NotificationAdmin(admin.ModelAdmin):
list_display = ('user', 'title', 'notification_type', 'is_read', 'created_at')
list_filter = ('notification_type', 'is_read', 'created_at')
search_fields = ('user__username', 'title', 'message')
raw_id_fields = ('user',)
readonly_fields = ('created_at', 'read_at')

@admin.register(ActivityLog)
class ActivityLogAdmin(admin.ModelAdmin):
list_display = ('user', 'action', 'description', 'ip_address', 'created_at')
list_filter = ('action', 'created_at')
search_fields = ('user__username', 'description', 'ip_address')
raw_id_fields = ('user',)
readonly_fields = ('created_at',)

def has_add_permission(self, request):
return False # 只读,不允许手动添加

@admin.register(FAQ)
class FAQAdmin(admin.ModelAdmin):
list_display = ('question', 'category', 'is_active', 'sort_order', 'view_count', 'created_at')
list_filter = ('is_active', 'category', 'created_at')
search_fields = ('question', 'answer', 'category')
ordering = ('sort_order', '-created_at')

@admin.register(ContactMessage)
class ContactMessageAdmin(admin.ModelAdmin):
list_display = ('name', 'email', 'subject', 'is_replied', 'created_at')
list_filter = ('is_replied', 'created_at', 'replied_at')
search_fields = ('name', 'email', 'subject', 'message')
readonly_fields = ('created_at',)
raw_id_fields = ('replied_by',)

fieldsets = (
('联系信息', {
'fields': ('name', 'email', 'phone', 'created_at')
}),
('消息内容', {
'fields': ('subject', 'message')
}),
('回复信息', {
'fields': ('is_replied', 'reply_message', 'replied_by', 'replied_at')
}),
)

@admin.register(EmailTemplate)
class EmailTemplateAdmin(admin.ModelAdmin):
list_display = ('name', 'code', 'subject', 'is_active', 'created_at')
list_filter = ('is_active', 'created_at')
search_fields = ('name', 'code', 'subject')
readonly_fields = ('created_at', 'updated_at')
6 changes: 6 additions & 0 deletions core/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class CoreConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'core'
159 changes: 159 additions & 0 deletions core/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Generated by Django 5.2.5 on 2025-08-12 02:09

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
('contenttypes', '0002_remove_content_type_name'),
]

operations = [
migrations.CreateModel(
name='Banner',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=200, verbose_name='标题')),
('subtitle', models.CharField(blank=True, max_length=200, verbose_name='副标题')),
('image', models.ImageField(upload_to='banners/', verbose_name='图片')),
('link', models.URLField(blank=True, verbose_name='链接')),
('button_text', models.CharField(blank=True, max_length=50, verbose_name='按钮文字')),
('is_active', models.BooleanField(default=True, verbose_name='是否激活')),
('sort_order', models.IntegerField(default=0, verbose_name='排序')),
('start_date', models.DateTimeField(blank=True, null=True, verbose_name='开始时间')),
('end_date', models.DateTimeField(blank=True, null=True, verbose_name='结束时间')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
],
options={
'verbose_name': '轮播图',
'verbose_name_plural': '轮播图',
'ordering': ['sort_order', '-created_at'],
},
),
migrations.CreateModel(
name='ContactMessage',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100, verbose_name='姓名')),
('email', models.EmailField(max_length=254, verbose_name='邮箱')),
('phone', models.CharField(blank=True, max_length=20, verbose_name='电话')),
('subject', models.CharField(max_length=200, verbose_name='主题')),
('message', models.TextField(verbose_name='消息内容')),
('is_replied', models.BooleanField(default=False, verbose_name='是否已回复')),
('reply_message', models.TextField(blank=True, verbose_name='回复内容')),
('replied_at', models.DateTimeField(blank=True, null=True, verbose_name='回复时间')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
],
options={
'verbose_name': '联系消息',
'verbose_name_plural': '联系消息',
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='EmailTemplate',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100, verbose_name='模板名称')),
('code', models.CharField(max_length=50, unique=True, verbose_name='模板代码')),
('subject', models.CharField(max_length=200, verbose_name='邮件主题')),
('html_content', models.TextField(verbose_name='HTML内容')),
('text_content', models.TextField(blank=True, verbose_name='文本内容')),
('variables', models.JSONField(blank=True, help_text='JSON格式的变量说明', null=True, verbose_name='可用变量')),
('is_active', models.BooleanField(default=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': '邮件模板',
},
),
migrations.CreateModel(
name='FAQ',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('question', models.CharField(max_length=300, verbose_name='问题')),
('answer', models.TextField(verbose_name='答案')),
('category', models.CharField(blank=True, max_length=100, verbose_name='分类')),
('is_active', models.BooleanField(default=True, verbose_name='是否激活')),
('sort_order', models.IntegerField(default=0, verbose_name='排序')),
('view_count', models.IntegerField(default=0, 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': ['sort_order', '-created_at'],
},
),
migrations.CreateModel(
name='Notification',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=200, verbose_name='标题')),
('message', models.TextField(verbose_name='消息内容')),
('notification_type', models.CharField(choices=[('info', '信息'), ('success', '成功'), ('warning', '警告'), ('error', '错误')], default='info', max_length=20, verbose_name='通知类型')),
('is_read', models.BooleanField(default=False, verbose_name='是否已读')),
('link', models.URLField(blank=True, verbose_name='相关链接')),
('object_id', models.PositiveIntegerField(blank=True, null=True)),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('read_at', models.DateTimeField(blank=True, null=True, verbose_name='阅读时间')),
],
options={
'verbose_name': '通知',
'verbose_name_plural': '通知',
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='SiteSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('site_name', models.CharField(default='我的网站', max_length=100, verbose_name='网站名称')),
('site_description', models.TextField(blank=True, verbose_name='网站描述')),
('site_keywords', models.TextField(blank=True, verbose_name='网站关键词')),
('logo', models.ImageField(blank=True, null=True, upload_to='site/', verbose_name='网站LOGO')),
('favicon', models.ImageField(blank=True, null=True, upload_to='site/', verbose_name='网站图标')),
('contact_email', models.EmailField(blank=True, max_length=254, verbose_name='联系邮箱')),
('contact_phone', models.CharField(blank=True, max_length=20, verbose_name='联系电话')),
('address', models.TextField(blank=True, verbose_name='地址')),
('weibo_url', models.URLField(blank=True, verbose_name='微博链接')),
('wechat_qr', models.ImageField(blank=True, null=True, upload_to='site/', verbose_name='微信二维码')),
('google_analytics', models.TextField(blank=True, verbose_name='Google Analytics代码')),
('baidu_analytics', models.TextField(blank=True, verbose_name='百度统计代码')),
('maintenance_mode', models.BooleanField(default=False, verbose_name='维护模式')),
('maintenance_message', models.TextField(blank=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': '网站设置',
},
),
migrations.CreateModel(
name='ActivityLog',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('action', models.CharField(choices=[('create', '创建'), ('update', '更新'), ('delete', '删除'), ('login', '登录'), ('logout', '登出'), ('view', '查看'), ('download', '下载'), ('upload', '上传'), ('other', '其他')], max_length=20, verbose_name='操作')),
('description', models.TextField(verbose_name='描述')),
('ip_address', models.GenericIPAddressField(blank=True, null=True, verbose_name='IP地址')),
('user_agent', models.TextField(blank=True, verbose_name='用户代理')),
('object_id', models.PositiveIntegerField(blank=True, null=True)),
('extra_data', models.JSONField(blank=True, null=True, verbose_name='额外数据')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('content_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
],
options={
'verbose_name': '活动日志',
'verbose_name_plural': '活动日志',
'ordering': ['-created_at'],
},
),
]
39 changes: 39 additions & 0 deletions core/migrations/0002_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Django 5.2.5 on 2025-08-12 02:09

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('core', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.AddField(
model_name='activitylog',
name='user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='activity_logs', to=settings.AUTH_USER_MODEL, verbose_name='用户'),
),
migrations.AddField(
model_name='contactmessage',
name='replied_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replied_messages', to=settings.AUTH_USER_MODEL, verbose_name='回复人'),
),
migrations.AddField(
model_name='notification',
name='content_type',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'),
),
migrations.AddField(
model_name='notification',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to=settings.AUTH_USER_MODEL, verbose_name='用户'),
),
]
Empty file added core/migrations/__init__.py
Empty file.
Loading