From 43f4bd0165a924dd9c2e8eefd3d371aca8006416 Mon Sep 17 00:00:00 2001 From: ngfchl Date: Wed, 1 Apr 2026 20:49:04 +0800 Subject: [PATCH] =?UTF-8?q?update.=20=E5=AE=8C=E6=88=90=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=EF=BC=8C=E6=B8=85=E7=90=86=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=86=97=E4=BD=99=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front/urls.py | 6 +- front/views.py | 356 ++++++---------------------- templates/components/main_menu.html | 2 +- templates/front/list.html | 158 ++++++++---- 4 files changed, 198 insertions(+), 324 deletions(-) diff --git a/front/urls.py b/front/urls.py index 03c4bcb..616c709 100644 --- a/front/urls.py +++ b/front/urls.py @@ -6,16 +6,12 @@ app_name = 'front' # 可选,用于命名空间(如 {% url 'main:index' %} urlpatterns = [ path('', views.index, name='index'), - path('.html', views.info, name='menu'), + path('.html', views.section, name='section'), path('/list.html', views.main_article_list, name='main_list'), path('/list/.html', views.sub_article_list, name='sub_list'), path('about/', views.about, name='about'), path('news/', views.news, name='news'), - path('info/', views.info, name='info'), path('news/.html', views.sub_news_list, name='news_list'), - path('party/', views.party, name='party'), - path('interaction/', views.interaction, name='interaction'), - path('science/', views.science, name='science'), path('article/.html/', views.article_detail, name='article_detail'), path('news/.html/', views.news_detail, name='news_detail'), ] diff --git a/front/views.py b/front/views.py index 94c800f..ac7e57b 100644 --- a/front/views.py +++ b/front/views.py @@ -2,7 +2,8 @@ import traceback from typing import Dict, List from unicodedata import category -from django.db.models import Prefetch +from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage +from django.db.models import Prefetch, Q from django.http import Http404, HttpResponse from django.shortcuts import render, get_object_or_404 from loguru import logger @@ -32,6 +33,7 @@ def article_detail(request, pk: int): logger.error(traceback.format_exc()) return render(request, 'front/error/500.html') + def news_detail(request, pk: int): """ 根据主键 (pk) 获取文章详情 @@ -71,22 +73,10 @@ def index(request): ) # 3. 构建数据 (纯内存操作,速度极快) - section_data = [] - for main in main_sections: - # 收集该主板块下所有子板块的文章 - all_articles = [] - for sub in main.children.all(): - # 使用预取好的 children - # 使用预取好的 latest_articles,并取前7条 - all_articles.extend(sub.latest_articles[:7]) - all_articles.sort(key=lambda x: x.created_at, reverse=True) - # 截取总列表的前7条(如果需要限制总数) - section_data.append({ - "key": main.code, # 建议使用 code 作为 key,比对象本身更安全 - "data": { - main.title: all_articles[:7] - } - }) + section_data = [{ + "key": main.code, + "data": {main.title: articles_qs.filter(section__in=main.children.all()).order_by('-created_at')[:7]} + } for main in main_sections] logger.info(section_data) carousel = { "key": "index", @@ -146,7 +136,7 @@ def news(request): return render(request, 'front/news.html', context) -def info(request, main): +def section(request, main): """信息公开""" logger.info(f"正在访问 {main}") main_section = MainMenu.objects.filter(code=main).first() @@ -169,66 +159,13 @@ def info(request, main): return render(request, 'front/info.html', context=context) -def main_article_list(request, main): - """信息公开""" - logger.info(f"正在访问 {main}") - main_section = MainMenu.objects.filter(code=main).first() - if not main_section: - raise Http404("不存在的板块") - articles_qs = Article.objects.filter(is_published=True).order_by('-created_at') - - sections = main_section.active_children.order_by('order').prefetch_related( - Prefetch('article_set', queryset=articles_qs, to_attr='latest_articles') - ) - section_data = { - "key": main_section, - "data": { - main_section.title: [ - article - for section in sections - for article in section.latest_articles[:7] - ], - } - } - - logger.info(section_data) - context = { - 'main_section': main_section, - 'sections': sections, - 'articles': [ - article - for section in sections - for article in section.latest_articles[:7] - ] - } - return render(request, 'front/list.html', context=context) - - -def sub_news_list(request, sub: str): - logger.info(f"正在访问 {sub}") - sections = NewsSection.objects.all().order_by('order') - logger.info(f"新闻板块: {sections}") - main_section = { - 'title': '新闻中心', - 'code': 'news' - } - sub_section = sections.filter(code=sub).first() - logger.info(f"主板块 {main_section} 子板块 {sub_section}") - if not sub_section or not main_section: - raise Http404("不存在的板块") - context = { - 'main_section': main_section, - 'sub_section': sub_section, - 'sections': sections, - 'articles': sub_section.news_set.filter(is_published=True).order_by('-created_at')[:21] - } - return render(request, 'front/list.html', context=context) - - def main_news_list(request): logger.info("正在访问新闻中心") news_list = News.objects.all() news_sections = NewsSection.objects.all() + # 分页参数 + news_list = custom_pagination(news_list, request) + return render(request, 'front/list.html', { 'main_section': { 'title': '新闻中心', @@ -239,6 +176,70 @@ def main_news_list(request): }) +def custom_pagination(news_list, request): + page = request.GET.get('page', 1) # 当前页码,默认第1页 + per_page = request.GET.get('per_page', 20) # 每页显示条数,默认20 + # 创建分页器 + paginator = Paginator(news_list, per_page) + try: + # 获取当前页数据 + news_list = paginator.page(page) + except PageNotAnInteger: + # 如果页码不是整数,返回第一页 + news_list = paginator.page(1) + except EmptyPage: + # 如果页码超出范围,返回最后一页 + news_list = paginator.page(paginator.num_pages) + return news_list + + +def sub_news_list(request, sub: str): + logger.info(f"正在访问 {sub}") + sections = NewsSection.objects.all().order_by('order') + logger.info(f"新闻板块: {sections}") + main_section = { + 'title': '新闻中心', + 'code': 'news' + } + sub_section = sections.filter(code=sub).first() + logger.info(f"主板块 {main_section} 子板块 {sub_section}") + if not sub_section or not main_section: + raise Http404("不存在的板块") + news_list = sub_section.news_set.filter(is_published=True).order_by('-created_at')[:21] + news_list = custom_pagination(news_list, request) + + context = { + 'main_section': main_section, + 'sub_section': sub_section, + 'sections': sections, + 'articles': news_list + } + logger.info(context) + return render(request, 'front/list.html', context=context) + + +def main_article_list(request, main): + """信息公开""" + logger.info(f"正在访问 {main}") + main_section = MainMenu.objects.filter(code=main).first() + if not main_section: + raise Http404("不存在的板块") + articles_qs = Article.objects.filter(is_published=True, section__in=main_section.active_children).order_by( + '-created_at') + + sections = main_section.active_children.order_by('order').prefetch_related( + Prefetch('article_set', queryset=articles_qs, to_attr='latest_articles') + ) + + articles = custom_pagination(articles_qs, request) + context = { + 'main_section': main_section, + 'sections': sections, + 'articles': articles, + } + return render(request, 'front/list.html', context=context) + + def sub_article_list(request, main: str, sub: str): """信息公开""" logger.info(f"正在访问 {main}") @@ -248,213 +249,12 @@ def sub_article_list(request, main: str, sub: str): logger.info(f"主板块 {main_section} 子板块 {sub_section}") if not sub_section or not main_section: raise Http404("不存在的板块") + articles = sub_section.article_set.filter(is_published=True).order_by('-created_at') + articles = custom_pagination(articles, request) context = { 'main_section': main_section, 'sub_section': sub_section, 'sections': sections.filter(parent__code=main), - 'articles': sub_section.article_set.filter(is_published=True).order_by('-created_at')[:21] + 'articles': articles } return render(request, 'front/list.html', context=context) - - -def service(request): - """办事服务""" - q = request.GET.get('q') or "办事指南" - sections = [ - "办事指南", - "政务服务", - "资料下载", - "办事统计", - ] - data = { - "办事指南": [ - {'title': '中共长白山保护开发区工委办公室关于印发杨文慧同志在 2026...', 'date': '2026-03-05'}, - {'title': '长白山管委会办公室关于印发《长白山保护开发区落实<吉林省...', 'date': '2026-02-28'}, - {'title': '长白山保护开发区管理委员会 2025 年度行政执法工作报告', 'date': '2026-01-30'}, - {'title': '长白山管委会办公室关于印发《美丽长白山建设行动方案(202...', 'date': '2025-12-31'}, - {'title': '长白山管委会办公室关于印发《长白山保护开发区碳达峰实施...', 'date': '2025-12-31'}, - {'title': '《长白山保护开发区防雷减灾管理办法》政策解读', 'date': '2025-12-12'}, - ], - "政务服务": [ - {'title': '《长白山保护开发区防雷减灾管理办法》政策解读', 'date': '2025-12-12'}, - {'title': '《长白山保护开发区旅游漂流活动管理规范》政策解读', 'date': '2025-07-23'}, - {'title': '《长白山 40 米射电望远镜电磁波宁静区保护办法》政策解读', 'date': '2025-07-23'}, - {'title': '《长白山保护开发区古树名木管理办法(试行)》政策解读', 'date': '2025-06-18'}, - {'title': '《长白山保护开发区公共租赁住房管理办法》政策解读', 'date': '2025-04-08'}, - {'title': '《长白山保护开发区旅游民宿管理与服务规范(试行)》政策解读', 'date': '2024-12-31'}, - ], - "资料下载": [ - {'title': '关于第二轮中央生态环境保护督察第四十一项整改任务销号...', 'date': '2026-03-11'}, - {'title': '关于第二轮中央生态环境保护督察第三十八项整改任务销号...', 'date': '2026-03-11'}, - {'title': '公告送达通知', 'date': '2026-03-10'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - ] - } - context = { - "sections": sections, - "data_list": data.get(q), - "q": q, - } - return render(request, 'front/service.html', context) - - -def party(request): - """党建引领""" - sections: List[Dict] = [ - { - "key": "party_work", - "data": { - "党建工作": [ - {'title': '关于第二轮中央生态环境保护督察第四十一项整改任务销号...', 'date': '2026-03-11'}, - {'title': '关于第二轮中央生态环境保护督察第三十八项整改任务销号...', 'date': '2026-03-11'}, - {'title': '公告送达通知', 'date': '2026-03-10'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - ] - } - }, - { - "key": "integrity", - "data": { - "党风廉政": [ - # ⚠️ 请替换为真实的法律法规数据 - {'title': '关于第二轮中央生态环境保护督察第四十一项整改任务销号...', 'date': '2026-03-11'}, - {'title': '关于第二轮中央生态环境保护督察第三十八项整改任务销号...', 'date': '2026-03-11'}, - {'title': '公告送达通知', 'date': '2026-03-10'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - ] - } - }, - { - "key": "advance", - "data": { - "先进典型": [ - {'title': '中共长白山保护开发区工委办公室关于印发杨文慧同志在 2026...', 'date': '2026-03-05'}, - {'title': '长白山管委会办公室关于印发《长白山保护开发区落实<吉林省...', 'date': '2026-02-28'}, - {'title': '长白山保护开发区管理委员会 2025 年度行政执法工作报告', 'date': '2026-01-30'}, - {'title': '长白山管委会办公室关于印发《美丽长白山建设行动方案(202...', 'date': '2025-12-31'}, - {'title': '长白山管委会办公室关于印发《长白山保护开发区碳达峰实施...', 'date': '2025-12-31'}, - {'title': '《长白山保护开发区防雷减灾管理办法》政策解读', 'date': '2025-12-12'}, - ] - } - }, - - ] - carousel: Dict = { - "key": "index", - "data": [ - { - "id": 0, - "image_url": "/media/upload/images/2022/12/15/11146164001.jpg", - "title": "First slide label", - # "description": "Some representative placeholder content for the first slide." - }, - { - "id": 1, - "image_url": "/media/upload/images/2022/12/15/11142163743.jpg", - "title": "Second slide label", - # "description": "Some representative placeholder content for the second slide." - }, - { - "id": 2, - "image_url": "/media/upload/images/2022/12/15/11150164804.jpg", - "title": "Third slide label", - # "description": "Some representative placeholder content for the third slide." - } - ] - } - sections.insert(1, carousel) - context = { - 'sections': sections, - } - - return render(request, 'front/party.html', context) - - -def interaction(request): - """互动交流""" - q = request.GET.get('q') or "专家访谈" - sections = [ - "专家访谈", - "调查征集", - "在线咨询", - ] - data = { - "专家访谈": [ - {'title': '中共长白山保护开发区工委办公室关于印发杨文慧同志在 2026...', 'date': '2026-03-05'}, - {'title': '长白山管委会办公室关于印发《长白山保护开发区落实<吉林省...', 'date': '2026-02-28'}, - {'title': '长白山保护开发区管理委员会 2025 年度行政执法工作报告', 'date': '2026-01-30'}, - {'title': '长白山管委会办公室关于印发《美丽长白山建设行动方案(202...', 'date': '2025-12-31'}, - {'title': '长白山管委会办公室关于印发《长白山保护开发区碳达峰实施...', 'date': '2025-12-31'}, - {'title': '《长白山保护开发区防雷减灾管理办法》政策解读', 'date': '2025-12-12'}, - ], - "调查征集": [ - {'title': '《长白山保护开发区防雷减灾管理办法》政策解读', 'date': '2025-12-12'}, - {'title': '《长白山保护开发区旅游漂流活动管理规范》政策解读', 'date': '2025-07-23'}, - {'title': '《长白山 40 米射电望远镜电磁波宁静区保护办法》政策解读', 'date': '2025-07-23'}, - {'title': '《长白山保护开发区古树名木管理办法(试行)》政策解读', 'date': '2025-06-18'}, - {'title': '《长白山保护开发区公共租赁住房管理办法》政策解读', 'date': '2025-04-08'}, - {'title': '《长白山保护开发区旅游民宿管理与服务规范(试行)》政策解读', 'date': '2024-12-31'}, - ], - "在线咨询": [ - {'title': '关于第二轮中央生态环境保护督察第四十一项整改任务销号...', 'date': '2026-03-11'}, - {'title': '关于第二轮中央生态环境保护督察第三十八项整改任务销号...', 'date': '2026-03-11'}, - {'title': '公告送达通知', 'date': '2026-03-10'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - ] - } - context = { - "sections": sections, - "data_list": data.get(q), - "q": q, - } - return render(request, 'front/interaction.html', context) - - -def science(request): - """消防科普""" - q = request.GET.get('q') or "数字消防" - sections = [ - "数字消防", - "火灾预防", - "自救逃生", - ] - data = { - "数字消防": [ - {'title': '中共长白山保护开发区工委办公室关于印发杨文慧同志在 2026...', 'date': '2026-03-05'}, - {'title': '长白山管委会办公室关于印发《长白山保护开发区落实<吉林省...', 'date': '2026-02-28'}, - {'title': '长白山保护开发区管理委员会 2025 年度行政执法工作报告', 'date': '2026-01-30'}, - {'title': '长白山管委会办公室关于印发《美丽长白山建设行动方案(202...', 'date': '2025-12-31'}, - {'title': '长白山管委会办公室关于印发《长白山保护开发区碳达峰实施...', 'date': '2025-12-31'}, - {'title': '《长白山保护开发区防雷减灾管理办法》政策解读', 'date': '2025-12-12'}, - ], - "火灾预防": [ - {'title': '《长白山保护开发区防雷减灾管理办法》政策解读', 'date': '2025-12-12'}, - {'title': '《长白山保护开发区旅游漂流活动管理规范》政策解读', 'date': '2025-07-23'}, - {'title': '《长白山 40 米射电望远镜电磁波宁静区保护办法》政策解读', 'date': '2025-07-23'}, - {'title': '《长白山保护开发区古树名木管理办法(试行)》政策解读', 'date': '2025-06-18'}, - {'title': '《长白山保护开发区公共租赁住房管理办法》政策解读', 'date': '2025-04-08'}, - {'title': '《长白山保护开发区旅游民宿管理与服务规范(试行)》政策解读', 'date': '2024-12-31'}, - ], - "自救逃生": [ - {'title': '关于第二轮中央生态环境保护督察第四十一项整改任务销号...', 'date': '2026-03-11'}, - {'title': '关于第二轮中央生态环境保护督察第三十八项整改任务销号...', 'date': '2026-03-11'}, - {'title': '公告送达通知', 'date': '2026-03-10'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - {'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'}, - ] - } - context = { - "sections": sections, - "data_list": data.get(q), - "q": q, - } - return render(request, 'front/science.html', context) diff --git a/templates/components/main_menu.html b/templates/components/main_menu.html index fd9b083..73ba2e5 100644 --- a/templates/components/main_menu.html +++ b/templates/components/main_menu.html @@ -4,7 +4,7 @@ {% endfor %} diff --git a/templates/front/list.html b/templates/front/list.html index 9f1737a..3e461f2 100644 --- a/templates/front/list.html +++ b/templates/front/list.html @@ -39,7 +39,7 @@
  • -
    {{ main_section.title }}
    +
    {{ main_section.title }}
  • {% for sec in sections %} @@ -77,7 +77,7 @@ {#
    #} {#
    #} {# #} -
      +
        {# items 就是当前 key 对应的列表数据,直接使用 #} {% if articles %} {% for item in articles %} @@ -94,25 +94,99 @@
      • 暂无数据
      • {% endif %}
      + + + - -
      -
        +
          +
        • + 共 {{ articles.paginator.count }} 条 +
        • + + {% if articles.has_previous %}
        • - - + 首页 +
        • + {% else %} +
        • + 首页 +
        • + {% endif %} + + + {% if articles.has_previous %} +
        • + + 上一页
        • -
        • 1
        • -
        • 2
        • -
        • 3
        • + {% else %} +
        • + 上一页 +
        • + {% endif %} + + {# 页码核心逻辑 #} + {% for i in articles.paginator.page_range %} + {% if articles.number == i %} + {# 当前页 #} +
        • + {{ i }} +
        • + {% else %} + {# 显示规则:第1-2页 | 当前页前后各2页 | 最后2页 #} + {% if i == 1 or i == 2 or i == articles.paginator.num_pages or i == articles.paginator.num_pages|add:"-1" or i >= articles.number|add:"-2" and i <= articles.number|add:"2" %} +
        • + {{ i }} +
        • + {% elif i == articles.number|add:"-3" or i == articles.number|add:"3" %} + {# 省略号只出现一次 #} +
        • + ... +
        • + {% endif %} + {% endif %} + {% endfor %} + + + {% if articles.has_next %}
        • - - + + 下一页
        • -
        -
      + {% else %} +
    • + 下一页 +
    • + {% endif %} + + + {% if articles.has_next %} +
    • + + 尾页 + +
    • + {% else %} +
    • + 尾页 +
    • + {% endif %} + {# 6. 跳转功能 (模拟图片样式:前往 [输入框] 页) #} + {#
    • #} + {# 前往#} + {#
    • #} + {#
    • #} + {# #} + {#
    • #} + {#
    • {# 这里隐藏一个提交按钮,主要靠JS触发 #} + {# #} + {#
    • #} +
    @@ -123,7 +197,7 @@ .section-header-card { position: relative; width: 100%; - {#max-width: 800px; /* 模拟图片中的长宽比 */#} min-height: 720px; /* 设置一个保底高度 */ + min-height: 720px; /* 设置一个保底高度 */ height: auto; /* 高度随内容增加而增加 */ background-color: #ffffff; border-radius: 12px; /* 大圆角 */ @@ -133,7 +207,6 @@ flex-direction: column; align-items: center; padding-left: 30px; - {#justify-content: space-between;#} } /* 左侧内容区域 */ @@ -145,6 +218,35 @@ width: 100%; } + + .list-unstyled { + flex-grow: 1; /* 使列表占满剩余的空间 */ + padding-right: 38px; + margin-left: 0; + width: 100%; + } + + .pagination-wrapper { + display: flex; + justify-content: end; /* 分页内容左右对齐 */ + align-items: center; + margin: 10px auto -20px; + + padding: 5px 0; + border-radius: 12px; /* 大圆角 */ + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08) !important; /* 柔和阴影 */ + } + + .page-link { + border: none !important; + color: #6C757D; + } + + .page-item.active .page-link { + background-color: #23408A; + border-color: #23408A; + } + /* 标题部分 */ .header-title { font-size: 20px; @@ -175,30 +277,6 @@ margin: 0; } - /* --- 右侧装饰块 --- */ - .right-decoration { - position: absolute; - right: 0; - top: 0; - bottom: 0; - width: 60px; /* 装饰块宽度 */ - display: flex; - flex-direction: column; - } - - /* 上方深色块 */ - .deco-top { - flex: 1; /* 占据上半部分 */ - background-color: #5a6da3; /* 深蓝灰色 */ - min-height: 50%; - } - - /* 下方浅色块 */ - .deco-bottom { - flex: 1; /* 占据下半部分 */ - background-color: #eef4ff; /* 极浅的蓝色 */ - min-height: 50%; - } {% endblock %}