feat(portal): 门户左侧栏目导航+首页视觉升级+主题正名批次-PortalSideNav模型+attachCategoryNavigation注入doCategory/doArticle三件套categoryPath/navTopId/sideNav(站点快照树推导零新增查询,home/search不注入);7主题侧栏两栏markup+窄屏横滚+顶导航祖先高亮+二级下拉当前项高亮+面包屑全路径;cms_category.home_style全链路(news_grid 16条8x2日期前缀/media_focus形态)+PortalListData.Item补source来源徽标四处装配;Banner机制gallery展示位→galleryBanners四列大图轮播(自由字符串零DDL);页脚config 12新键(footer_addresses多校区/qr_*/social_*含URL校验,footerAddressLines由PortalSiteSnapshot.of拆行派生);新增展示型皮肤包campus-glow;fresh-mint2正名fresh-mint(theme.json/头注释同步);AttachmentService scene白名单加category(单页富文本贴图免清孤儿);新增PortalSideNavIT 8+PortalHomeBlocksIT 3,CategoryServiceIT/SiteServiceIT/PortalSsrIT/ThemeContractIT等单类独跑全绿;附sql/clear_cms_data.sql全量清库脚本(清cms_*六表留平台账号/主题包/上传文件,测试数据重走用)
build / build-push (push) Successful in 1m47s
build / build-push (push) Successful in 1m47s
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" lang="zh-CN">
|
||||
<head th:replace="~{${themeBase} + '/fragments/head' :: head}"></head>
|
||||
<body>
|
||||
<header th:replace="~{${themeBase} + '/fragments/header' :: header}"></header>
|
||||
|
||||
<main class="cg-home" id="main-content">
|
||||
<!-- 首页轮播位(cms_banner position=home;设计尺寸 1920×560,见 theme.json bannerSize) -->
|
||||
<section class="cg-banner" th:if="${!#lists.isEmpty(banners)}" aria-label="焦点图片">
|
||||
<div class="cg-banner-slides">
|
||||
<a class="cg-banner-slide" th:each="b, stat : ${banners}"
|
||||
th:classappend="${stat.first} ? 'active'"
|
||||
th:href="${b.linkUrl}" th:title="${b.title}">
|
||||
<img th:src="${b.imageUrl}" th:alt="${b.title}">
|
||||
<span class="cg-banner-cap" th:text="${b.title}">标题</span>
|
||||
</a>
|
||||
</div>
|
||||
<button class="cg-banner-arrow prev" type="button" aria-label="上一张" th:if="${#lists.size(banners) > 1}">‹</button>
|
||||
<button class="cg-banner-arrow next" type="button" aria-label="下一张" th:if="${#lists.size(banners) > 1}">›</button>
|
||||
<div class="cg-banner-dots" th:if="${#lists.size(banners) > 1}">
|
||||
<button th:each="b, stat : ${banners}" th:classappend="${stat.first} ? 'active'"
|
||||
th:aria-label="${'第' + (stat.count) + '张'}"></button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 要闻速递横条:置顶文章横向无缝滚动(hover 暂停) -->
|
||||
<section class="cg-ticker" th:if="${!#lists.isEmpty(topArticles)}" aria-label="要闻速递">
|
||||
<div class="cg-container cg-ticker-inner">
|
||||
<span class="cg-ticker-label">要闻速递</span>
|
||||
<div class="cg-ticker-viewport">
|
||||
<div class="cg-ticker-track">
|
||||
<a class="cg-ticker-item" th:each="item : ${topArticles}" th:href="${url.article(item.id)}">
|
||||
<span class="cg-ticker-dot" aria-hidden="true"></span>
|
||||
<span th:text="${item.title}">要闻标题</span>
|
||||
</a>
|
||||
<a class="cg-ticker-item" th:each="item : ${topArticles}" th:href="${url.article(item.id)}" aria-hidden="true">
|
||||
<span class="cg-ticker-dot" aria-hidden="true"></span>
|
||||
<span th:text="${item.title}">要闻标题</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 一级栏目区块(docs/12):按栏目 homeStyle 三种形态渲染,栏目顺序即首页板块顺序 -->
|
||||
<th:block th:each="block : ${categoryBlocks}">
|
||||
<!-- 形态一:双栏新闻卡(homeStyle=news_grid)——全幅背景 + 毛玻璃卡 + 双栏日期列表 -->
|
||||
<section class="cg-newshot" th:if="${block.homeStyle == 'news_grid'}"
|
||||
th:with="newsBg=${site.config['news_bg_image']}" aria-label="栏目区块">
|
||||
<div class="cg-newshot-bg" th:if="${!#strings.isEmpty(newsBg)}"
|
||||
th:style="|background-image:url(${url.upload(newsBg)})|"></div>
|
||||
<div class="cg-container">
|
||||
<div class="cg-newshot-card">
|
||||
<div class="cg-sec-head">
|
||||
<h2 th:text="${block.category.name}">校园时讯</h2>
|
||||
<a class="cg-more-circle" th:href="${block.moreUrl}" aria-label="更多">
|
||||
<svg viewBox="0 0 24 24" width="18" height="18" focusable="false" aria-hidden="true">
|
||||
<path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" d="M5 12h14M13 6l6 6-6 6"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<ul class="cg-news-grid" th:if="${!#lists.isEmpty(block.items)}">
|
||||
<li th:each="item : ${block.items}">
|
||||
<span class="cg-news-date" th:if="${item.publishTime != null}"
|
||||
th:text="${#temporals.format(item.publishTime, 'MM-dd')}">09-09</span>
|
||||
<a class="cg-news-title" th:href="${url.article(item.id)}" th:text="${item.title}">文章标题</a>
|
||||
<span class="cg-top-badge" th:if="${item.topmost == 1}">置顶</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="cg-empty" th:if="${#lists.isEmpty(block.items)}">
|
||||
<p>栏目暂无内容</p>
|
||||
<p class="cg-empty-hint">内容发布后将在此展示</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 形态二:媒体聚焦列表(homeStyle=media_focus)——来源徽标 + 标题双栏 -->
|
||||
<section class="cg-media" th:if="${block.homeStyle == 'media_focus'}" aria-label="栏目区块">
|
||||
<div class="cg-container">
|
||||
<div class="cg-media-card">
|
||||
<div class="cg-sec-head">
|
||||
<h2 th:text="${block.category.name}">媒体聚焦</h2>
|
||||
<a class="cg-more-circle" th:href="${block.moreUrl}" aria-label="更多">
|
||||
<svg viewBox="0 0 24 24" width="18" height="18" focusable="false" aria-hidden="true">
|
||||
<path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" d="M5 12h14M13 6l6 6-6 6"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<ul class="cg-media-grid" th:if="${!#lists.isEmpty(block.items)}">
|
||||
<li th:each="item : ${block.items}">
|
||||
<span class="cg-source-badge" th:if="${!#strings.isEmpty(item.source)}"
|
||||
th:text="${item.source}">媒体来源</span>
|
||||
<a class="cg-media-title" th:href="${url.article(item.id)}" th:text="${item.title}">文章标题</a>
|
||||
<span class="cg-top-badge" th:if="${item.topmost == 1}">置顶</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="cg-empty" th:if="${#lists.isEmpty(block.items)}">
|
||||
<p>栏目暂无内容</p>
|
||||
<p class="cg-empty-hint">内容发布后将在此展示</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 形态三:默认卡(homeStyle 空)——featured 首条 + 行式列表,旧栏目保持常规呈现 -->
|
||||
<section class="cg-block" th:if="${block.homeStyle == null or block.homeStyle == ''}" aria-label="栏目区块">
|
||||
<div class="cg-container">
|
||||
<div class="cg-block-card">
|
||||
<div class="cg-sec-head">
|
||||
<h2 th:text="${block.category.name}">栏目名</h2>
|
||||
<a class="cg-more-text" th:href="${block.moreUrl}">更多 ></a>
|
||||
</div>
|
||||
<div class="cg-block-cols" th:if="${!#lists.isEmpty(block.items)}">
|
||||
<a class="cg-block-featured" th:with="feat=${block.items[0]}" th:href="${url.article(feat.id)}">
|
||||
<span class="cg-feat-cover" th:if="${feat.coverImage != null}">
|
||||
<img th:src="${url.upload(feat.coverImage)}" th:alt="${feat.title}">
|
||||
</span>
|
||||
<span class="cg-feat-body">
|
||||
<span class="cg-feat-title" th:text="${feat.title}">头条标题</span>
|
||||
<span class="cg-feat-summary" th:if="${!#strings.isEmpty(feat.summary)}"
|
||||
th:text="${feat.summary}">摘要</span>
|
||||
<span class="cg-feat-meta">
|
||||
<time th:if="${feat.publishTime != null}"
|
||||
th:text="${#temporals.format(feat.publishTime, 'yyyy-MM-dd')}">2026-01-01</time>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="cg-block-list">
|
||||
<li th:each="item, stat : ${block.items}" th:if="${stat.index > 0}">
|
||||
<a th:href="${url.article(item.id)}" th:text="${item.title}">文章标题</a>
|
||||
<time th:if="${item.publishTime != null}"
|
||||
th:text="${#temporals.format(item.publishTime, 'MM-dd')}">01-01</time>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="cg-empty" th:if="${#lists.isEmpty(block.items)}">
|
||||
<p>栏目暂无内容</p>
|
||||
<p class="cg-empty-hint">内容发布后将在此展示</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</th:block>
|
||||
|
||||
<!-- 线上展厅(cms_banner position=gallery;设计尺寸 800×520;每行列数由主题参数 galleryCols 控制) -->
|
||||
<section class="cg-gallery" th:if="${!#lists.isEmpty(galleryBanners)}" aria-label="线上展厅">
|
||||
<div class="cg-container">
|
||||
<div class="cg-gallery-head">
|
||||
<h2 th:text="${site.config['gallery_title'] ?: '线上展厅'}">线上展厅</h2>
|
||||
<p class="cg-gallery-sub" th:text="${site.config['gallery_subtitle'] ?: 'Online Exhibition Hall'}">Online Exhibition Hall</p>
|
||||
</div>
|
||||
<div class="cg-gallery-stage"
|
||||
th:classappend="${'cg-gallery-cols-' + (themeParams['galleryCols'] ?: '4')}"
|
||||
th:attr="data-cols=${themeParams['galleryCols'] ?: '4'}">
|
||||
<div class="cg-gallery-track">
|
||||
<a class="cg-gallery-item" th:each="g : ${galleryBanners}" th:href="${g.linkUrl}"
|
||||
th:title="${g.title}">
|
||||
<img th:src="${g.imageUrl}" th:alt="${g.title}">
|
||||
<span class="cg-gallery-cap" th:if="${!#strings.isEmpty(g.title)}"
|
||||
th:text="${g.title}">作品标题</span>
|
||||
</a>
|
||||
</div>
|
||||
<button class="cg-gallery-arrow prev" type="button" aria-label="上一页" th:if="${#lists.size(galleryBanners) > 1}">‹</button>
|
||||
<button class="cg-gallery-arrow next" type="button" aria-label="下一页" th:if="${#lists.size(galleryBanners) > 1}">›</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer th:replace="~{${themeBase} + '/fragments/footer' :: footer}"></footer>
|
||||
<script th:src="${url.asset('js/main.js')}"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user