From 784c8bbb6ec6a109bb948dec23ab8233eab7c850 Mon Sep 17 00:00:00 2001 From: ngfchl Date: Thu, 2 Apr 2026 11:01:25 +0800 Subject: [PATCH] =?UTF-8?q?update.=20=E4=BC=98=E5=8C=96=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- base/admin.py | 24 ++++- base/context_processors.py | 5 +- base/migrations/0004_picturelink.py | 31 +++++++ base/models.py | 37 ++++++++ server/settings.py | 19 ++++ static/css/style.css | 20 ++-- templates/base.html | 51 ++++++++++- templates/front/index.html | 136 ++++++++++++++-------------- templates/header.html | 35 ------- templates/index.html | 11 --- 10 files changed, 241 insertions(+), 128 deletions(-) create mode 100644 base/migrations/0004_picturelink.py delete mode 100644 templates/header.html delete mode 100644 templates/index.html diff --git a/base/admin.py b/base/admin.py index c4171e8..e49c831 100644 --- a/base/admin.py +++ b/base/admin.py @@ -1,7 +1,8 @@ -from django.contrib import admin +from django.contrib import admin, messages +from django.core.cache import cache from import_export.admin import ImportExportModelAdmin -from base.models import MainMenu, BaseInfo, LinkCategory, FriendLink +from base.models import MainMenu, BaseInfo, LinkCategory, FriendLink, PictureLink # —————— 主菜单 —————— @@ -60,6 +61,25 @@ class FriendLinkAdmin(ImportExportModelAdmin): return super().formfield_for_foreignkey(db_field, request, **kwargs) +@admin.register(PictureLink) +class PictureLinkAdmin(admin.ModelAdmin): + list_display = ['name', 'order', 'is_active', 'created_at'] + + def save_model(self, request, obj, form, change): + # 1. 先执行 Model 的 save 方法(这里会触发逻辑判断和消息暂存) + super().save_model(request, obj, form, change) + + # 2. 【关键】检查有没有暂存的消息 + # 获取 key(如果是新建对象,obj.pk 此时已经有了,如果是内存中的临时对象则用 id) + msg_key = obj.pk if obj.pk else id(obj) + key = f"picture_count_limit_{msg_key}" + msg = cache.get(key) # 缓存 30 秒 + if msg: + # 取出消息并弹窗 + cache.delete(key) + self.message_user(request, msg, level=messages.WARNING) + + # —————— 页脚链接 —————— @admin.register(BaseInfo) class BaseInfoAdmin(ImportExportModelAdmin): diff --git a/base/context_processors.py b/base/context_processors.py index 7ed907d..2717d97 100644 --- a/base/context_processors.py +++ b/base/context_processors.py @@ -1,4 +1,4 @@ -from base.models import BaseInfo, LinkCategory, MainMenu +from base.models import BaseInfo, LinkCategory, MainMenu, PictureLink def site_info(request): @@ -8,9 +8,10 @@ def site_info(request): site_info_obj = BaseInfo.objects.filter(is_active=True).first() link_categories = LinkCategory.objects.filter(is_active=True).prefetch_related('links') menus = MainMenu.objects.filter(visible=True, parent__isnull=True).order_by('order') - + picture_links = PictureLink.objects.filter(is_active=True).order_by('order') return { 'site_info': site_info_obj, 'link_categories': link_categories, 'menus': menus, + 'picture_links': picture_links, } diff --git a/base/migrations/0004_picturelink.py b/base/migrations/0004_picturelink.py new file mode 100644 index 0000000..fc63a6c --- /dev/null +++ b/base/migrations/0004_picturelink.py @@ -0,0 +1,31 @@ +# Generated by Django 6.0.3 on 2026-04-02 01:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0003_baseinfo_delete_footerlink'), + ] + + operations = [ + migrations.CreateModel( + name='PictureLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')), + ('name', models.CharField(max_length=100, verbose_name='网站名称')), + ('picture', models.ImageField(help_text='建议尺寸:280x120', upload_to='picture/%Y/%m/%d/', verbose_name='图片链接')), + ('url', models.URLField(help_text='点击图片要访问的站点地址', verbose_name='链接地址')), + ('order', models.IntegerField(default=0, verbose_name='排序')), + ('is_active', models.BooleanField(default=True, verbose_name='是否启用')), + ], + options={ + 'verbose_name': '图片链接', + 'verbose_name_plural': '图链管理', + 'ordering': ['order', '-created_at'], + }, + ), + ] diff --git a/base/models.py b/base/models.py index fbc2299..797eaa5 100644 --- a/base/models.py +++ b/base/models.py @@ -1,3 +1,4 @@ +from django.core.cache import cache from django.core.exceptions import ValidationError from django.db import models @@ -49,6 +50,42 @@ class FriendLink(BaseEntity): return f"[{self.category.name}] {self.name}" +class PictureLink(BaseEntity): + name = models.CharField("网站名称", max_length=100) + picture = models.ImageField("图片链接", upload_to='picture/%Y/%m/%d/', help_text="建议尺寸:280x120") + url = models.URLField("链接地址", help_text="点击图片要访问的站点地址") + + # 2. 排序和状态 + order = models.IntegerField("排序", default=0) + is_active = models.BooleanField("是否启用", default=True) + + class Meta: + verbose_name = "图片链接" + verbose_name_plural = "图链管理" + ordering = ['order', '-created_at'] + + def __str__(self): + return f"{self.name}" + + def save(self, *args, **kwargs): + # 1. 逻辑判断:如果当前想要启用 + if self.is_active: + # 统计现有的启用数量(排除自己) + active_count = PictureLink.objects.filter(is_active=True).exclude(pk=self.pk).count() + + # 2. 如果已满 4 个 + if active_count >= 4: + self.is_active = False # 强制设为不生效 + + # 3. 【关键】把消息暂存起来,key 用 pk(如果是新建还没 pk,用 id(self) 临时顶替) + # 注意:这里不能直接弹窗,因为没有 request + msg_key = self.pk if self.pk else id(self) + msg = "限制生效:最多只能有 4 个启用的链接,当前对象已被自动设置为【不启用】。" + cache.set(f"picture_count_limit_{msg_key}", msg) # 缓存 30 秒 + + super().save(*args, **kwargs) + + class MainMenu(BaseEntity): # --- 基础信息 --- title = models.CharField("标题", max_length=100) diff --git a/server/settings.py b/server/settings.py index 9f2f076..de3421f 100644 --- a/server/settings.py +++ b/server/settings.py @@ -156,6 +156,25 @@ else: }, } +CACHES = { + 'default': { + # 指定使用本地内存缓存后端 + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + + # 缓存实例的名称,用于区分不同的内存存储 + # 如果只有一个 locmem 缓存,可以忽略此项,但建议设置 + 'LOCATION': 'unique-snowflake', + + # (可选) 默认超时时间,单位:秒 + 'TIMEOUT': 300, + + # (可选) 最大缓存条目数,超过后会根据 LRU 策略淘汰旧数据 + 'OPTIONS': { + 'MAX_ENTRIES': 1000, + 'CULL_FREQUENCY': 3, # 到达 MAX_ENTRIES 时,剔除 1/CULL_FREQUENCY 的数据 + } + } +} # Password validation # https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators diff --git a/static/css/style.css b/static/css/style.css index db31e69..bf61c73 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -241,7 +241,7 @@ body { } .nav-tabs .nav-item { - margin-bottom: -3px; /* 负边距,让 Tab 沉下去盖住强调线 */ + /*margin-bottom: -3px; !* 负边距,让 Tab 沉下去盖住强调线 *!*/ margin-right: 5px; } @@ -251,7 +251,7 @@ body { border-top-right-radius: 4px; /* 4. 字体大小修正 */ - font-size: 15px; + /*font-size: 15px;*/ font-weight: 600; /* 加粗 */ color: #555; /* 未选中时的文字颜色 */ @@ -364,16 +364,16 @@ body { } /* --- 自定义样式结束 --- */ - -.ad-banner { - display: flex; - justify-content: space-between; - padding: 30px 0 15px 0; +/* 可选:给图片加点样式,让它更好看 */ +.link-image { + border-radius: 8px; /* 圆角 */ + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); /* 阴影 */ + transition: transform 0.2s; /* 悬停动画 */ } -.ad-item { - width: 280px; - height: 120px; +/* 鼠标悬停时图片微微放大 */ +.link-image:hover { + transform: scale(1.02); } .grid { diff --git a/templates/base.html b/templates/base.html index 93da50f..9015a8c 100644 --- a/templates/base.html +++ b/templates/base.html @@ -16,7 +16,7 @@

{{ site_info.title }}

{{ site_info.e_title }}

-

CHANGBAI MOUNTAIN FIRE AND RESCUE BRIGADE

+

CHANGBAI MOUNTAIN FIRE AND RESCUE BRIGADE

@@ -159,10 +159,59 @@ + + + + + + + {% block extra_js %}{% endblock %} diff --git a/templates/front/index.html b/templates/front/index.html index 6879fb7..293c5c4 100644 --- a/templates/front/index.html +++ b/templates/front/index.html @@ -5,80 +5,82 @@ {% block title %}首页 - {% endblock %} {% block content %} - -
-
- 标语背景 - {#

对党忠诚 纪律严明 赴汤蹈火 竭诚为民

#} +
+ +
+
+ 标语背景 + {#

对党忠诚 纪律严明 赴汤蹈火 竭诚为民

#} +
+
+
+
+ {{ time_str }} +
+
+
+ + +
+
-
-
-
- {{ time_str }} -
-
-
- - -
-
- - - - - - + + + + + +
-
- - -
-
- {% include 'components/_carousel.html' with carousel_id=carousel.key slides=carousel.data height="300px" %} + + +
+
+ {% include 'components/_carousel.html' with carousel_id=carousel.key slides=carousel.data height="300px" %} +
+
+ {% url "front:news_main" as more_url %} + {% include 'components/_news_card.html' with data=news_data.data unique_id=news_data.key more_url=more_url route="front:news_detail" %} +
-
- {% url "front:news_main" as more_url %} - {% include 'components/_news_card.html' with data=news_data.data unique_id=news_data.key more_url=more_url route="front:news_detail" %} -
-
- -
-
- 我为十五五规划献策 -
-
- 精彩火焰蓝 -
-
- 电动自行车安全 -
-
- 消防安全培训 -
-
- - -
- {% for section in section_data %} - {% if forloop.revcounter == 1 and forloop.counter|add:"0"|divisibleby:"2" == False %} - -
- {% url "front:main_list" main=section.key as card_more_url %} - {% include 'components/_news_card.html' with data=section.data unique_id=section.key more_url=card_more_url %} +
+ {% for link in picture_links %} + + - {% else %} -
- {% url "front:main_list" main=section.key as card_more_url %} - {% include 'components/_news_card.html' with data=section.data unique_id=section.key more_url=card_more_url %} -
- {% endif %} - {% endfor %} + {% endfor %} +
+ + +
+ {% for section in section_data %} + {% if forloop.revcounter == 1 and forloop.counter|add:"0"|divisibleby:"2" == False %} + +
+ {% url "front:main_list" main=section.key as card_more_url %} + {% include 'components/_news_card.html' with data=section.data unique_id=section.key more_url=card_more_url %} +
+ {% else %} +
+ {% url "front:main_list" main=section.key as card_more_url %} + {% include 'components/_news_card.html' with data=section.data unique_id=section.key more_url=card_more_url %} +
+ {% endif %} + {% endfor %} +
{% endblock %} diff --git a/templates/header.html b/templates/header.html deleted file mode 100644 index 9a7cb78..0000000 --- a/templates/header.html +++ /dev/null @@ -1,35 +0,0 @@ -{% load static %} - \ No newline at end of file diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index f5ac0c3..0000000 --- a/templates/index.html +++ /dev/null @@ -1,11 +0,0 @@ -{% load static %} - - - - - 长白山消防支队 - - - - - \ No newline at end of file