init. 初始化项目,并初步完成前端模板样式

This commit is contained in:
2026-03-26 11:08:42 +08:00
commit af9d7a676f
116 changed files with 5266 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
{% comment %}
用法: {% include "includes/carousel.html" with carousel_id="mainBanner" slides=carousel_data height="500px" show_caption=True %}
参数说明:
- carousel_id: 唯一ID,用于区分页面上的多个轮播图 (必填)
- slides: 列表,包含字典 {'image_url': '...', 'title': '...', 'description': '...'} (必填)
- height: 轮播图高度,默认 400px (可选)
- show_caption: 是否显示文字描述,默认 True (可选)
- object_fit: 图片填充模式,默认 'cover' (可选: cover, contain, fill)
{% endcomment %}
{% load static %}
<div id="{{ carousel_id }}" class="carousel slide" data-ride="carousel">
<!-- 1. 指示器 (Indicators) -->
{% if slides|length > 1 %}
<ol class="carousel-indicators">
{% for slide in slides %}
<li data-target="#{{ carousel_id }}" data-slide-to="{{ forloop.counter0 }}"
{% if forloop.first %}class="active"{% endif %}></li>
{% endfor %}
</ol>
{% endif %}
<!-- 2. 图片区域 (Inner) -->
<div class="carousel-inner" style="height: {{ height|default:'400px' }}; background: #f8f9fa;">
{% for slide in slides %}
<div class="carousel-item {% if forloop.first %}active{% endif %}" style="height: 100%;">
<!-- 图片 -->
<img src="{{ slide.image_url }}"
class="d-block w-100 h-100"
alt="{{ slide.title|default:'Slide image' }}"
style="object-fit: {{ object_fit|default:'cover' }}; width: 100%; height: 100%;">
<!-- 文字描述 (可选) -->
{% if show_caption|default:True and slide.title %}
<div class="carousel-caption d-none d-md-block"
style="background: rgba(0,0,0,0.3); border-radius: 8px; padding: 10px 20px; bottom: 20px;">
<h5 class="text-white text-shadow">{{ slide.title }}</h5>
{% if slide.description %}
<p class="text-white text-shadow">{{ slide.description }}</p>
{% endif %}
</div>
{% endif %}
</div>
{% empty %}
<!-- 空状态占位 -->
<div class="carousel-item active" style="height: 100%; display: flex; align-items: center; justify-content: center; color: #999;">
<span>暂无轮播图片</span>
</div>
{% endfor %}
</div>
<!-- 3. 控制按钮 (Controls) - 仅当多于1张图时显示 -->
{% if slides|length > 1 %}
<button class="carousel-control-prev" type="button" data-target="#{{ carousel_id }}" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-target="#{{ carousel_id }}" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</button>
{% endif %}
</div>
<style>
/* 可选:增加文字阴影以确保在亮色图片上可见 */
.text-shadow {
text-shadow: 0 2px 4px rgba(0,0,0,0.6);
}
/* 修复 Bootstrap 默认 carousel-item 高度问题 */
.carousel-inner {
position: relative;
overflow: hidden;
}
.carousel-item {
height: 100%;
}
</style>
+66
View File
@@ -0,0 +1,66 @@
<!-- templates/components/_news_card.html -->
{% load dict_tools %} {# 确保加载了过滤器,虽然这里可能不再需要 get_item,但保留以防万一 #}
<div class="news-card">
<div class="custom-tabs-header">
<div class="tabs-header-wrapper">
<ul class="nav nav-tabs" id="newsTab_{{ unique_id }}" role="tablist">
{# 核心修改:直接遍历 data 字典的 key #}
{% for tab_id, items in data.items %}
<li class="nav-item">
{# 确定显示名称:如果有 labels 字典则取 labels.tab_id,否则直接用 tab_id (或进行capitalize处理) #}
{% with display_name=tab_id %}
{# 如果 default 返回的是英文 key,可以在这里做简单的格式化,比如首字母大写,或者保持原样 #}
<a class="nav-link {% if forloop.first %}active{% endif %}"
id="{{ tab_id }}-tab_{{ unique_id }}"
data-toggle="tab"
href="#{{ tab_id }}_{{ unique_id }}"
role="tab"
aria-selected="{% if forloop.first %}true{% else %}false{% endif %}">
{{ display_name }}
</a>
{% endwith %}
</li>
{% endfor %}
</ul>
<!-- 右侧:更多链接 (独立于 ul) -->
<a class="more-link-standalone"
href="{{ more_url|default:'#' }}">
更多 &gt;
</a>
</div>
</div>
<div class="tab-content news-list-body" id="newsTabContent_{{ unique_id }}">
{# 再次遍历 data 生成内容面板 #}
{% for tab_id, items in data.items %}
<div class="tab-pane fade {% if forloop.first %}show active{% endif %}"
id="{{ tab_id }}_{{ unique_id }}"
role="tabpanel"
aria-labelledby="{{ tab_id }}-tab_{{ unique_id }}">
<ul class="list-unstyled mb-0">
{# items 就是当前 key 对应的列表数据,直接使用 #}
{% if items %}
{% for item in items %}
<li class="news-item">
<div class="news-title-wrapper">
<span class="bullet-point"></span>
<span class="news-title-text"
title="{{ item.title }}">{{ item.title|truncatechars:30 }}</span>
</div>
<span class="news-date">{{ item.date }}</span>
</li>
{% endfor %}
{% else %}
<li class="text-muted text-center py-2">暂无数据</li>
{% endif %}
</ul>
</div>
{% endfor %}
</div>
</div>