uiux
This commit is contained in:
@@ -18,8 +18,8 @@ the reusable UI units.
|
||||
sidebar, footer, pagination, and message banners.
|
||||
- Use `.jspf` includes for the current JSP presentation layer. The authenticated
|
||||
application frame lives in `src/main/webapp/WEB-INF/jsp/common/header.jspf`
|
||||
and owns the dark sidebar, top utility bar, role workbench links, module
|
||||
navigation, global search, user display, and logout link.
|
||||
and owns the dark sidebar, top utility bar, module navigation, global search,
|
||||
user display, and logout link.
|
||||
- Any `.jspf` fragment that contains user-visible Simplified Chinese text must
|
||||
declare `<%@ page pageEncoding="UTF-8" %>` at the top. Do not rely only on the
|
||||
including JSP page or response `Content-Type`; Tomcat/Jasper can otherwise
|
||||
@@ -31,6 +31,19 @@ the reusable UI units.
|
||||
links stay inside `sessionScope.userRole == 'administrator'`; staff links stay
|
||||
inside `administrator or librarian`; reader-only links stay inside
|
||||
`sessionScope.userRole == 'reader'`.
|
||||
- For active navigation in forwarded JSPs, derive the current location from the
|
||||
public Servlet path before falling back to the JSP servlet path. Use exact
|
||||
matches or slash-delimited prefixes; do not use broad `fn:contains` checks
|
||||
against `requestURI`, because forwarded pages expose `/WEB-INF/jsp/...` paths
|
||||
and can activate unrelated sidebar items.
|
||||
|
||||
```jsp
|
||||
<c:set var="currentPath" value="${requestScope['javax.servlet.forward.servlet_path']}" />
|
||||
<c:if test="${empty currentPath}">
|
||||
<c:set var="currentPath" value="${pageContext.request.servletPath}" />
|
||||
</c:if>
|
||||
<a class="${(currentPath == '/books' or fn:startsWith(currentPath, '/books/')) ? 'is-active' : ''}">
|
||||
```
|
||||
- Keep fragments presentation-focused. They should not open database
|
||||
connections or call DAOs.
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{"file": ".trellis/spec/frontend/index.md", "reason": "Frontend stack and checklist for final review."}
|
||||
{"file": ".trellis/spec/frontend/component-guidelines.md", "reason": "Check JSP fragments, role-conditioned navigation, Chinese copy, and reusable UI patterns."}
|
||||
{"file": ".trellis/spec/frontend/state-management.md", "reason": "Check session/request state usage remains server-rendered and safe."}
|
||||
{"file": ".trellis/spec/frontend/type-safety.md", "reason": "Check JSP/Servlet display contracts and safe EL/JSTL rendering."}
|
||||
{"file": ".trellis/spec/frontend/quality-guidelines.md", "reason": "Check navigation, layout, accessibility, and JSP/CSS architecture quality."}
|
||||
{"file": ".trellis/tasks/archive/2026-04/00-bootstrap-guidelines/research/project-requirements.md", "reason": "Check the change preserves the agreed JSP + Servlet + Tomcat stack."}
|
||||
@@ -0,0 +1,6 @@
|
||||
{"file": ".trellis/spec/frontend/index.md", "reason": "Frontend stack and checklist for JSP/CSS implementation."}
|
||||
{"file": ".trellis/spec/frontend/component-guidelines.md", "reason": "Shared JSP fragment, role-conditioned navigation, Simplified Chinese copy, form, table, and CSS conventions."}
|
||||
{"file": ".trellis/spec/frontend/state-management.md", "reason": "Server-rendered request/session state conventions while using session role data in navigation."}
|
||||
{"file": ".trellis/spec/frontend/type-safety.md", "reason": "JSP/Servlet display contracts and safe EL/JSTL rendering constraints."}
|
||||
{"file": ".trellis/spec/frontend/quality-guidelines.md", "reason": "Frontend verification expectations for navigation, layout, accessibility, and JSP/CSS boundaries."}
|
||||
{"file": ".trellis/tasks/archive/2026-04/00-bootstrap-guidelines/research/project-requirements.md", "reason": "Project stack constraints for JSP, Servlet, MySQL, and Tomcat."}
|
||||
@@ -0,0 +1,87 @@
|
||||
# Sidebar Active State And Management UX Cleanup
|
||||
|
||||
## Goal
|
||||
|
||||
Fix several visible JSP/CSS navigation and layout issues in the authenticated library-management UI, and reduce confusion between reader profile management and user account management without changing the backend data model.
|
||||
|
||||
## What I Already Know
|
||||
|
||||
* The application is a Java 11 Maven WAR using JSP, Servlet, JSTL, CSS, and Tomcat.
|
||||
* Authenticated navigation lives in `src/main/webapp/WEB-INF/jsp/common/header.jspf`.
|
||||
* Sidebar active state currently uses `fn:contains(currentUri, ...)`, but rendered JSP paths can differ from public servlet paths after `RequestDispatcher.forward`.
|
||||
* This explains reported false positives and false negatives:
|
||||
* `/catalog` can render through `/WEB-INF/jsp/books/catalog.jsp`, causing the books nav item to look active.
|
||||
* `/book-categories` renders through `/WEB-INF/jsp/books/categories.jsp`, causing books to look active while categories may not.
|
||||
* `/reports` renders `reports/dashboard.jsp`, which can make dashboard/workbench look active.
|
||||
* `/admin/system-logs` renders `maintenance/system-logs.jsp`, so the system log item may not activate.
|
||||
* The catalog, book management, and reader management hero sections put eyebrow/title/body/actions directly under a flex container; pages that wrap text in a child `<div>` avoid the horizontal layout break.
|
||||
* `dashboard.jsp` contains the small technical sentence the user wants removed.
|
||||
* `ReaderManagementServlet` manages reader profiles/eligibility/contact/borrowing limits; `UserManagementServlet` manages login accounts/roles/active status. These are overlapping concepts to users but distinct backend workflows.
|
||||
|
||||
## Requirements
|
||||
|
||||
* Sidebar active state must be based on the original public servlet path, not the forwarded JSP path.
|
||||
* Only the matching sidebar item should be active for catalog, books, book categories, reports, and system logs.
|
||||
* Remove the sidebar "角色工作台" block.
|
||||
* Remove the sidebar "工作台" nav item.
|
||||
* Move "报表中心" to the top of the main module navigation for administrator/librarian roles.
|
||||
* Fix the header/hero layout on catalog, book management, and reader management so eyebrow/title/description stay grouped vertically.
|
||||
* Remove the dashboard sentence: `登录后进入 Dashboard,会话仅保存安全的 AuthenticatedUser 快照、角色代码与权限代码集合。`
|
||||
* Reduce the perceived duplication between reader management and user management using conservative UI changes:
|
||||
* Treat reader management as reader profile/borrowing eligibility management.
|
||||
* Treat user management as account/role/login status management.
|
||||
* Prefer clearer labels, descriptions, and cross-links over merging backend flows.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
* [x] Opening `/catalog` highlights only "馆藏检索".
|
||||
* [x] Opening `/books` highlights only "图书管理".
|
||||
* [x] Opening `/book-categories` highlights only "图书分类管理".
|
||||
* [x] Opening `/reports` highlights only "报表中心" and does not highlight "工作台".
|
||||
* [x] Opening `/admin/system-logs` highlights "系统日志".
|
||||
* [x] The sidebar no longer displays the role workbench cards or a "工作台" nav item.
|
||||
* [x] "报表中心" appears before catalog/books/readers/borrowing for administrator/librarian navigation.
|
||||
* [x] Catalog, book management, and reader management hero copy is vertically grouped and does not lay out as separate horizontal items.
|
||||
* [x] The dashboard technical session sentence is absent.
|
||||
* [x] Reader/user management labels and descriptions make the distinction between reader profiles and user accounts clearer.
|
||||
* [x] Maven verification passes or the closest available build command is reported.
|
||||
|
||||
## Definition Of Done
|
||||
|
||||
* Focused JSP/CSS changes only unless a backend change is required by verification.
|
||||
* Existing Servlet/JSP rendering and JSTL escaping behavior remains intact.
|
||||
* Maven build/test verification run where available.
|
||||
* Trellis quality check completed before final response.
|
||||
|
||||
## Technical Approach
|
||||
|
||||
* In `header.jspf`, derive a `currentPath` from `requestScope['javax.servlet.forward.servlet_path']` with a fallback to `pageContext.request.servletPath`.
|
||||
* Replace broad `fn:contains` checks with exact or prefix checks against public servlet paths.
|
||||
* Reorder and trim sidebar markup according to the requested information architecture.
|
||||
* Wrap catalog/book/reader hero text in a child `<div>` to match pages that already render correctly.
|
||||
* Remove only the requested dashboard small text, leaving role-specific workbench headings and metrics intact.
|
||||
* Use copy changes and cross-links to clarify reader profiles versus user accounts without changing controllers, entities, DAOs, or database schema.
|
||||
|
||||
## Out Of Scope
|
||||
|
||||
* Merging reader and user management into a single page.
|
||||
* Changing authentication, authorization, database schema, or service-layer behavior.
|
||||
* Redesigning the whole dashboard or adding new frontend libraries.
|
||||
|
||||
## Technical Notes
|
||||
|
||||
* Relevant frontend spec index: `.trellis/spec/frontend/index.md`.
|
||||
* Relevant files inspected:
|
||||
* `src/main/webapp/WEB-INF/jsp/common/header.jspf`
|
||||
* `src/main/webapp/WEB-INF/jsp/dashboard.jsp`
|
||||
* `src/main/webapp/WEB-INF/jsp/books/catalog.jsp`
|
||||
* `src/main/webapp/WEB-INF/jsp/books/manage.jsp`
|
||||
* `src/main/webapp/WEB-INF/jsp/books/categories.jsp`
|
||||
* `src/main/webapp/WEB-INF/jsp/readers/manage.jsp`
|
||||
* `src/main/webapp/WEB-INF/jsp/admin/users/manage.jsp`
|
||||
* `src/main/webapp/static/css/app.css`
|
||||
* Build command from README: `mvn clean package`; fallback path documented as `/home/sjy/.sdkman/candidates/maven/current/bin/mvn clean package` if `mvn` is not on `PATH`.
|
||||
* Verification on 2026-04-28:
|
||||
* `git diff --check` passed.
|
||||
* Search for removed sidebar role/workbench and old active-state patterns returned no matches.
|
||||
* `/home/sjy/.sdkman/candidates/maven/current/bin/mvn clean package` passed with `BUILD SUCCESS`.
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "sidebar-layout-management-ux",
|
||||
"name": "sidebar-layout-management-ux",
|
||||
"title": "修复侧边栏高亮与管理页布局优化",
|
||||
"description": "",
|
||||
"status": "in_progress",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P2",
|
||||
"creator": "Zzzz",
|
||||
"assignee": "Zzzz",
|
||||
"createdAt": "2026-04-28",
|
||||
"completedAt": null,
|
||||
"branch": null,
|
||||
"base_branch": "master",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [],
|
||||
"notes": "",
|
||||
"meta": {}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>用户管理 - MZH 图书馆</title>
|
||||
<title>用户账户管理 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css?v=20260428-visual-shell">
|
||||
</head>
|
||||
<body>
|
||||
@@ -14,11 +14,14 @@
|
||||
<main class="page-shell">
|
||||
<section class="dashboard-hero catalog-hero" aria-labelledby="manage-users-title">
|
||||
<div>
|
||||
<p class="eyebrow">系统管理</p>
|
||||
<h1 id="manage-users-title">管理用户</h1>
|
||||
<p>创建、更新、停用和查看管理员、馆员与读者账户。</p>
|
||||
<p class="eyebrow">系统账户</p>
|
||||
<h1 id="manage-users-title">用户账户与角色</h1>
|
||||
<p>维护登录账户、角色、密码和启用状态;读者联系方式、借阅上限和资格请在读者管理中处理。</p>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/admin/users/new">新增用户账户</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/readers">读者档案</a>
|
||||
</div>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/admin/users/new">新增用户</a>
|
||||
</section>
|
||||
|
||||
<c:if test="${not empty successMessage}">
|
||||
@@ -32,7 +35,7 @@
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<section class="toolbar-panel" aria-label="用户管理检索">
|
||||
<section class="toolbar-panel" aria-label="用户账户检索">
|
||||
<form class="search-form" action="${pageContext.request.contextPath}/admin/users" method="get">
|
||||
<div class="search-field">
|
||||
<label for="keyword">关键词</label>
|
||||
|
||||
@@ -13,9 +13,11 @@
|
||||
<%@ include file="/WEB-INF/jsp/common/header.jspf" %>
|
||||
<main class="page-shell">
|
||||
<section class="dashboard-hero catalog-hero" aria-labelledby="catalog-title">
|
||||
<p class="eyebrow">馆藏</p>
|
||||
<h1 id="catalog-title">馆藏检索</h1>
|
||||
<p>按图书编号、书名、作者或分类检索馆藏。</p>
|
||||
<div>
|
||||
<p class="eyebrow">馆藏</p>
|
||||
<h1 id="catalog-title">馆藏检索</h1>
|
||||
<p>按图书编号、书名、作者或分类检索馆藏。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<c:if test="${not empty errorMessage}">
|
||||
|
||||
@@ -13,9 +13,11 @@
|
||||
<%@ include file="/WEB-INF/jsp/common/header.jspf" %>
|
||||
<main class="page-shell">
|
||||
<section class="dashboard-hero catalog-hero" aria-labelledby="manage-title">
|
||||
<p class="eyebrow">图书管理</p>
|
||||
<h1 id="manage-title">管理图书</h1>
|
||||
<p>创建、更新、删除和查看馆藏记录的库存信息。</p>
|
||||
<div>
|
||||
<p class="eyebrow">图书管理</p>
|
||||
<h1 id="manage-title">管理图书</h1>
|
||||
<p>创建、更新、删除和查看馆藏记录的库存信息。</p>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/books/new">新增图书</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/book-categories">分类</a>
|
||||
|
||||
@@ -4,83 +4,56 @@
|
||||
<header class="app-header ${not empty sessionScope.authenticatedUser ? 'app-header-auth' : 'app-header-public'}">
|
||||
<c:choose>
|
||||
<c:when test="${not empty sessionScope.authenticatedUser}">
|
||||
<c:set var="currentUri" value="${pageContext.request.requestURI}" />
|
||||
<c:set var="currentPath" value="${requestScope['javax.servlet.forward.servlet_path']}" />
|
||||
<c:if test="${empty currentPath}">
|
||||
<c:set var="currentPath" value="${pageContext.request.servletPath}" />
|
||||
</c:if>
|
||||
<aside class="app-sidebar" aria-label="主导航">
|
||||
<a class="sidebar-brand" href="${pageContext.request.contextPath}/dashboard">
|
||||
<span class="brand-text">图书管理系统</span>
|
||||
</a>
|
||||
|
||||
<section class="role-workbench" aria-label="角色工作台">
|
||||
<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-copy">
|
||||
<strong>管理员</strong>
|
||||
<small>系统管理</small>
|
||||
</span>
|
||||
</a>
|
||||
</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-copy">
|
||||
<strong>馆员</strong>
|
||||
<small>流通工作</small>
|
||||
</span>
|
||||
</a>
|
||||
</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-copy">
|
||||
<strong>读者</strong>
|
||||
<small>自助服务</small>
|
||||
</span>
|
||||
</a>
|
||||
</c:if>
|
||||
</section>
|
||||
|
||||
<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-text">工作台</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/catalog') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/catalog">
|
||||
<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-text">图书管理</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/book-categories') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/book-categories">
|
||||
<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-text">读者管理</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/borrowing') ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/borrowing">
|
||||
<span class="nav-text">借阅流通</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/reports') ? 'is-active' : ''}"
|
||||
<a class="side-nav-link ${currentPath == '/reports' ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/reports">
|
||||
<span class="nav-text">报表中心</span>
|
||||
</a>
|
||||
</c:if>
|
||||
<a class="side-nav-link ${currentPath == '/catalog' ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/catalog">
|
||||
<span class="nav-text">馆藏检索</span>
|
||||
</a>
|
||||
<c:if test="${sessionScope.userRole == 'administrator' or sessionScope.userRole == 'librarian'}">
|
||||
<a class="side-nav-link ${(currentPath == '/books' or fn:startsWith(currentPath, '/books/')) ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/books">
|
||||
<span class="nav-text">图书管理</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${(currentPath == '/book-categories' or fn:startsWith(currentPath, '/book-categories/')) ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/book-categories">
|
||||
<span class="nav-text">图书分类管理</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${(currentPath == '/readers' or fn:startsWith(currentPath, '/readers/')) ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/readers">
|
||||
<span class="nav-text">读者档案</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${(currentPath == '/borrowing' or fn:startsWith(currentPath, '/borrowing/')) ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/borrowing">
|
||||
<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' : ''}"
|
||||
<a class="side-nav-link ${(currentPath == '/reader/loans' or fn:startsWith(currentPath, '/reader/loans/')) ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/reader/loans">
|
||||
<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' : ''}"
|
||||
<a class="side-nav-link ${(currentPath == '/admin/users' or fn:startsWith(currentPath, '/admin/users/')) ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/admin/users">
|
||||
<span class="nav-text">用户管理</span>
|
||||
<span class="nav-text">用户账户</span>
|
||||
</a>
|
||||
<a class="side-nav-link ${fn:contains(currentUri, '/admin/system-logs') ? 'is-active' : ''}"
|
||||
<a class="side-nav-link ${(currentPath == '/admin/system-logs' or fn:startsWith(currentPath, '/admin/system-logs/')) ? 'is-active' : ''}"
|
||||
href="${pageContext.request.contextPath}/admin/system-logs">
|
||||
<span class="nav-text">系统日志</span>
|
||||
</a>
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
<c:otherwise>读者工作台</c:otherwise>
|
||||
</c:choose>
|
||||
</h1>
|
||||
<p>登录后进入 Dashboard,会话仅保存安全的 AuthenticatedUser 快照、角色代码与权限代码集合。</p>
|
||||
</div>
|
||||
<div class="welcome-user">
|
||||
<span>当前登录</span>
|
||||
|
||||
@@ -6,17 +6,24 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>读者管理 - MZH 图书馆</title>
|
||||
<title>读者档案 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css?v=20260428-visual-shell">
|
||||
</head>
|
||||
<body>
|
||||
<%@ include file="/WEB-INF/jsp/common/header.jspf" %>
|
||||
<main class="page-shell">
|
||||
<section class="dashboard-hero catalog-hero" aria-labelledby="manage-readers-title">
|
||||
<p class="eyebrow">读者管理</p>
|
||||
<h1 id="manage-readers-title">管理读者</h1>
|
||||
<p>创建、更新和查看读者资格及联系方式记录。</p>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/readers/new">新增读者</a>
|
||||
<div>
|
||||
<p class="eyebrow">读者档案</p>
|
||||
<h1 id="manage-readers-title">读者档案与借阅资格</h1>
|
||||
<p>维护读者资料、联系方式、借阅上限和借阅资格;登录账户、角色和启用状态请在用户管理中处理。</p>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/readers/new">新增读者档案</a>
|
||||
<c:if test="${sessionScope.userRole == 'administrator'}">
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/users">管理登录账户</a>
|
||||
</c:if>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<c:if test="${not empty successMessage}">
|
||||
@@ -30,7 +37,7 @@
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<section class="toolbar-panel" aria-label="读者管理检索">
|
||||
<section class="toolbar-panel" aria-label="读者档案检索">
|
||||
<form class="search-form" action="${pageContext.request.contextPath}/readers" method="get">
|
||||
<div class="search-field">
|
||||
<label for="identifier">读者编号</label>
|
||||
@@ -68,10 +75,10 @@
|
||||
</section>
|
||||
|
||||
<section class="table-panel" aria-labelledby="reader-results-title">
|
||||
<h2 id="reader-results-title">读者记录</h2>
|
||||
<h2 id="reader-results-title">读者档案</h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty readers}">
|
||||
<p class="empty-state">没有符合当前筛选条件的读者记录。</p>
|
||||
<p class="empty-state">没有符合当前筛选条件的读者档案。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
@@ -81,7 +88,7 @@
|
||||
<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>
|
||||
|
||||
@@ -133,69 +133,6 @@ textarea {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.role-workbench {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
margin-top: 22px;
|
||||
padding: 0 0 16px;
|
||||
border-bottom: 1px solid rgba(148, 163, 184, 0.14);
|
||||
}
|
||||
|
||||
.sidebar-section-title {
|
||||
grid-column: 1 / -1;
|
||||
margin: 0 0 10px;
|
||||
padding: 0 12px;
|
||||
color: #91a2bd;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.role-chip {
|
||||
min-height: 44px;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 2px;
|
||||
align-items: center;
|
||||
padding: 9px 11px;
|
||||
border-radius: 7px;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.16);
|
||||
}
|
||||
|
||||
.role-chip-copy {
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.role-chip strong {
|
||||
overflow: hidden;
|
||||
line-height: 1.1;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.role-chip small {
|
||||
overflow: hidden;
|
||||
color: rgba(255, 255, 255, 0.82);
|
||||
font-size: 11px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.role-chip-admin {
|
||||
background: linear-gradient(135deg, #316cf4, #1f57d8);
|
||||
}
|
||||
|
||||
.role-chip-librarian {
|
||||
background: linear-gradient(135deg, #4db7ad, #278f87);
|
||||
}
|
||||
|
||||
.role-chip-reader {
|
||||
background: linear-gradient(135deg, #ffac48, #f08a24);
|
||||
}
|
||||
|
||||
.side-nav {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
|
||||
Reference in New Issue
Block a user