build / build-push (push) Successful in 51s
以 default 为基座(文件最全:含事项库 service/guide 两模板),设计语言与配色取自 真实高校官网 CSS(浙理工 #0558A5+橙、信阳农林 #1C6E19+麦穗金、信阳师大 #008D3F+暖橙)。 三包均自带九段 home-blocks、:root 契约变量别名、中文防塌列三件套、真实实拍截图 (1920 无头截图缩样)。 - UniversitySkinContractTest(7 用例):九段 fragment/homeStyle 分发/防塌列/变量别名/ 层序/自有截图/主色色域(蓝或绿通道主导,粉紫禁入) - ThemeRegistryTest +哨兵:三包注册成功且主色与 default/scholar-blue 及彼此互异 - jade-normal 修复:news_grid 全宽封面变体把正文列压成 0 宽致 390px 溢出 47px, 增 .jn-feat-a--stack 纵向变体,复测 overflowX=0 - 门禁:ThemeContractIT 14 主题×7 路由全绿;全量 mvn test 393/393 绿
112 lines
6.4 KiB
HTML
112 lines
6.4 KiB
HTML
<!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>
|
||
|
||
<!-- 服务中心(事项库 §6.1 契约):serviceList / serviceFilters / activeFilters / q;
|
||
筛选与分页 URL 全部后端预生成(facets[].url / pageUrls[].url),模板禁止手拼 query -->
|
||
<main class="af-page af-container" id="main-content">
|
||
<div class="af-page-card af-svc-page">
|
||
<nav class="af-crumb" aria-label="面包屑">
|
||
<a th:href="${url.home()}">首页</a>
|
||
<span class="af-crumb-sep" aria-hidden="true">/</span>
|
||
<span class="af-crumb-current">服务中心</span>
|
||
</nav>
|
||
|
||
<h1 class="af-page-title">服务中心</h1>
|
||
|
||
<!-- P1-4 停机空态:svc-hall 不可达时降级渲染(200),不出 500 错误页 -->
|
||
<div class="af-empty af-svc-unavailable" th:if="${svcUnavailable}">
|
||
<p>事项服务暂时不可用,请稍后再试</p>
|
||
<p class="af-empty-hint">事项数据服务暂不可达,稍后刷新即可恢复</p>
|
||
</div>
|
||
|
||
<div class="af-svc-filters"
|
||
th:if="${!svcUnavailable and (!#lists.isEmpty(serviceFilters.objects) or !#lists.isEmpty(serviceFilters.categories) or !#lists.isEmpty(serviceFilters.depts))}">
|
||
<div class="af-svc-filter-group" th:if="${!#lists.isEmpty(serviceFilters.objects)}">
|
||
<span class="af-svc-filter-label">服务对象</span>
|
||
<div class="af-svc-filter-options">
|
||
<a class="af-svc-chip" th:each="opt : ${serviceFilters.objects}"
|
||
th:classappend="${opt.active} ? 'active'" th:href="${opt.url}">
|
||
<span th:text="${opt.name}">对象</span><em th:text="${opt.count}">0</em>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
<div class="af-svc-filter-group" th:if="${!#lists.isEmpty(serviceFilters.categories)}">
|
||
<span class="af-svc-filter-label">事项类别</span>
|
||
<div class="af-svc-filter-options">
|
||
<a class="af-svc-chip" th:each="opt : ${serviceFilters.categories}"
|
||
th:classappend="${opt.active} ? 'active'" th:href="${opt.url}">
|
||
<span th:text="${opt.name}">类别</span><em th:text="${opt.count}">0</em>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
<div class="af-svc-filter-group" th:if="${!#lists.isEmpty(serviceFilters.depts)}">
|
||
<span class="af-svc-filter-label">服务部门</span>
|
||
<div class="af-svc-filter-options">
|
||
<a class="af-svc-chip" th:each="opt : ${serviceFilters.depts}"
|
||
th:classappend="${opt.active} ? 'active'" th:href="${opt.url}">
|
||
<span th:text="${opt.name}">部门</span><em th:text="${opt.count}">0</em>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="af-svc-toolbar" th:if="${!svcUnavailable}">
|
||
<form class="af-svc-search" th:action="${url.serviceList()}" method="get" role="search">
|
||
<input type="search" name="q" th:value="${q}" placeholder="搜索事项名称 / 简介" maxlength="64">
|
||
<button type="submit">搜索</button>
|
||
</form>
|
||
<a class="af-svc-clear" th:if="${activeFilters.hasAny}" th:href="${activeFilters.clearUrl}">清除筛选</a>
|
||
</div>
|
||
|
||
<ul class="af-svc-list" th:if="${!svcUnavailable}">
|
||
<li th:each="it : ${serviceList.items}">
|
||
<a class="af-svc-item" th:href="${url.serviceItem(it.id)}">
|
||
<span class="af-svc-item-cover" th:if="${it.coverImage != null}">
|
||
<img th:src="${url.upload(it.coverImage)}" th:alt="${it.title}">
|
||
</span>
|
||
<span class="af-svc-item-body">
|
||
<span class="af-svc-item-title">
|
||
<span class="af-svc-item-name" th:text="${it.title}">事项名称</span>
|
||
<span class="af-svc-tag online" th:if="${it.onlineFlag == 1}">可在线办理</span>
|
||
<span class="af-svc-tag"
|
||
th:text="${it.handleMode == 1 ? '线上办理' : (it.handleMode == 2 ? '线下办理' : '线上线下')}">办理方式</span>
|
||
</span>
|
||
<span class="af-svc-item-summary" th:if="${!#strings.isEmpty(it.summary)}"
|
||
th:text="${it.summary}">简介</span>
|
||
<span class="af-svc-item-meta">
|
||
<span th:if="${!#strings.isEmpty(it.deptName)}" th:text="${it.deptName}">部门</span>
|
||
<span th:if="${!#strings.isEmpty(it.categoryName)}" th:text="${it.categoryName}">类别</span>
|
||
<time th:if="${it.publishTime != null}"
|
||
th:text="${#temporals.format(it.publishTime, 'yyyy-MM-dd')}">2026-01-01</time>
|
||
</span>
|
||
</span>
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
<div class="af-empty" th:if="${!svcUnavailable and #lists.isEmpty(serviceList.items)}">
|
||
<p th:if="${activeFilters.hasAny}">未找到符合条件的服务事项</p>
|
||
<p th:if="${!activeFilters.hasAny}">服务中心暂未上架事项</p>
|
||
<p class="af-empty-hint" th:if="${activeFilters.hasAny}">换个筛选条件或关键词试试</p>
|
||
<p class="af-empty-hint" th:if="${!activeFilters.hasAny}">事项发布后将在此展示</p>
|
||
</div>
|
||
|
||
<!-- 分页:URL 由后端预生成(携带当前筛选,pageUrls[].active 标记当前页);停机态 totalPages=0 自然隐藏 -->
|
||
<nav class="af-pagination" th:if="${!svcUnavailable and serviceList.totalPages > 1}" aria-label="分页">
|
||
<a th:each="p : ${serviceList.pageUrls}"
|
||
th:classappend="${p.active} ? 'active'"
|
||
th:href="${p.url}"
|
||
th:aria-label="${'第' + p.page + '页'}"
|
||
th:aria-current="${p.active} ? 'page'"
|
||
th:text="${p.page}">1</a>
|
||
</nav>
|
||
</div>
|
||
</main>
|
||
|
||
<footer th:replace="~{${themeBase} + '/fragments/footer' :: footer}"></footer>
|
||
<script th:src="${url.asset('js/main.js')}"></script>
|
||
</body>
|
||
</html>
|