前端优化
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
<c:set var="currentUri" value="${pageContext.request.requestURI}" />
|
||||
<aside class="app-sidebar" aria-label="主导航">
|
||||
<a class="sidebar-brand" href="${pageContext.request.contextPath}/dashboard">
|
||||
<span class="brand-mark" aria-hidden="true">书</span>
|
||||
<span class="brand-text">图书管理系统</span>
|
||||
</a>
|
||||
|
||||
@@ -15,7 +14,6 @@
|
||||
<p class="sidebar-section-title">角色工作台</p>
|
||||
<c:if test="${sessionScope.userRole == 'administrator'}">
|
||||
<a class="role-chip role-chip-admin" href="${pageContext.request.contextPath}/admin/home">
|
||||
<span class="role-chip-icon" aria-hidden="true">管</span>
|
||||
<span class="role-chip-copy">
|
||||
<strong>管理员</strong>
|
||||
<small>系统管理</small>
|
||||
@@ -24,7 +22,6 @@
|
||||
</c:if>
|
||||
<c:if test="${sessionScope.userRole == 'administrator' or sessionScope.userRole == 'librarian'}">
|
||||
<a class="role-chip role-chip-librarian" href="${pageContext.request.contextPath}/librarian/home">
|
||||
<span class="role-chip-icon" aria-hidden="true">馆</span>
|
||||
<span class="role-chip-copy">
|
||||
<strong>馆员</strong>
|
||||
<small>流通工作</small>
|
||||
@@ -33,7 +30,6 @@
|
||||
</c:if>
|
||||
<c:if test="${sessionScope.userRole == 'reader'}">
|
||||
<a class="role-chip role-chip-reader" href="${pageContext.request.contextPath}/reader/home">
|
||||
<span class="role-chip-icon" aria-hidden="true">读</span>
|
||||
<span class="role-chip-copy">
|
||||
<strong>读者</strong>
|
||||
<small>自助服务</small>
|
||||
@@ -45,64 +41,53 @@
|
||||
<nav class="side-nav" aria-label="模块导航">
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/dashboard') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/dashboard">
|
||||
<span class="nav-icon" aria-hidden="true">台</span>
|
||||
<span class="nav-text">工作台</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/catalog') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/catalog">
|
||||
<span class="nav-icon" aria-hidden="true">搜</span>
|
||||
<span class="nav-text">馆藏检索</span>
|
||||
</a>
|
||||
<c:if test="${sessionScope.userRole == 'administrator' or sessionScope.userRole == 'librarian'}">
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/books') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/books">
|
||||
<span class="nav-icon" aria-hidden="true">书</span>
|
||||
<span class="nav-text">图书管理</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/book-categories') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/book-categories">
|
||||
<span class="nav-icon" aria-hidden="true">类</span>
|
||||
<span class="nav-text">图书分类管理</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/readers') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/readers">
|
||||
<span class="nav-icon" aria-hidden="true">人</span>
|
||||
<span class="nav-text">读者管理</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/borrowing') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/borrowing">
|
||||
<span class="nav-icon" aria-hidden="true">借</span>
|
||||
<span class="nav-text">借阅流通</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/reports') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/reports">
|
||||
<span class="nav-icon" aria-hidden="true">报</span>
|
||||
<span class="nav-text">报表中心</span>
|
||||
</a>
|
||||
</c:if>
|
||||
<c:if test="${sessionScope.userRole == 'reader'}">
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/reader/loans') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/reader/loans">
|
||||
<span class="nav-icon" aria-hidden="true">历</span>
|
||||
<span class="nav-text">读者借阅历史</span>
|
||||
</a>
|
||||
</c:if>
|
||||
<c:if test="${sessionScope.userRole == 'administrator'}">
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/admin/users') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/admin/users">
|
||||
<span class="nav-icon" aria-hidden="true">户</span>
|
||||
<span class="nav-text">用户管理</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/admin/system-logs') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/admin/system-logs">
|
||||
<span class="nav-icon" aria-hidden="true">志</span>
|
||||
<span class="nav-text">系统日志</span>
|
||||
</a>
|
||||
</c:if>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
<span class="sidebar-menu-dot" aria-hidden="true">≡</span>
|
||||
<a href="${pageContext.request.contextPath}/logout">退出登录</a>
|
||||
</div>
|
||||
</aside>
|
||||
@@ -115,15 +100,7 @@
|
||||
<button type="submit" aria-label="搜索">搜</button>
|
||||
</form>
|
||||
<div class="topbar-actions">
|
||||
<span class="notification-dot" aria-label="通知">!</span>
|
||||
<span class="user-summary">
|
||||
<span class="avatar" aria-hidden="true">
|
||||
<c:choose>
|
||||
<c:when test="${sessionScope.userRole == 'administrator'}">管</c:when>
|
||||
<c:when test="${sessionScope.userRole == 'librarian'}">馆</c:when>
|
||||
<c:otherwise>读</c:otherwise>
|
||||
</c:choose>
|
||||
</span>
|
||||
<span class="user-meta">
|
||||
<span class="user-pill">
|
||||
<c:out value="${sessionScope.authenticatedUser.displayName}" />
|
||||
|
||||
@@ -31,39 +31,36 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<c:if test="${not empty errorMessage}">
|
||||
<p class="message message-error"><c:out value="${errorMessage}" /></p>
|
||||
</c:if>
|
||||
|
||||
<section class="dashboard-metrics" aria-label="核心指标">
|
||||
<article class="metric-card">
|
||||
<span class="metric-icon metric-blue" aria-hidden="true">书</span>
|
||||
<div>
|
||||
<h2>馆藏总量</h2>
|
||||
<p class="metric-value">12,586 <small>册</small></p>
|
||||
<p class="metric-trend trend-up">较上月 ↑ 5.2%</p>
|
||||
</div>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-icon metric-green" aria-hidden="true">借</span>
|
||||
<div>
|
||||
<h2>在借数量</h2>
|
||||
<p class="metric-value">1,258 <small>册</small></p>
|
||||
<p class="metric-trend trend-up">较上月 ↑ 3.1%</p>
|
||||
</div>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-icon metric-orange" aria-hidden="true">期</span>
|
||||
<div>
|
||||
<h2>逾期数量</h2>
|
||||
<p class="metric-value">87 <small>册</small></p>
|
||||
<p class="metric-trend trend-down">较上月 ↓ 12.4%</p>
|
||||
</div>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<span class="metric-icon metric-purple" aria-hidden="true">者</span>
|
||||
<div>
|
||||
<h2>读者总数</h2>
|
||||
<p class="metric-value">3,682 <small>人</small></p>
|
||||
<p class="metric-trend trend-up">较上月 ↑ 4.8%</p>
|
||||
</div>
|
||||
</article>
|
||||
<c:choose>
|
||||
<c:when test="${empty dashboardMetrics}">
|
||||
<article class="metric-card metric-card-empty">
|
||||
<div>
|
||||
<h2>核心指标</h2>
|
||||
<p class="metric-value">--</p>
|
||||
<p class="metric-trend">暂无可展示的实时数据。</p>
|
||||
</div>
|
||||
</article>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:forEach var="metric" items="${dashboardMetrics}">
|
||||
<article class="metric-card">
|
||||
<div>
|
||||
<h2><c:out value="${metric.label}" /></h2>
|
||||
<p class="metric-value">
|
||||
<c:out value="${metric.value}" />
|
||||
<small><c:out value="${metric.unit}" /></small>
|
||||
</p>
|
||||
<p class="metric-trend"><c:out value="${metric.note}" /></p>
|
||||
</div>
|
||||
</article>
|
||||
</c:forEach>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</section>
|
||||
|
||||
<section class="dashboard-grid" aria-label="检索与排行">
|
||||
@@ -85,7 +82,10 @@
|
||||
<div class="search-field">
|
||||
<label for="dashCategory">分类</label>
|
||||
<select id="dashCategory" name="categoryId">
|
||||
<option value="">请选择分类</option>
|
||||
<option value="">全部分类</option>
|
||||
<c:forEach var="category" items="${categories}">
|
||||
<option value="${category.id}"><c:out value="${category.name}" /></option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</div>
|
||||
<div class="dashboard-form-actions">
|
||||
@@ -100,117 +100,116 @@
|
||||
<h2>热门图书排行</h2>
|
||||
<span>借阅次数TOP10</span>
|
||||
</div>
|
||||
<div class="rank-chart" aria-label="热门图书排行柱状图">
|
||||
<div class="rank-item"><span class="rank-value">230</span><span class="rank-bar" style="--bar-height: 92%;"></span><small>活着</small></div>
|
||||
<div class="rank-item"><span class="rank-value">198</span><span class="rank-bar" style="--bar-height: 79%;"></span><small>三体</small></div>
|
||||
<div class="rank-item"><span class="rank-value">175</span><span class="rank-bar" style="--bar-height: 70%;"></span><small>百年孤独</small></div>
|
||||
<div class="rank-item"><span class="rank-value">164</span><span class="rank-bar" style="--bar-height: 66%;"></span><small>围城</small></div>
|
||||
<div class="rank-item"><span class="rank-value">150</span><span class="rank-bar" style="--bar-height: 60%;"></span><small>平凡的世界</small></div>
|
||||
<div class="rank-item"><span class="rank-value">138</span><span class="rank-bar" style="--bar-height: 55%;"></span><small>解忧杂货店</small></div>
|
||||
<div class="rank-item"><span class="rank-value">120</span><span class="rank-bar" style="--bar-height: 48%;"></span><small>红楼梦</small></div>
|
||||
<div class="rank-item"><span class="rank-value">112</span><span class="rank-bar" style="--bar-height: 45%;"></span><small>白夜行</small></div>
|
||||
<div class="rank-item"><span class="rank-value">98</span><span class="rank-bar" style="--bar-height: 39%;"></span><small>追风筝的人</small></div>
|
||||
<div class="rank-item"><span class="rank-value">85</span><span class="rank-bar" style="--bar-height: 34%;"></span><small>小王子</small></div>
|
||||
</div>
|
||||
<c:choose>
|
||||
<c:when test="${empty reportCenter or empty reportCenter.popularBooks}">
|
||||
<p class="empty-state">暂无热门排行数据。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:set var="rankingMax" value="${reportCenter.popularBooks[0].borrowCount}" />
|
||||
<div class="rank-chart" aria-label="热门图书排行柱状图">
|
||||
<c:forEach var="row" items="${reportCenter.popularBooks}" end="9">
|
||||
<div class="rank-item">
|
||||
<span class="rank-value"><c:out value="${row.borrowCount}" /></span>
|
||||
<span class="rank-bar"
|
||||
style="--bar-height: ${rankingMax > 0 ? row.borrowCount * 100 / rankingMax : 0}%;"></span>
|
||||
<small><c:out value="${row.title}" /></small>
|
||||
</div>
|
||||
</c:forEach>
|
||||
</div>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<c:if test="${sessionScope.userRole == 'administrator' or sessionScope.userRole == 'librarian'}">
|
||||
<section class="dashboard-table-grid" aria-label="业务表格">
|
||||
<article class="dashboard-panel table-panel-compact table-panel-wide">
|
||||
<h2>借阅流通 <span>最新记录</span></h2>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table dashboard-data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">流水号</th>
|
||||
<th scope="col">读者姓名</th>
|
||||
<th scope="col">图书编号</th>
|
||||
<th scope="col">书名</th>
|
||||
<th scope="col">借阅日期</th>
|
||||
<th scope="col">应还日期</th>
|
||||
<th scope="col">状态</th>
|
||||
<th scope="col">库存联动</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>L20240521001</td>
|
||||
<td>张晓明</td>
|
||||
<td>B001245</td>
|
||||
<td>活着</td>
|
||||
<td>2024-05-21</td>
|
||||
<td>2024-06-04</td>
|
||||
<td><span class="status-pill status-active">在借</span></td>
|
||||
<td><span class="stock-plus">库存-1</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>L20240521002</td>
|
||||
<td>李华</td>
|
||||
<td>B001026</td>
|
||||
<td>三体</td>
|
||||
<td>2024-05-20</td>
|
||||
<td>2024-06-03</td>
|
||||
<td><span class="status-pill status-active">在借</span></td>
|
||||
<td><span class="stock-plus">库存-1</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>L20240521003</td>
|
||||
<td>王丽</td>
|
||||
<td>B002031</td>
|
||||
<td>百年孤独</td>
|
||||
<td>2024-05-18</td>
|
||||
<td>2024-06-01</td>
|
||||
<td><span class="status-pill status-returned">已归还</span></td>
|
||||
<td><span class="stock-return">库存+1</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>L20240521004</td>
|
||||
<td>陈强</td>
|
||||
<td>B001895</td>
|
||||
<td>围城</td>
|
||||
<td>2024-05-10</td>
|
||||
<td>2024-05-24</td>
|
||||
<td><span class="status-pill status-overdue">逾期</span></td>
|
||||
<td><span class="stock-plus">库存-1</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>L20240521005</td>
|
||||
<td>刘洋</td>
|
||||
<td>B002119</td>
|
||||
<td>解忧杂货店</td>
|
||||
<td>2024-05-12</td>
|
||||
<td>2024-05-26</td>
|
||||
<td><span class="status-pill status-overdue">逾期</span></td>
|
||||
<td><span class="stock-plus">库存-1</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h2>借阅流通 <span>实时记录</span></h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty dashboardBorrowRecords}">
|
||||
<p class="empty-state">暂无借阅流通记录。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table dashboard-data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">流水号</th>
|
||||
<th scope="col">读者姓名</th>
|
||||
<th scope="col">图书编号</th>
|
||||
<th scope="col">书名</th>
|
||||
<th scope="col">借阅日期</th>
|
||||
<th scope="col">应还日期</th>
|
||||
<th scope="col">状态</th>
|
||||
<th scope="col">库存联动</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<c:forEach var="record" items="${dashboardBorrowRecords}" end="4">
|
||||
<tr>
|
||||
<td>#<c:out value="${record.id}" /></td>
|
||||
<td><c:out value="${record.readerName}" /></td>
|
||||
<td><c:out value="${record.bookIdentifier}" /></td>
|
||||
<td><c:out value="${record.bookTitle}" /></td>
|
||||
<td><c:out value="${record.borrowedAtText}" /></td>
|
||||
<td><c:out value="${record.dueAtText}" /></td>
|
||||
<td>
|
||||
<span class="status-pill status-${record.displayStatusCode}">
|
||||
<c:out value="${record.displayStatusName}" />
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<c:choose>
|
||||
<c:when test="${record.displayStatusCode == 'returned'}">
|
||||
<span class="stock-return">库存已返还</span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span class="stock-plus">借出占用</span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</article>
|
||||
|
||||
<article class="dashboard-panel table-panel-compact">
|
||||
<h2>逾期列表 <span>待处理</span></h2>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table dashboard-data-table overdue-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">读者姓名</th>
|
||||
<th scope="col">图书编号</th>
|
||||
<th scope="col">书名</th>
|
||||
<th scope="col">应还日期</th>
|
||||
<th scope="col">逾期天数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>陈强</td><td>B001895</td><td>围城</td><td>2024-05-24</td><td><span class="overdue-days">7天</span></td></tr>
|
||||
<tr><td>赵敏</td><td>B001122</td><td>平凡的世界</td><td>2024-05-20</td><td><span class="overdue-days">11天</span></td></tr>
|
||||
<tr><td>孙涛</td><td>B002003</td><td>红楼梦</td><td>2024-05-18</td><td><span class="overdue-days">13天</span></td></tr>
|
||||
<tr><td>周雨</td><td>B000987</td><td>追风筝的人</td><td>2024-05-17</td><td><span class="overdue-days">14天</span></td></tr>
|
||||
<tr><td>吴迪</td><td>B001776</td><td>白夜行</td><td>2024-05-15</td><td><span class="overdue-days">16天</span></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<c:choose>
|
||||
<c:when test="${empty reportCenter or empty reportCenter.overdueRows}">
|
||||
<p class="empty-state">当前没有逾期未还的借阅记录。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table dashboard-data-table overdue-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">读者姓名</th>
|
||||
<th scope="col">图书编号</th>
|
||||
<th scope="col">书名</th>
|
||||
<th scope="col">应还日期</th>
|
||||
<th scope="col">逾期天数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<c:forEach var="row" items="${reportCenter.overdueRows}" end="4">
|
||||
<tr>
|
||||
<td><c:out value="${row.readerName}" /></td>
|
||||
<td><c:out value="${row.bookIdentifier}" /></td>
|
||||
<td><c:out value="${row.bookTitle}" /></td>
|
||||
<td><c:out value="${row.dueAtText}" /></td>
|
||||
<td><span class="overdue-days"><c:out value="${row.overdueDays}" />天</span></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</article>
|
||||
|
||||
<article class="dashboard-panel table-panel-compact table-panel-wide">
|
||||
@@ -218,87 +217,55 @@
|
||||
<h2>图书管理 <span>馆藏列表</span></h2>
|
||||
<a href="${pageContext.request.contextPath}/books">进入管理</a>
|
||||
</div>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table dashboard-data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">图书编号</th>
|
||||
<th scope="col">书名</th>
|
||||
<th scope="col">作者</th>
|
||||
<th scope="col">分类</th>
|
||||
<th scope="col">出版日期</th>
|
||||
<th scope="col">库存状态</th>
|
||||
<th scope="col">馆藏地</th>
|
||||
<th scope="col">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>B001245</td><td>活着</td><td>余华</td><td>文学 > 小说</td><td>2012-08-01</td>
|
||||
<td><span class="status-pill status-available">可借(15)</span></td><td>二楼文学区</td>
|
||||
<td><a class="text-link" href="${pageContext.request.contextPath}/books">管理</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B001026</td><td>三体</td><td>刘慈欣</td><td>文学 > 科幻</td><td>2008-01-01</td>
|
||||
<td><span class="status-pill status-available">可借(8)</span></td><td>三楼科幻区</td>
|
||||
<td><a class="text-link" href="${pageContext.request.contextPath}/books">管理</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B002031</td><td>百年孤独</td><td>加西亚·马尔克斯</td><td>文学 > 外国文学</td><td>2011-06-01</td>
|
||||
<td><span class="status-pill status-available">可借(6)</span></td><td>二楼文学区</td>
|
||||
<td><a class="text-link" href="${pageContext.request.contextPath}/books">管理</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B001895</td><td>围城</td><td>钱钟书</td><td>文学 > 小说</td><td>2008-05-01</td>
|
||||
<td><span class="status-pill status-available">可借(4)</span></td><td>二楼文学区</td>
|
||||
<td><a class="text-link" href="${pageContext.request.contextPath}/books">管理</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B002119</td><td>解忧杂货店</td><td>东野圭吾</td><td>文学 > 小说</td><td>2014-07-01</td>
|
||||
<td><span class="status-pill status-available">可借(10)</span></td><td>二楼文学区</td>
|
||||
<td><a class="text-link" href="${pageContext.request.contextPath}/books">管理</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<c:choose>
|
||||
<c:when test="${empty dashboardBooks}">
|
||||
<p class="empty-state">暂无馆藏图书记录。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table dashboard-data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">图书编号</th>
|
||||
<th scope="col">书名</th>
|
||||
<th scope="col">作者</th>
|
||||
<th scope="col">分类</th>
|
||||
<th scope="col">库存状态</th>
|
||||
<th scope="col">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<c:forEach var="book" items="${dashboardBooks}" end="4">
|
||||
<tr>
|
||||
<td><c:out value="${book.identifier}" /></td>
|
||||
<td><c:out value="${book.title}" /></td>
|
||||
<td><c:out value="${book.author}" /></td>
|
||||
<td><c:out value="${book.categoryName}" /></td>
|
||||
<td>
|
||||
<span class="status-pill status-${book.status.code}">
|
||||
<c:out value="${book.status.displayName}" />
|
||||
(<c:out value="${book.availableCopies}" />/<c:out value="${book.totalCopies}" />)
|
||||
</span>
|
||||
</td>
|
||||
<td><a class="text-link" href="${pageContext.request.contextPath}/books">管理</a></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</article>
|
||||
|
||||
<aside class="shortcut-grid" aria-label="快捷入口">
|
||||
<a class="shortcut-card" href="${pageContext.request.contextPath}/readers">
|
||||
<span class="shortcut-icon shortcut-blue" aria-hidden="true">者</span>
|
||||
<strong>读者管理</strong>
|
||||
<small>管理读者信息、证件办理与权限设置</small>
|
||||
</a>
|
||||
<a class="shortcut-card" href="${pageContext.request.contextPath}/reports">
|
||||
<span class="shortcut-icon shortcut-green" aria-hidden="true">报</span>
|
||||
<strong>报表中心</strong>
|
||||
<small>生成各类统计报表,支持导出与分析</small>
|
||||
</a>
|
||||
<a class="shortcut-card" href="${pageContext.request.contextPath}/borrowing">
|
||||
<span class="shortcut-icon shortcut-orange" aria-hidden="true">借</span>
|
||||
<strong>借阅流通</strong>
|
||||
<small>借书、还书、续借与逾期处理</small>
|
||||
</a>
|
||||
<c:if test="${sessionScope.userRole == 'administrator'}">
|
||||
<a class="shortcut-card" href="${pageContext.request.contextPath}/admin/system-logs">
|
||||
<span class="shortcut-icon shortcut-purple" aria-hidden="true">志</span>
|
||||
<strong>系统日志</strong>
|
||||
<small>系统操作日志与安全审计记录查询</small>
|
||||
</a>
|
||||
</c:if>
|
||||
</aside>
|
||||
</section>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${sessionScope.userRole == 'reader'}">
|
||||
<section class="shortcut-grid reader-shortcut-grid" aria-label="读者快捷入口">
|
||||
<a class="shortcut-card" href="${pageContext.request.contextPath}/reader/loans">
|
||||
<span class="shortcut-icon shortcut-blue" aria-hidden="true">历</span>
|
||||
<strong>我的借阅</strong>
|
||||
<small>查看在借、已还、续借次数和逾期状态</small>
|
||||
</a>
|
||||
<a class="shortcut-card" href="${pageContext.request.contextPath}/catalog">
|
||||
<span class="shortcut-icon shortcut-green" aria-hidden="true">搜</span>
|
||||
<strong>馆藏检索</strong>
|
||||
<small>按书名、作者、分类或图书编号查找馆藏</small>
|
||||
</a>
|
||||
|
||||
@@ -41,6 +41,10 @@ body {
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
body:not(.auth-page) {
|
||||
min-width: calc(var(--sidebar-width) + 320px);
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
@@ -113,9 +117,8 @@ textarea {
|
||||
.sidebar-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 11px;
|
||||
min-height: 44px;
|
||||
padding: 0 10px;
|
||||
padding: 0 12px;
|
||||
color: #ffffff;
|
||||
font-size: 17px;
|
||||
font-weight: 800;
|
||||
@@ -130,18 +133,6 @@ textarea {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.brand-mark {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 7px;
|
||||
color: #102033;
|
||||
background: #ffffff;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.role-workbench {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
@@ -162,8 +153,8 @@ textarea {
|
||||
.role-chip {
|
||||
min-height: 44px;
|
||||
display: grid;
|
||||
grid-template-columns: 30px minmax(0, 1fr);
|
||||
gap: 0 10px;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 2px;
|
||||
align-items: center;
|
||||
padding: 9px 11px;
|
||||
border-radius: 7px;
|
||||
@@ -172,18 +163,6 @@ textarea {
|
||||
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.16);
|
||||
}
|
||||
|
||||
.role-chip-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.24);
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.role-chip-copy {
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
@@ -226,29 +205,15 @@ textarea {
|
||||
.side-nav-link {
|
||||
min-height: 40px;
|
||||
display: grid;
|
||||
grid-template-columns: 28px minmax(0, 1fr);
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 10px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 7px;
|
||||
color: #c8d2df;
|
||||
line-height: 1.2;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.side-nav-link .nav-icon {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
color: #9aa9bd;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.side-nav-link .nav-text {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
@@ -263,12 +228,6 @@ textarea {
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.side-nav-link:hover .nav-icon,
|
||||
.side-nav-link.is-active .nav-icon {
|
||||
color: #ffffff;
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
min-height: 34px;
|
||||
display: flex;
|
||||
@@ -287,11 +246,6 @@ textarea {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sidebar-menu-dot {
|
||||
color: #91a2bd;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.app-topbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@@ -373,47 +327,18 @@ textarea {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.notification-dot {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
flex: 0 0 24px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 999px;
|
||||
color: #ffffff;
|
||||
background: #ef4444;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.user-summary {
|
||||
min-width: 0;
|
||||
max-width: 240px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 4px 10px 4px 4px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 999px;
|
||||
border-radius: 8px;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 999px;
|
||||
color: #102033;
|
||||
background: linear-gradient(135deg, #dbeafe, #ffffff);
|
||||
font-weight: 800;
|
||||
flex: 0 0 32px;
|
||||
box-shadow: inset 0 0 0 1px #bfdbfe;
|
||||
}
|
||||
|
||||
.user-meta {
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
@@ -715,12 +640,14 @@ h2 {
|
||||
flex: 1 1 230px;
|
||||
min-width: 0;
|
||||
min-height: 98px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
display: block;
|
||||
padding: 18px 20px;
|
||||
}
|
||||
|
||||
.metric-card-empty {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.metric-card > div {
|
||||
min-width: 0;
|
||||
}
|
||||
@@ -731,35 +658,6 @@ h2 {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.metric-icon {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
display: inline-flex;
|
||||
flex: 0 0 52px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 999px;
|
||||
color: #ffffff;
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.metric-blue {
|
||||
background: linear-gradient(135deg, #4b83f3, #2869e8);
|
||||
}
|
||||
|
||||
.metric-green {
|
||||
background: linear-gradient(135deg, #5ccaae, #1f9d68);
|
||||
}
|
||||
|
||||
.metric-orange {
|
||||
background: linear-gradient(135deg, #ffb25c, #f08a24);
|
||||
}
|
||||
|
||||
.metric-purple {
|
||||
background: linear-gradient(135deg, #9187f1, #6f60e5);
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
margin-bottom: 4px;
|
||||
font-size: 24px;
|
||||
@@ -933,7 +831,7 @@ h2 {
|
||||
.shortcut-card {
|
||||
min-height: 100px;
|
||||
display: grid;
|
||||
grid-template-columns: 46px 1fr 14px;
|
||||
grid-template-columns: minmax(0, 1fr) 14px;
|
||||
grid-template-rows: auto auto;
|
||||
gap: 5px 13px;
|
||||
align-items: center;
|
||||
@@ -944,7 +842,7 @@ h2 {
|
||||
.shortcut-card::after {
|
||||
content: "›";
|
||||
grid-row: 1 / 3;
|
||||
grid-column: 3;
|
||||
grid-column: 2;
|
||||
color: #94a3b8;
|
||||
font-size: 24px;
|
||||
}
|
||||
@@ -959,37 +857,6 @@ h2 {
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.shortcut-icon {
|
||||
grid-row: 1 / 3;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 999px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.shortcut-blue {
|
||||
color: #2454cb;
|
||||
background: #eaf1ff;
|
||||
}
|
||||
|
||||
.shortcut-green {
|
||||
color: #16825a;
|
||||
background: #dcfce7;
|
||||
}
|
||||
|
||||
.shortcut-orange {
|
||||
color: #c46615;
|
||||
background: #fff3df;
|
||||
}
|
||||
|
||||
.shortcut-purple {
|
||||
color: #6254d6;
|
||||
background: #eeeaff;
|
||||
}
|
||||
|
||||
.card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
|
||||
@@ -1280,60 +1147,27 @@ h2 {
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.app-sidebar,
|
||||
.app-topbar {
|
||||
position: static;
|
||||
top: auto;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
width: auto;
|
||||
inset: auto;
|
||||
}
|
||||
|
||||
.app-sidebar {
|
||||
min-height: auto;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.role-workbench {
|
||||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||
}
|
||||
|
||||
.side-nav {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.app-topbar {
|
||||
height: auto;
|
||||
flex-direction: column;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
align-items: stretch;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 10px;
|
||||
padding: 14px 16px;
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.topbar-actions {
|
||||
justify-content: space-between;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.user-summary {
|
||||
max-width: none;
|
||||
max-width: 180px;
|
||||
}
|
||||
|
||||
.user-pill,
|
||||
.role-label {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
body:not(.auth-page) .page-shell {
|
||||
width: min(1280px, calc(100% - 24px));
|
||||
margin: 0 auto;
|
||||
padding: 18px 0 40px;
|
||||
max-width: 140px;
|
||||
}
|
||||
|
||||
.global-search {
|
||||
|
||||
Reference in New Issue
Block a user