+chinese
This commit is contained in:
@@ -44,7 +44,7 @@ public class BookManagementServlet extends HttpServlet {
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
String path = request.getServletPath();
|
||||
if ("/books/new".equals(path)) {
|
||||
renderForm(request, response, "Create book", "/books", new Book(), Collections.emptyMap(),
|
||||
renderForm(request, response, "创建图书", "/books", new Book(), Collections.emptyMap(),
|
||||
Collections.emptyMap(), null);
|
||||
return;
|
||||
}
|
||||
@@ -57,7 +57,7 @@ public class BookManagementServlet extends HttpServlet {
|
||||
return;
|
||||
}
|
||||
if ("/book-categories/new".equals(path)) {
|
||||
renderCategoryForm(request, response, "Create category", "/book-categories", new BookCategory(),
|
||||
renderCategoryForm(request, response, "创建分类", "/book-categories", new BookCategory(),
|
||||
Collections.emptyMap(), Collections.emptyMap(), null);
|
||||
return;
|
||||
}
|
||||
@@ -134,12 +134,12 @@ public class BookManagementServlet extends HttpServlet {
|
||||
long id = requiredLong(request.getParameter("id"), -1L);
|
||||
ServiceResult<Optional<Book>> result = bookService.findBook(id);
|
||||
if (!result.isSuccessful() || !result.getData().isPresent()) {
|
||||
flashError(request, result.isSuccessful() ? "Book was not found." : result.getMessage());
|
||||
flashError(request, result.isSuccessful() ? "未找到图书。" : result.getMessage());
|
||||
response.sendRedirect(request.getContextPath() + "/books");
|
||||
return;
|
||||
}
|
||||
|
||||
renderForm(request, response, "Edit book", "/books/update", result.getData().get(),
|
||||
renderForm(request, response, "编辑图书", "/books/update", result.getData().get(),
|
||||
Collections.emptyMap(), Collections.emptyMap(), null);
|
||||
}
|
||||
|
||||
@@ -160,26 +160,26 @@ public class BookManagementServlet extends HttpServlet {
|
||||
long id = requiredLong(request.getParameter("id"), -1L);
|
||||
ServiceResult<Optional<BookCategory>> result = bookService.findCategory(id);
|
||||
if (!result.isSuccessful() || !result.getData().isPresent()) {
|
||||
flashError(request, result.isSuccessful() ? "Category was not found." : result.getMessage());
|
||||
flashError(request, result.isSuccessful() ? "未找到分类。" : result.getMessage());
|
||||
response.sendRedirect(request.getContextPath() + "/book-categories");
|
||||
return;
|
||||
}
|
||||
|
||||
renderCategoryForm(request, response, "Edit category", "/book-categories/update", result.getData().get(),
|
||||
renderCategoryForm(request, response, "编辑分类", "/book-categories/update", result.getData().get(),
|
||||
Collections.emptyMap(), Collections.emptyMap(), null);
|
||||
}
|
||||
|
||||
private void createBook(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
BookForm form = readBookForm(request, false);
|
||||
if (!form.getErrors().isEmpty()) {
|
||||
renderForm(request, response, "Create book", "/books", form.getBook(), form.getValues(),
|
||||
form.getErrors(), "Please correct the highlighted book fields.");
|
||||
renderForm(request, response, "创建图书", "/books", form.getBook(), form.getValues(),
|
||||
form.getErrors(), "请修正高亮的图书字段。");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceResult<Long> result = bookService.createBook(currentUser(request), form.getBook());
|
||||
if (!result.isSuccessful()) {
|
||||
handleFormFailure(request, response, "Create book", "/books", form, result);
|
||||
handleFormFailure(request, response, "创建图书", "/books", form, result);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -190,14 +190,14 @@ public class BookManagementServlet extends HttpServlet {
|
||||
private void updateBook(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
BookForm form = readBookForm(request, true);
|
||||
if (!form.getErrors().isEmpty()) {
|
||||
renderForm(request, response, "Edit book", "/books/update", form.getBook(), form.getValues(),
|
||||
form.getErrors(), "Please correct the highlighted book fields.");
|
||||
renderForm(request, response, "编辑图书", "/books/update", form.getBook(), form.getValues(),
|
||||
form.getErrors(), "请修正高亮的图书字段。");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceResult<Void> result = bookService.updateBook(currentUser(request), form.getBook());
|
||||
if (!result.isSuccessful()) {
|
||||
handleFormFailure(request, response, "Edit book", "/books/update", form, result);
|
||||
handleFormFailure(request, response, "编辑图书", "/books/update", form, result);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -224,14 +224,14 @@ public class BookManagementServlet extends HttpServlet {
|
||||
throws ServletException, IOException {
|
||||
CategoryForm form = readCategoryForm(request, false);
|
||||
if (!form.getErrors().isEmpty()) {
|
||||
renderCategoryForm(request, response, "Create category", "/book-categories", form.getCategory(),
|
||||
form.getValues(), form.getErrors(), "Please correct the highlighted category fields.");
|
||||
renderCategoryForm(request, response, "创建分类", "/book-categories", form.getCategory(),
|
||||
form.getValues(), form.getErrors(), "请修正高亮的分类字段。");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceResult<Long> result = bookService.createCategory(currentUser(request), form.getCategory());
|
||||
if (!result.isSuccessful()) {
|
||||
handleCategoryFormFailure(request, response, "Create category", "/book-categories", form, result);
|
||||
handleCategoryFormFailure(request, response, "创建分类", "/book-categories", form, result);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -243,14 +243,14 @@ public class BookManagementServlet extends HttpServlet {
|
||||
throws ServletException, IOException {
|
||||
CategoryForm form = readCategoryForm(request, true);
|
||||
if (!form.getErrors().isEmpty()) {
|
||||
renderCategoryForm(request, response, "Edit category", "/book-categories/update", form.getCategory(),
|
||||
form.getValues(), form.getErrors(), "Please correct the highlighted category fields.");
|
||||
renderCategoryForm(request, response, "编辑分类", "/book-categories/update", form.getCategory(),
|
||||
form.getValues(), form.getErrors(), "请修正高亮的分类字段。");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceResult<Void> result = bookService.updateCategory(currentUser(request), form.getCategory());
|
||||
if (!result.isSuccessful()) {
|
||||
handleCategoryFormFailure(request, response, "Edit category", "/book-categories/update", form, result);
|
||||
handleCategoryFormFailure(request, response, "编辑分类", "/book-categories/update", form, result);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -338,20 +338,20 @@ public class BookManagementServlet extends HttpServlet {
|
||||
Book book = new Book();
|
||||
|
||||
if (requireId) {
|
||||
book.setId(parseLong(values.get("id"), "id", "Select a valid book.", errors));
|
||||
book.setId(parseLong(values.get("id"), "id", "请选择有效的图书。", errors));
|
||||
}
|
||||
book.setIdentifier(values.get("identifier"));
|
||||
book.setTitle(values.get("title"));
|
||||
book.setAuthor(values.get("author"));
|
||||
book.setCategoryId(parseLong(values.get("categoryId"), "categoryId", "Select a category.", errors));
|
||||
book.setTotalCopies(parseInt(values.get("totalCopies"), "totalCopies", "Enter a valid total copy count.", errors));
|
||||
book.setCategoryId(parseLong(values.get("categoryId"), "categoryId", "请选择分类。", errors));
|
||||
book.setTotalCopies(parseInt(values.get("totalCopies"), "totalCopies", "请输入有效的馆藏总数。", errors));
|
||||
book.setAvailableCopies(parseInt(values.get("availableCopies"), "availableCopies",
|
||||
"Enter a valid available copy count.", errors));
|
||||
"请输入有效的可借数量。", errors));
|
||||
|
||||
try {
|
||||
book.setStatus(BookStatus.fromCode(values.get("status")));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
errors.put("status", "Select a status.");
|
||||
errors.put("status", "请选择状态。");
|
||||
}
|
||||
|
||||
return new BookForm(book, values, errors);
|
||||
@@ -376,7 +376,7 @@ public class BookManagementServlet extends HttpServlet {
|
||||
BookCategory category = new BookCategory();
|
||||
|
||||
if (requireId) {
|
||||
category.setId(parseLong(values.get("id"), "id", "Select a valid category.", errors));
|
||||
category.setId(parseLong(values.get("id"), "id", "请选择有效的分类。", errors));
|
||||
}
|
||||
category.setName(values.get("name"));
|
||||
category.setDescription(values.get("description"));
|
||||
@@ -454,7 +454,7 @@ public class BookManagementServlet extends HttpServlet {
|
||||
}
|
||||
|
||||
private boolean isPermissionDenied(ServiceResult<?> result) {
|
||||
return !result.isSuccessful() && "You do not have permission to manage books.".equals(result.getMessage());
|
||||
return !result.isSuccessful() && "您无权管理图书。".equals(result.getMessage());
|
||||
}
|
||||
|
||||
private void forwardDenied(HttpServletRequest request, HttpServletResponse response, String message)
|
||||
|
||||
@@ -115,7 +115,7 @@ public class BorrowingManagementServlet extends HttpServlet {
|
||||
throws IOException, ServletException {
|
||||
long id = requiredLong(request.getParameter("id"), -1L);
|
||||
ServiceResult<Void> result = id <= 0
|
||||
? ServiceResult.failure("Select a valid borrowing record.")
|
||||
? ServiceResult.failure("请选择有效的借阅记录。")
|
||||
: borrowingService.returnBook(currentUser(request), id);
|
||||
redirectWithResult(request, response, result);
|
||||
}
|
||||
@@ -124,7 +124,7 @@ public class BorrowingManagementServlet extends HttpServlet {
|
||||
throws IOException, ServletException {
|
||||
long id = requiredLong(request.getParameter("id"), -1L);
|
||||
ServiceResult<Void> result = id <= 0
|
||||
? ServiceResult.failure("Select a valid borrowing record.")
|
||||
? ServiceResult.failure("请选择有效的借阅记录。")
|
||||
: borrowingService.renewLoan(currentUser(request), id);
|
||||
redirectWithResult(request, response, result);
|
||||
}
|
||||
@@ -185,12 +185,12 @@ public class BorrowingManagementServlet extends HttpServlet {
|
||||
if (result.hasErrors()) {
|
||||
return result.getErrors().values().iterator().next();
|
||||
}
|
||||
return "Borrowing action failed.";
|
||||
return "借阅操作失败。";
|
||||
}
|
||||
|
||||
private boolean isPermissionDenied(ServiceResult<?> result) {
|
||||
return !result.isSuccessful()
|
||||
&& "You do not have permission to manage borrowing.".equals(result.getMessage());
|
||||
&& "您无权管理借阅。".equals(result.getMessage());
|
||||
}
|
||||
|
||||
private void forwardDenied(HttpServletRequest request, HttpServletResponse response, String message)
|
||||
|
||||
@@ -20,7 +20,7 @@ import javax.servlet.http.HttpSession;
|
||||
public class ReaderLoanHistoryServlet extends HttpServlet {
|
||||
private static final String HISTORY_JSP = "/WEB-INF/jsp/reader/loans.jsp";
|
||||
private static final String UNAUTHORIZED_JSP = "/WEB-INF/jsp/auth/unauthorized.jsp";
|
||||
private static final String HISTORY_DENIED_MESSAGE = "You do not have permission to view loan history.";
|
||||
private static final String HISTORY_DENIED_MESSAGE = "您无权查看借阅历史。";
|
||||
|
||||
private BorrowingServiceImpl borrowingService;
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public class ReaderManagementServlet extends HttpServlet {
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
String path = request.getServletPath();
|
||||
if ("/readers/new".equals(path)) {
|
||||
renderForm(request, response, "Create reader", "/readers", defaultReader(), Collections.emptyMap(),
|
||||
renderForm(request, response, "创建读者", "/readers", defaultReader(), Collections.emptyMap(),
|
||||
Collections.emptyMap(), null);
|
||||
return;
|
||||
}
|
||||
@@ -99,12 +99,12 @@ public class ReaderManagementServlet extends HttpServlet {
|
||||
long id = requiredLong(request.getParameter("id"), -1L);
|
||||
ServiceResult<Optional<Reader>> result = readerService.findReader(id);
|
||||
if (!result.isSuccessful() || !result.getData().isPresent()) {
|
||||
flashError(request, result.isSuccessful() ? "Reader profile was not found." : result.getMessage());
|
||||
flashError(request, result.isSuccessful() ? "未找到读者档案。" : result.getMessage());
|
||||
response.sendRedirect(request.getContextPath() + "/readers");
|
||||
return;
|
||||
}
|
||||
|
||||
renderForm(request, response, "Edit reader", "/readers/update", result.getData().get(),
|
||||
renderForm(request, response, "编辑读者", "/readers/update", result.getData().get(),
|
||||
Collections.emptyMap(), Collections.emptyMap(), null);
|
||||
}
|
||||
|
||||
@@ -112,14 +112,14 @@ public class ReaderManagementServlet extends HttpServlet {
|
||||
throws ServletException, IOException {
|
||||
ReaderForm form = readReaderForm(request, false);
|
||||
if (!form.getErrors().isEmpty()) {
|
||||
renderForm(request, response, "Create reader", "/readers", form.getReader(), form.getValues(),
|
||||
form.getErrors(), "Please correct the highlighted reader fields.");
|
||||
renderForm(request, response, "创建读者", "/readers", form.getReader(), form.getValues(),
|
||||
form.getErrors(), "请修正高亮的读者字段。");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceResult<Long> result = readerService.createReader(currentUser(request), form.getReader());
|
||||
if (!result.isSuccessful()) {
|
||||
handleFormFailure(request, response, "Create reader", "/readers", form, result);
|
||||
handleFormFailure(request, response, "创建读者", "/readers", form, result);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -131,14 +131,14 @@ public class ReaderManagementServlet extends HttpServlet {
|
||||
throws ServletException, IOException {
|
||||
ReaderForm form = readReaderForm(request, true);
|
||||
if (!form.getErrors().isEmpty()) {
|
||||
renderForm(request, response, "Edit reader", "/readers/update", form.getReader(), form.getValues(),
|
||||
form.getErrors(), "Please correct the highlighted reader fields.");
|
||||
renderForm(request, response, "编辑读者", "/readers/update", form.getReader(), form.getValues(),
|
||||
form.getErrors(), "请修正高亮的读者字段。");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceResult<Void> result = readerService.updateReader(currentUser(request), form.getReader());
|
||||
if (!result.isSuccessful()) {
|
||||
handleFormFailure(request, response, "Edit reader", "/readers/update", form, result);
|
||||
handleFormFailure(request, response, "编辑读者", "/readers/update", form, result);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -195,21 +195,21 @@ public class ReaderManagementServlet extends HttpServlet {
|
||||
Reader reader = new Reader();
|
||||
|
||||
if (requireId) {
|
||||
reader.setId(parseLong(values.get("id"), "id", "Select a valid reader.", errors));
|
||||
reader.setId(parseLong(values.get("id"), "id", "请选择有效的读者。", errors));
|
||||
}
|
||||
reader.setIdentifier(values.get("identifier"));
|
||||
reader.setUserId(optionalPositiveLong(values.get("userId"), "userId",
|
||||
"Enter a valid linked account ID.", errors));
|
||||
"请输入有效的关联账户 ID。", errors));
|
||||
reader.setFullName(values.get("fullName"));
|
||||
reader.setPhone(values.get("phone"));
|
||||
reader.setEmail(values.get("email"));
|
||||
reader.setMaxBorrowCount(parseInt(values.get("maxBorrowCount"), "maxBorrowCount",
|
||||
"Enter a valid max borrow count.", errors));
|
||||
"请输入有效的最大借阅数量。", errors));
|
||||
|
||||
try {
|
||||
reader.setStatus(ReaderStatus.fromCode(values.get("status")));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
errors.put("status", "Select a status.");
|
||||
errors.put("status", "请选择状态。");
|
||||
}
|
||||
|
||||
return new ReaderForm(reader, values, errors);
|
||||
@@ -304,7 +304,7 @@ public class ReaderManagementServlet extends HttpServlet {
|
||||
}
|
||||
|
||||
private boolean isPermissionDenied(ServiceResult<?> result) {
|
||||
return !result.isSuccessful() && "You do not have permission to manage readers.".equals(result.getMessage());
|
||||
return !result.isSuccessful() && "您无权管理读者。".equals(result.getMessage());
|
||||
}
|
||||
|
||||
private void forwardDenied(HttpServletRequest request, HttpServletResponse response, String message)
|
||||
|
||||
@@ -46,7 +46,7 @@ public class ReportServlet extends HttpServlet {
|
||||
|
||||
private boolean isPermissionDenied(ServiceResult<?> result) {
|
||||
return !result.isSuccessful()
|
||||
&& "You do not have permission to view reports.".equals(result.getMessage());
|
||||
&& "您无权查看报表。".equals(result.getMessage());
|
||||
}
|
||||
|
||||
private void forwardDenied(HttpServletRequest request, HttpServletResponse response, String message)
|
||||
|
||||
@@ -14,14 +14,14 @@ public class RoleAreaServlet extends HttpServlet {
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
String servletPath = request.getServletPath();
|
||||
if (servletPath.startsWith("/admin")) {
|
||||
request.setAttribute("areaName", "Administration");
|
||||
request.setAttribute("areaSummary", "Account, role, permission, and system-maintenance entry point.");
|
||||
request.setAttribute("areaName", "系统管理");
|
||||
request.setAttribute("areaSummary", "账户、角色、权限和系统维护入口。");
|
||||
} else if (servletPath.startsWith("/librarian")) {
|
||||
request.setAttribute("areaName", "Librarian Workspace");
|
||||
request.setAttribute("areaSummary", "Book, reader, borrowing, return, renewal, and overdue entry point.");
|
||||
request.setAttribute("areaName", "馆员工作台");
|
||||
request.setAttribute("areaSummary", "图书、读者、借阅、归还、续借和逾期处理入口。");
|
||||
} else {
|
||||
request.setAttribute("areaName", "Reader Center");
|
||||
request.setAttribute("areaSummary", "Catalog search and reader self-service entry point.");
|
||||
request.setAttribute("areaName", "读者中心");
|
||||
request.setAttribute("areaSummary", "馆藏检索和读者自助服务入口。");
|
||||
}
|
||||
|
||||
request.getRequestDispatcher(ROLE_HOME_JSP).forward(request, response);
|
||||
|
||||
@@ -21,7 +21,7 @@ import javax.servlet.http.HttpSession;
|
||||
public class SystemLogServlet extends HttpServlet {
|
||||
private static final String LOGS_JSP = "/WEB-INF/jsp/maintenance/system-logs.jsp";
|
||||
private static final String UNAUTHORIZED_JSP = "/WEB-INF/jsp/auth/unauthorized.jsp";
|
||||
private static final String DENIED_MESSAGE = "You do not have permission to view system logs.";
|
||||
private static final String DENIED_MESSAGE = "您无权查看系统日志。";
|
||||
|
||||
private SystemLogService systemLogService;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public class UserManagementServlet extends HttpServlet {
|
||||
private static final String UNAUTHORIZED_JSP = "/WEB-INF/jsp/auth/unauthorized.jsp";
|
||||
private static final String FLASH_SUCCESS = "flashSuccess";
|
||||
private static final String FLASH_ERROR = "flashError";
|
||||
private static final String DENIED_MESSAGE = "You do not have permission to manage users.";
|
||||
private static final String DENIED_MESSAGE = "您无权管理用户。";
|
||||
|
||||
private UserAccountService userAccountService;
|
||||
|
||||
@@ -44,7 +44,7 @@ public class UserManagementServlet extends HttpServlet {
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
String path = request.getServletPath();
|
||||
if ("/admin/users/new".equals(path)) {
|
||||
renderForm(request, response, "Create user account", "/admin/users", defaultUser(),
|
||||
renderForm(request, response, "创建用户账户", "/admin/users", defaultUser(),
|
||||
Collections.emptyMap(), Collections.emptyMap(), null);
|
||||
return;
|
||||
}
|
||||
@@ -108,12 +108,12 @@ public class UserManagementServlet extends HttpServlet {
|
||||
return;
|
||||
}
|
||||
if (!result.isSuccessful() || !result.getData().isPresent()) {
|
||||
flashError(request, result.isSuccessful() ? "User account was not found." : result.getMessage());
|
||||
flashError(request, result.isSuccessful() ? "未找到用户账户。" : result.getMessage());
|
||||
response.sendRedirect(request.getContextPath() + "/admin/users");
|
||||
return;
|
||||
}
|
||||
|
||||
renderForm(request, response, "Edit user account", "/admin/users/update", result.getData().get(),
|
||||
renderForm(request, response, "编辑用户账户", "/admin/users/update", result.getData().get(),
|
||||
Collections.emptyMap(), Collections.emptyMap(), null);
|
||||
}
|
||||
|
||||
@@ -121,15 +121,15 @@ public class UserManagementServlet extends HttpServlet {
|
||||
throws ServletException, IOException {
|
||||
UserForm form = readUserForm(request, false);
|
||||
if (!form.getErrors().isEmpty()) {
|
||||
renderForm(request, response, "Create user account", "/admin/users", form.getUser(), form.getValues(),
|
||||
form.getErrors(), "Please correct the highlighted account fields.");
|
||||
renderForm(request, response, "创建用户账户", "/admin/users", form.getUser(), form.getValues(),
|
||||
form.getErrors(), "请修正高亮的账户字段。");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceResult<Long> result = userAccountService.createUser(currentUser(request), form.getUser(),
|
||||
form.getPassword(), clientIp(request));
|
||||
if (!result.isSuccessful()) {
|
||||
handleFormFailure(request, response, "Create user account", "/admin/users", form, result);
|
||||
handleFormFailure(request, response, "创建用户账户", "/admin/users", form, result);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -141,15 +141,15 @@ public class UserManagementServlet extends HttpServlet {
|
||||
throws ServletException, IOException {
|
||||
UserForm form = readUserForm(request, true);
|
||||
if (!form.getErrors().isEmpty()) {
|
||||
renderForm(request, response, "Edit user account", "/admin/users/update", form.getUser(), form.getValues(),
|
||||
form.getErrors(), "Please correct the highlighted account fields.");
|
||||
renderForm(request, response, "编辑用户账户", "/admin/users/update", form.getUser(), form.getValues(),
|
||||
form.getErrors(), "请修正高亮的账户字段。");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceResult<Void> result = userAccountService.updateUser(currentUser(request), form.getUser(),
|
||||
form.getPassword(), clientIp(request));
|
||||
if (!result.isSuccessful()) {
|
||||
handleFormFailure(request, response, "Edit user account", "/admin/users/update", form, result);
|
||||
handleFormFailure(request, response, "编辑用户账户", "/admin/users/update", form, result);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ public class UserManagementServlet extends HttpServlet {
|
||||
User user = new User();
|
||||
|
||||
if (requireId) {
|
||||
user.setId(parseLong(values.get("id"), "id", "Select a valid user account.", errors));
|
||||
user.setId(parseLong(values.get("id"), "id", "请选择有效的用户账户。", errors));
|
||||
}
|
||||
user.setUsername(values.get("username"));
|
||||
user.setDisplayName(values.get("displayName"));
|
||||
@@ -214,7 +214,7 @@ public class UserManagementServlet extends HttpServlet {
|
||||
try {
|
||||
user.setRole(Role.fromCode(values.get("role")));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
errors.put("role", "Select a role.");
|
||||
errors.put("role", "请选择角色。");
|
||||
}
|
||||
|
||||
return new UserForm(user, values, errors, request.getParameter("password"));
|
||||
@@ -253,7 +253,7 @@ public class UserManagementServlet extends HttpServlet {
|
||||
if ("false".equals(normalized) || UserSearchCriteria.INACTIVE_STATUS.equals(normalized)) {
|
||||
return false;
|
||||
}
|
||||
errors.put("active", "Select an active state.");
|
||||
errors.put("active", "请选择启用状态。");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ package com.mzh.library.entity;
|
||||
import java.util.Locale;
|
||||
|
||||
public enum BookStatus {
|
||||
AVAILABLE("available", "Available"),
|
||||
UNAVAILABLE("unavailable", "Unavailable"),
|
||||
ARCHIVED("archived", "Archived");
|
||||
AVAILABLE("available", "可借"),
|
||||
UNAVAILABLE("unavailable", "不可借"),
|
||||
ARCHIVED("archived", "已归档");
|
||||
|
||||
private final String code;
|
||||
private final String displayName;
|
||||
|
||||
@@ -145,7 +145,7 @@ public class BorrowRecord {
|
||||
}
|
||||
|
||||
public String getDisplayStatusName() {
|
||||
return isOverdue() ? "Overdue" : status.getDisplayName();
|
||||
return isOverdue() ? "逾期" : status.getDisplayName();
|
||||
}
|
||||
|
||||
public String getBorrowedAtText() {
|
||||
|
||||
@@ -3,8 +3,8 @@ package com.mzh.library.entity;
|
||||
import java.util.Locale;
|
||||
|
||||
public enum BorrowRecordStatus {
|
||||
ACTIVE("active", "Active"),
|
||||
RETURNED("returned", "Returned");
|
||||
ACTIVE("active", "借阅中"),
|
||||
RETURNED("returned", "已归还");
|
||||
|
||||
private final String code;
|
||||
private final String displayName;
|
||||
|
||||
@@ -3,9 +3,9 @@ package com.mzh.library.entity;
|
||||
import java.util.Locale;
|
||||
|
||||
public enum ReaderStatus {
|
||||
ACTIVE("active", "Active"),
|
||||
SUSPENDED("suspended", "Suspended"),
|
||||
INACTIVE("inactive", "Inactive");
|
||||
ACTIVE("active", "正常"),
|
||||
SUSPENDED("suspended", "暂停"),
|
||||
INACTIVE("inactive", "停用");
|
||||
|
||||
private final String code;
|
||||
private final String displayName;
|
||||
|
||||
@@ -3,9 +3,9 @@ package com.mzh.library.entity;
|
||||
import java.util.Locale;
|
||||
|
||||
public enum Role {
|
||||
ADMINISTRATOR("administrator", "Administrator"),
|
||||
LIBRARIAN("librarian", "Librarian"),
|
||||
READER("reader", "Reader");
|
||||
ADMINISTRATOR("administrator", "管理员"),
|
||||
LIBRARIAN("librarian", "馆员"),
|
||||
READER("reader", "读者");
|
||||
|
||||
private final String code;
|
||||
private final String displayName;
|
||||
|
||||
@@ -131,7 +131,7 @@ public class SystemLog {
|
||||
return username;
|
||||
}
|
||||
|
||||
return operatorId == null ? "System" : "User #" + operatorId;
|
||||
return operatorId == null ? "系统" : "用户 #" + operatorId;
|
||||
}
|
||||
|
||||
public String getOperatorMetaText() {
|
||||
@@ -144,7 +144,7 @@ public class SystemLog {
|
||||
if (operatorId != null && (!displayName.isEmpty() || !username.isEmpty())) {
|
||||
appendMeta(meta, "#" + operatorId);
|
||||
}
|
||||
appendMeta(meta, trim(operatorRole));
|
||||
appendMeta(meta, displayRole(operatorRole));
|
||||
return meta.toString();
|
||||
}
|
||||
|
||||
@@ -157,8 +157,22 @@ public class SystemLog {
|
||||
}
|
||||
|
||||
public String getResultStatusName() {
|
||||
String trimmed = trim(resultStatus);
|
||||
return trimmed.isEmpty() ? "Unknown" : trimmed;
|
||||
String normalized = trim(resultStatus).toLowerCase(Locale.ROOT);
|
||||
if ("success".equals(normalized)) {
|
||||
return "成功";
|
||||
}
|
||||
if ("failure".equals(normalized)) {
|
||||
return "失败";
|
||||
}
|
||||
return normalized.isEmpty() ? "未知" : trim(resultStatus);
|
||||
}
|
||||
|
||||
public String getTargetTableName() {
|
||||
String normalized = trim(targetTable).toLowerCase(Locale.ROOT);
|
||||
if ("users".equals(normalized)) {
|
||||
return "用户";
|
||||
}
|
||||
return trim(targetTable);
|
||||
}
|
||||
|
||||
private void appendMeta(StringBuilder meta, String value) {
|
||||
@@ -174,4 +188,16 @@ public class SystemLog {
|
||||
private String trim(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
private String displayRole(String roleCode) {
|
||||
String normalized = trim(roleCode);
|
||||
if (normalized.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
return Role.fromCode(normalized).getDisplayName();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public class User {
|
||||
}
|
||||
|
||||
public String getActiveStatusName() {
|
||||
return active ? "Active" : "Inactive";
|
||||
return active ? "启用" : "停用";
|
||||
}
|
||||
|
||||
public String getCreatedAtText() {
|
||||
|
||||
@@ -62,7 +62,7 @@ public class AuthorizationFilter implements Filter {
|
||||
|
||||
logDeniedAccess(user, requiredRule, path);
|
||||
httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
request.setAttribute("errorMessage", "You do not have permission to access this page.");
|
||||
request.setAttribute("errorMessage", "您无权访问此页面。");
|
||||
request.getRequestDispatcher(UNAUTHORIZED_JSP).forward(request, response);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ import java.util.logging.Logger;
|
||||
|
||||
public class AuthServiceImpl implements AuthService {
|
||||
private static final Logger LOGGER = Logger.getLogger(AuthServiceImpl.class.getName());
|
||||
private static final String REQUIRED_MESSAGE = "Username and password are required.";
|
||||
private static final String INVALID_MESSAGE = "Invalid username or password.";
|
||||
private static final String UNAVAILABLE_MESSAGE = "Login service is temporarily unavailable. Please try again later.";
|
||||
private static final String REQUIRED_MESSAGE = "请输入用户名和密码。";
|
||||
private static final String INVALID_MESSAGE = "用户名或密码不正确。";
|
||||
private static final String UNAVAILABLE_MESSAGE = "登录服务暂时不可用,请稍后重试。";
|
||||
|
||||
private final UserDao userDao;
|
||||
private final PermissionPolicy permissionPolicy;
|
||||
|
||||
@@ -21,10 +21,10 @@ import java.util.logging.Logger;
|
||||
public class BookServiceImpl implements BookService {
|
||||
private static final Logger LOGGER = Logger.getLogger(BookServiceImpl.class.getName());
|
||||
private static final String UNAVAILABLE_MESSAGE =
|
||||
"Book service is temporarily unavailable. Please try again later.";
|
||||
private static final String VALIDATION_MESSAGE = "Please correct the highlighted book fields.";
|
||||
private static final String CATEGORY_VALIDATION_MESSAGE = "Please correct the highlighted category fields.";
|
||||
private static final String DENIED_MESSAGE = "You do not have permission to manage books.";
|
||||
"图书服务暂时不可用,请稍后重试。";
|
||||
private static final String VALIDATION_MESSAGE = "请修正高亮的图书字段。";
|
||||
private static final String CATEGORY_VALIDATION_MESSAGE = "请修正高亮的分类字段。";
|
||||
private static final String DENIED_MESSAGE = "您无权管理图书。";
|
||||
|
||||
private final BookDao bookDao;
|
||||
private final PermissionPolicy permissionPolicy;
|
||||
@@ -51,7 +51,7 @@ public class BookServiceImpl implements BookService {
|
||||
@Override
|
||||
public ServiceResult<Optional<BookCategory>> findCategory(long id) {
|
||||
if (id <= 0) {
|
||||
return ServiceResult.failure("Select a valid category.");
|
||||
return ServiceResult.failure("请选择有效的分类。");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -76,13 +76,13 @@ public class BookServiceImpl implements BookService {
|
||||
|
||||
try {
|
||||
if (bookDao.findCategoryByName(category.getName()).isPresent()) {
|
||||
errors.put("name", "Category name is already in use.");
|
||||
errors.put("name", "分类名称已被使用。");
|
||||
return ServiceResult.validationFailure(CATEGORY_VALIDATION_MESSAGE, errors);
|
||||
}
|
||||
|
||||
long id = bookDao.createCategory(category);
|
||||
LOGGER.info("Created book category id=" + id + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(id, "Category created.");
|
||||
return ServiceResult.success(id, "分类已创建。");
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to create book category actorId=" + actor.getId()
|
||||
+ " name=" + safeCategoryName(category), ex);
|
||||
@@ -105,16 +105,16 @@ public class BookServiceImpl implements BookService {
|
||||
try {
|
||||
Optional<BookCategory> existingWithName = bookDao.findCategoryByName(category.getName());
|
||||
if (existingWithName.isPresent() && existingWithName.get().getId() != category.getId()) {
|
||||
errors.put("name", "Category name is already in use.");
|
||||
errors.put("name", "分类名称已被使用。");
|
||||
return ServiceResult.validationFailure(CATEGORY_VALIDATION_MESSAGE, errors);
|
||||
}
|
||||
|
||||
if (!bookDao.updateCategory(category)) {
|
||||
return ServiceResult.failure("Category was not found.");
|
||||
return ServiceResult.failure("未找到分类。");
|
||||
}
|
||||
|
||||
LOGGER.info("Updated book category id=" + category.getId() + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(null, "Category updated.");
|
||||
return ServiceResult.success(null, "分类已更新。");
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to update book category id=" + category.getId()
|
||||
+ " actorId=" + actor.getId(), ex);
|
||||
@@ -128,25 +128,25 @@ public class BookServiceImpl implements BookService {
|
||||
return ServiceResult.failure(DENIED_MESSAGE);
|
||||
}
|
||||
if (id <= 0) {
|
||||
return ServiceResult.failure("Select a valid category.");
|
||||
return ServiceResult.failure("请选择有效的分类。");
|
||||
}
|
||||
|
||||
try {
|
||||
if (!bookDao.findCategoryById(id).isPresent()) {
|
||||
return ServiceResult.failure("Category was not found.");
|
||||
return ServiceResult.failure("未找到分类。");
|
||||
}
|
||||
if (bookDao.countBooksByCategoryId(id) > 0) {
|
||||
Map<String, String> errors = new LinkedHashMap<>();
|
||||
errors.put("category", "Category is used by existing books and cannot be deleted.");
|
||||
return ServiceResult.validationFailure("Category is used by existing books and cannot be deleted.",
|
||||
errors.put("category", "该分类已被现有图书使用,不能删除。");
|
||||
return ServiceResult.validationFailure("该分类已被现有图书使用,不能删除。",
|
||||
errors);
|
||||
}
|
||||
if (!bookDao.deleteCategory(id)) {
|
||||
return ServiceResult.failure("Category was not found.");
|
||||
return ServiceResult.failure("未找到分类。");
|
||||
}
|
||||
|
||||
LOGGER.info("Deleted book category id=" + id + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(null, "Category deleted.");
|
||||
return ServiceResult.success(null, "分类已删除。");
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to delete book category id=" + id + " actorId=" + actor.getId(), ex);
|
||||
return ServiceResult.failure(UNAVAILABLE_MESSAGE);
|
||||
@@ -158,8 +158,8 @@ public class BookServiceImpl implements BookService {
|
||||
BookSearchCriteria normalized = criteria == null ? new BookSearchCriteria() : criteria;
|
||||
if (normalized.getCategoryId() != null && normalized.getCategoryId() <= 0) {
|
||||
Map<String, String> errors = new LinkedHashMap<>();
|
||||
errors.put("categoryId", "Select a valid category.");
|
||||
return ServiceResult.validationFailure("Please correct the catalog search filters.", errors);
|
||||
errors.put("categoryId", "请选择有效的分类。");
|
||||
return ServiceResult.validationFailure("请修正馆藏检索筛选条件。", errors);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -173,7 +173,7 @@ public class BookServiceImpl implements BookService {
|
||||
@Override
|
||||
public ServiceResult<Optional<Book>> findBook(long id) {
|
||||
if (id <= 0) {
|
||||
return ServiceResult.failure("Select a valid book.");
|
||||
return ServiceResult.failure("请选择有效的图书。");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -198,13 +198,13 @@ public class BookServiceImpl implements BookService {
|
||||
|
||||
try {
|
||||
if (bookDao.findByIdentifier(book.getIdentifier()).isPresent()) {
|
||||
errors.put("identifier", "Book identifier is already in use.");
|
||||
errors.put("identifier", "图书编号已被使用。");
|
||||
return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
|
||||
}
|
||||
|
||||
long id = bookDao.create(book);
|
||||
LOGGER.info("Created book id=" + id + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(id, "Book created.");
|
||||
return ServiceResult.success(id, "图书已创建。");
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to create book actorId=" + actor.getId(), ex);
|
||||
return ServiceResult.failure(UNAVAILABLE_MESSAGE);
|
||||
@@ -226,16 +226,16 @@ public class BookServiceImpl implements BookService {
|
||||
try {
|
||||
Optional<Book> existingWithIdentifier = bookDao.findByIdentifier(book.getIdentifier());
|
||||
if (existingWithIdentifier.isPresent() && existingWithIdentifier.get().getId() != book.getId()) {
|
||||
errors.put("identifier", "Book identifier is already in use.");
|
||||
errors.put("identifier", "图书编号已被使用。");
|
||||
return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
|
||||
}
|
||||
|
||||
if (!bookDao.update(book)) {
|
||||
return ServiceResult.failure("Book was not found.");
|
||||
return ServiceResult.failure("未找到图书。");
|
||||
}
|
||||
|
||||
LOGGER.info("Updated book id=" + book.getId() + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(null, "Book updated.");
|
||||
return ServiceResult.success(null, "图书已更新。");
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to update book id=" + book.getId() + " actorId=" + actor.getId(), ex);
|
||||
return ServiceResult.failure(UNAVAILABLE_MESSAGE);
|
||||
@@ -248,16 +248,16 @@ public class BookServiceImpl implements BookService {
|
||||
return ServiceResult.failure(DENIED_MESSAGE);
|
||||
}
|
||||
if (id <= 0) {
|
||||
return ServiceResult.failure("Select a valid book.");
|
||||
return ServiceResult.failure("请选择有效的图书。");
|
||||
}
|
||||
|
||||
try {
|
||||
if (!bookDao.delete(id)) {
|
||||
return ServiceResult.failure("Book was not found.");
|
||||
return ServiceResult.failure("未找到图书。");
|
||||
}
|
||||
|
||||
LOGGER.info("Deleted book id=" + id + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(null, "Book deleted.");
|
||||
return ServiceResult.success(null, "图书已删除。");
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to delete book id=" + id + " actorId=" + actor.getId(), ex);
|
||||
return ServiceResult.failure(UNAVAILABLE_MESSAGE);
|
||||
@@ -288,30 +288,30 @@ public class BookServiceImpl implements BookService {
|
||||
private Map<String, String> validate(Book book, boolean requireId) {
|
||||
Map<String, String> errors = new LinkedHashMap<>();
|
||||
if (book == null) {
|
||||
errors.put("book", "Book details are required.");
|
||||
errors.put("book", "请填写图书详情。");
|
||||
return errors;
|
||||
}
|
||||
|
||||
if (requireId && book.getId() <= 0) {
|
||||
errors.put("id", "Select a valid book.");
|
||||
errors.put("id", "请选择有效的图书。");
|
||||
}
|
||||
requireLength(errors, "identifier", book.getIdentifier(), "Book identifier", 64);
|
||||
requireLength(errors, "title", book.getTitle(), "Title", 200);
|
||||
requireLength(errors, "author", book.getAuthor(), "Author", 120);
|
||||
requireLength(errors, "identifier", book.getIdentifier(), "图书编号", 64);
|
||||
requireLength(errors, "title", book.getTitle(), "书名", 200);
|
||||
requireLength(errors, "author", book.getAuthor(), "作者", 120);
|
||||
if (book.getCategoryId() <= 0) {
|
||||
errors.put("categoryId", "Select a category.");
|
||||
errors.put("categoryId", "请选择分类。");
|
||||
}
|
||||
if (book.getTotalCopies() < 0) {
|
||||
errors.put("totalCopies", "Total copies cannot be negative.");
|
||||
errors.put("totalCopies", "馆藏总数不能为负数。");
|
||||
}
|
||||
if (book.getAvailableCopies() < 0) {
|
||||
errors.put("availableCopies", "Available copies cannot be negative.");
|
||||
errors.put("availableCopies", "可借数量不能为负数。");
|
||||
}
|
||||
if (book.getAvailableCopies() > book.getTotalCopies()) {
|
||||
errors.put("availableCopies", "Available copies cannot exceed total copies.");
|
||||
errors.put("availableCopies", "可借数量不能超过馆藏总数。");
|
||||
}
|
||||
if (book.getStatus() == null) {
|
||||
errors.put("status", "Select a status.");
|
||||
errors.put("status", "请选择状态。");
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
@@ -319,16 +319,16 @@ public class BookServiceImpl implements BookService {
|
||||
private Map<String, String> validate(BookCategory category, boolean requireId) {
|
||||
Map<String, String> errors = new LinkedHashMap<>();
|
||||
if (category == null) {
|
||||
errors.put("category", "Category details are required.");
|
||||
errors.put("category", "请填写分类详情。");
|
||||
return errors;
|
||||
}
|
||||
|
||||
if (requireId && category.getId() <= 0) {
|
||||
errors.put("id", "Select a valid category.");
|
||||
errors.put("id", "请选择有效的分类。");
|
||||
}
|
||||
requireLength(errors, "name", category.getName(), "Category name", 96);
|
||||
requireLength(errors, "name", category.getName(), "分类名称", 96);
|
||||
if (category.getDescription() != null && category.getDescription().length() > 255) {
|
||||
errors.put("description", "Description must be 255 characters or fewer.");
|
||||
errors.put("description", "说明不能超过 255 个字符。");
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
@@ -339,11 +339,11 @@ public class BookServiceImpl implements BookService {
|
||||
|
||||
private void requireLength(Map<String, String> errors, String field, String value, String label, int maxLength) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
errors.put(field, label + " is required.");
|
||||
errors.put(field, "请填写" + label + "。");
|
||||
return;
|
||||
}
|
||||
if (value.length() > maxLength) {
|
||||
errors.put(field, label + " must be " + maxLength + " characters or fewer.");
|
||||
errors.put(field, label + "不能超过 " + maxLength + " 个字符。");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,10 +35,10 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(BorrowingServiceImpl.class.getName());
|
||||
private static final String UNAVAILABLE_MESSAGE =
|
||||
"Borrowing service is temporarily unavailable. Please try again later.";
|
||||
private static final String VALIDATION_MESSAGE = "Please correct the highlighted borrowing fields.";
|
||||
private static final String DENIED_MESSAGE = "You do not have permission to manage borrowing.";
|
||||
private static final String HISTORY_DENIED_MESSAGE = "You do not have permission to view loan history.";
|
||||
"借阅服务暂时不可用,请稍后重试。";
|
||||
private static final String VALIDATION_MESSAGE = "请修正高亮的借阅字段。";
|
||||
private static final String DENIED_MESSAGE = "您无权管理借阅。";
|
||||
private static final String HISTORY_DENIED_MESSAGE = "您无权查看借阅历史。";
|
||||
private static final int LOAN_DAYS = 14;
|
||||
private static final int MAX_RENEWALS = 1;
|
||||
|
||||
@@ -68,7 +68,7 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
BorrowRecordSearchCriteria normalized = criteria == null ? new BorrowRecordSearchCriteria() : criteria;
|
||||
Map<String, String> errors = validateSearch(normalized);
|
||||
if (!errors.isEmpty()) {
|
||||
return ServiceResult.validationFailure("Please correct the borrowing search filters.", errors);
|
||||
return ServiceResult.validationFailure("请修正借阅检索筛选条件。", errors);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -98,13 +98,13 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
Optional<Reader> readerResult = borrowRecordDao.findReaderByIdentifierForUpdate(connection,
|
||||
normalizedReaderIdentifier);
|
||||
if (!readerResult.isPresent()) {
|
||||
transactionErrors.put("readerIdentifier", "Reader was not found.");
|
||||
transactionErrors.put("readerIdentifier", "未找到读者。");
|
||||
}
|
||||
|
||||
Optional<Book> bookResult = borrowRecordDao.findBookByIdentifierForUpdate(connection,
|
||||
normalizedBookIdentifier);
|
||||
if (!bookResult.isPresent()) {
|
||||
transactionErrors.put("bookIdentifier", "Book was not found.");
|
||||
transactionErrors.put("bookIdentifier", "未找到图书。");
|
||||
}
|
||||
|
||||
if (!transactionErrors.isEmpty()) {
|
||||
@@ -134,7 +134,7 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
|
||||
LOGGER.info("Borrowed book recordId=" + id + " readerId=" + reader.getId()
|
||||
+ " bookId=" + book.getId() + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(id, "Book borrowed.");
|
||||
return ServiceResult.success(id, "图书已借出。");
|
||||
});
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to borrow book actorId=" + actor.getId()
|
||||
@@ -150,20 +150,20 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
return ServiceResult.failure(DENIED_MESSAGE);
|
||||
}
|
||||
if (recordId <= 0) {
|
||||
return ServiceResult.failure("Select a valid borrowing record.");
|
||||
return ServiceResult.failure("请选择有效的借阅记录。");
|
||||
}
|
||||
|
||||
try {
|
||||
return transactionExecutor.execute(connection -> {
|
||||
Optional<BorrowRecord> recordResult = borrowRecordDao.findByIdForUpdate(connection, recordId);
|
||||
if (!recordResult.isPresent()) {
|
||||
return ServiceResult.failure("Borrowing record was not found.");
|
||||
return ServiceResult.failure("未找到借阅记录。");
|
||||
}
|
||||
|
||||
BorrowRecord record = recordResult.get();
|
||||
Map<String, String> errors = validateActiveLoan(record);
|
||||
if (!errors.isEmpty()) {
|
||||
return ServiceResult.validationFailure("Borrowing record cannot be returned.", errors);
|
||||
return ServiceResult.validationFailure("借阅记录不能归还。", errors);
|
||||
}
|
||||
|
||||
if (!borrowRecordDao.markReturned(connection, recordId, now())) {
|
||||
@@ -172,7 +172,7 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
borrowRecordDao.incrementAvailableCopies(connection, record.getBookId());
|
||||
|
||||
LOGGER.info("Returned borrow recordId=" + recordId + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(null, "Book returned.");
|
||||
return ServiceResult.success(null, "图书已归还。");
|
||||
});
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to return borrow record id=" + recordId + " actorId=" + actor.getId(), ex);
|
||||
@@ -186,23 +186,23 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
return ServiceResult.failure(DENIED_MESSAGE);
|
||||
}
|
||||
if (recordId <= 0) {
|
||||
return ServiceResult.failure("Select a valid borrowing record.");
|
||||
return ServiceResult.failure("请选择有效的借阅记录。");
|
||||
}
|
||||
|
||||
try {
|
||||
return transactionExecutor.execute(connection -> {
|
||||
Optional<BorrowRecord> recordResult = borrowRecordDao.findByIdForUpdate(connection, recordId);
|
||||
if (!recordResult.isPresent()) {
|
||||
return ServiceResult.failure("Borrowing record was not found.");
|
||||
return ServiceResult.failure("未找到借阅记录。");
|
||||
}
|
||||
|
||||
BorrowRecord record = recordResult.get();
|
||||
Map<String, String> errors = validateActiveLoan(record);
|
||||
if (record.getRenewalCount() >= MAX_RENEWALS) {
|
||||
errors.put("renewalCount", "This loan has already reached the renewal limit.");
|
||||
errors.put("renewalCount", "该借阅已达到续借次数上限。");
|
||||
}
|
||||
if (!errors.isEmpty()) {
|
||||
return ServiceResult.validationFailure("Borrowing record cannot be renewed.", errors);
|
||||
return ServiceResult.validationFailure("借阅记录不能续借。", errors);
|
||||
}
|
||||
|
||||
LocalDateTime currentDueAt = record.getDueAt() == null ? now() : record.getDueAt();
|
||||
@@ -212,7 +212,7 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
}
|
||||
|
||||
LOGGER.info("Renewed borrow recordId=" + recordId + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(null, "Loan renewed.");
|
||||
return ServiceResult.success(null, "借阅已续借。");
|
||||
});
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to renew borrow record id=" + recordId + " actorId=" + actor.getId(), ex);
|
||||
@@ -229,7 +229,7 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
try {
|
||||
Optional<Reader> readerResult = borrowRecordDao.findReaderByUserId(actor.getId());
|
||||
if (!readerResult.isPresent()) {
|
||||
return ServiceResult.success(Collections.emptyList(), "No reader profile is linked to your account.");
|
||||
return ServiceResult.success(Collections.emptyList(), "您的账户未关联读者档案。");
|
||||
}
|
||||
|
||||
return ServiceResult.success(borrowRecordDao.findByReaderId(readerResult.get().getId()));
|
||||
@@ -246,16 +246,16 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
private void validateBorrowEligibility(Map<String, String> errors, Reader reader, Book book,
|
||||
java.sql.Connection connection) {
|
||||
if (reader.getStatus() != ReaderStatus.ACTIVE) {
|
||||
errors.put("readerIdentifier", "Reader must be active to borrow books.");
|
||||
errors.put("readerIdentifier", "读者状态必须为正常才能借阅图书。");
|
||||
}
|
||||
int activeLoans = borrowRecordDao.countActiveByReaderId(connection, reader.getId());
|
||||
if (activeLoans >= reader.getMaxBorrowCount()) {
|
||||
errors.put("readerIdentifier", "Reader has reached the active borrowing limit.");
|
||||
errors.put("readerIdentifier", "读者已达到在借数量上限。");
|
||||
}
|
||||
if (book.getStatus() != BookStatus.AVAILABLE) {
|
||||
errors.put("bookIdentifier", "Book status does not allow borrowing.");
|
||||
errors.put("bookIdentifier", "图书状态不允许借阅。");
|
||||
} else if (book.getAvailableCopies() <= 0) {
|
||||
errors.put("bookIdentifier", "No available copies remain for this book.");
|
||||
errors.put("bookIdentifier", "该图书没有可借副本。");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
try {
|
||||
BorrowRecordStatus.fromCode(statusCode);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
errors.put("status", "Select a valid borrowing status.");
|
||||
errors.put("status", "请选择有效的借阅状态。");
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
@@ -278,26 +278,26 @@ public class BorrowingServiceImpl implements BorrowingService {
|
||||
|
||||
private Map<String, String> validateBorrowIdentifiers(String readerIdentifier, String bookIdentifier) {
|
||||
Map<String, String> errors = new LinkedHashMap<>();
|
||||
requireLength(errors, "readerIdentifier", readerIdentifier, "Reader ID", 64);
|
||||
requireLength(errors, "bookIdentifier", bookIdentifier, "Book ID", 64);
|
||||
requireLength(errors, "readerIdentifier", readerIdentifier, "读者编号", 64);
|
||||
requireLength(errors, "bookIdentifier", bookIdentifier, "图书编号", 64);
|
||||
return errors;
|
||||
}
|
||||
|
||||
private Map<String, String> validateActiveLoan(BorrowRecord record) {
|
||||
Map<String, String> errors = new LinkedHashMap<>();
|
||||
if (record.getStatus() != BorrowRecordStatus.ACTIVE || record.getReturnedAt() != null) {
|
||||
errors.put("status", "Only active loans can use this action.");
|
||||
errors.put("status", "只有借阅中的记录可以执行此操作。");
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
private void requireLength(Map<String, String> errors, String field, String value, String label, int maxLength) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
errors.put(field, label + " is required.");
|
||||
errors.put(field, "请填写" + label + "。");
|
||||
return;
|
||||
}
|
||||
if (value.length() > maxLength) {
|
||||
errors.put(field, label + " must be " + maxLength + " characters or fewer.");
|
||||
errors.put(field, label + "不能超过 " + maxLength + " 个字符。");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@ import java.util.logging.Logger;
|
||||
public class ReaderServiceImpl implements ReaderService {
|
||||
private static final Logger LOGGER = Logger.getLogger(ReaderServiceImpl.class.getName());
|
||||
private static final String UNAVAILABLE_MESSAGE =
|
||||
"Reader service is temporarily unavailable. Please try again later.";
|
||||
private static final String VALIDATION_MESSAGE = "Please correct the highlighted reader fields.";
|
||||
private static final String SEARCH_VALIDATION_MESSAGE = "Please correct the reader search filters.";
|
||||
private static final String DENIED_MESSAGE = "You do not have permission to manage readers.";
|
||||
"读者服务暂时不可用,请稍后重试。";
|
||||
private static final String VALIDATION_MESSAGE = "请修正高亮的读者字段。";
|
||||
private static final String SEARCH_VALIDATION_MESSAGE = "请修正读者检索筛选条件。";
|
||||
private static final String DENIED_MESSAGE = "您无权管理读者。";
|
||||
private static final int MAX_BORROW_LIMIT = 50;
|
||||
private static final Pattern PHONE_PATTERN = Pattern.compile("(?=.*\\d)[0-9+()\\-\\s]{6,32}");
|
||||
private static final Pattern EMAIL_PATTERN = Pattern.compile("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$");
|
||||
@@ -61,7 +61,7 @@ public class ReaderServiceImpl implements ReaderService {
|
||||
@Override
|
||||
public ServiceResult<Optional<Reader>> findReader(long id) {
|
||||
if (id <= 0) {
|
||||
return ServiceResult.failure("Select a valid reader.");
|
||||
return ServiceResult.failure("请选择有效的读者。");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -86,17 +86,17 @@ public class ReaderServiceImpl implements ReaderService {
|
||||
|
||||
try {
|
||||
if (readerDao.findByIdentifier(reader.getIdentifier()).isPresent()) {
|
||||
errors.put("identifier", "Reader identifier is already in use.");
|
||||
errors.put("identifier", "读者编号已被使用。");
|
||||
return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
|
||||
}
|
||||
if (reader.getUserId() != null && readerDao.findByUserId(reader.getUserId()).isPresent()) {
|
||||
errors.put("userId", "Linked account is already assigned to a reader profile.");
|
||||
errors.put("userId", "关联账户已绑定到其他读者档案。");
|
||||
return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
|
||||
}
|
||||
|
||||
long id = readerDao.create(reader);
|
||||
LOGGER.info("Created reader id=" + id + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(id, "Reader profile created.");
|
||||
return ServiceResult.success(id, "读者档案已创建。");
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to create reader actorId=" + actor.getId(), ex);
|
||||
return ServiceResult.failure(UNAVAILABLE_MESSAGE);
|
||||
@@ -118,23 +118,23 @@ public class ReaderServiceImpl implements ReaderService {
|
||||
try {
|
||||
Optional<Reader> existingWithIdentifier = readerDao.findByIdentifier(reader.getIdentifier());
|
||||
if (existingWithIdentifier.isPresent() && existingWithIdentifier.get().getId() != reader.getId()) {
|
||||
errors.put("identifier", "Reader identifier is already in use.");
|
||||
errors.put("identifier", "读者编号已被使用。");
|
||||
return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
|
||||
}
|
||||
if (reader.getUserId() != null) {
|
||||
Optional<Reader> existingWithUser = readerDao.findByUserId(reader.getUserId());
|
||||
if (existingWithUser.isPresent() && existingWithUser.get().getId() != reader.getId()) {
|
||||
errors.put("userId", "Linked account is already assigned to a reader profile.");
|
||||
errors.put("userId", "关联账户已绑定到其他读者档案。");
|
||||
return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
|
||||
}
|
||||
}
|
||||
|
||||
if (!readerDao.update(reader)) {
|
||||
return ServiceResult.failure("Reader profile was not found.");
|
||||
return ServiceResult.failure("未找到读者档案。");
|
||||
}
|
||||
|
||||
LOGGER.info("Updated reader id=" + reader.getId() + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(null, "Reader profile updated.");
|
||||
return ServiceResult.success(null, "读者档案已更新。");
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to update reader id=" + reader.getId() + " actorId=" + actor.getId(), ex);
|
||||
return ServiceResult.failure(UNAVAILABLE_MESSAGE);
|
||||
@@ -147,16 +147,16 @@ public class ReaderServiceImpl implements ReaderService {
|
||||
return ServiceResult.failure(DENIED_MESSAGE);
|
||||
}
|
||||
if (id <= 0) {
|
||||
return ServiceResult.failure("Select a valid reader.");
|
||||
return ServiceResult.failure("请选择有效的读者。");
|
||||
}
|
||||
|
||||
try {
|
||||
if (!readerDao.deactivate(id)) {
|
||||
return ServiceResult.failure("Reader profile was not found.");
|
||||
return ServiceResult.failure("未找到读者档案。");
|
||||
}
|
||||
|
||||
LOGGER.info("Deactivated reader id=" + id + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(null, "Reader profile deactivated.");
|
||||
return ServiceResult.success(null, "读者档案已停用。");
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to deactivate reader id=" + id + " actorId=" + actor.getId(), ex);
|
||||
return ServiceResult.failure(UNAVAILABLE_MESSAGE);
|
||||
@@ -183,7 +183,7 @@ public class ReaderServiceImpl implements ReaderService {
|
||||
try {
|
||||
criteria.setStatusCode(ReaderStatus.fromCode(criteria.getStatusCode()).getCode());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
errors.put("status", "Select a valid status.");
|
||||
errors.put("status", "请选择有效的状态。");
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
@@ -192,24 +192,24 @@ public class ReaderServiceImpl implements ReaderService {
|
||||
private Map<String, String> validate(Reader reader, boolean requireId) {
|
||||
Map<String, String> errors = new LinkedHashMap<>();
|
||||
if (reader == null) {
|
||||
errors.put("reader", "Reader details are required.");
|
||||
errors.put("reader", "请填写读者详情。");
|
||||
return errors;
|
||||
}
|
||||
|
||||
if (requireId && reader.getId() <= 0) {
|
||||
errors.put("id", "Select a valid reader.");
|
||||
errors.put("id", "请选择有效的读者。");
|
||||
}
|
||||
requireLength(errors, "identifier", reader.getIdentifier(), "Reader identifier", 64);
|
||||
requireLength(errors, "fullName", reader.getFullName(), "Full name", 100);
|
||||
requireLength(errors, "identifier", reader.getIdentifier(), "读者编号", 64);
|
||||
requireLength(errors, "fullName", reader.getFullName(), "姓名", 100);
|
||||
if (reader.getUserId() != null && reader.getUserId() <= 0) {
|
||||
errors.put("userId", "Linked account ID must be positive.");
|
||||
errors.put("userId", "关联账户 ID 必须为正数。");
|
||||
}
|
||||
validateContact(errors, reader);
|
||||
if (reader.getStatus() == null) {
|
||||
errors.put("status", "Select a status.");
|
||||
errors.put("status", "请选择状态。");
|
||||
}
|
||||
if (reader.getMaxBorrowCount() < 1 || reader.getMaxBorrowCount() > MAX_BORROW_LIMIT) {
|
||||
errors.put("maxBorrowCount", "Max borrow count must be between 1 and " + MAX_BORROW_LIMIT + ".");
|
||||
errors.put("maxBorrowCount", "最大借阅数量必须在 1 到 " + MAX_BORROW_LIMIT + " 之间。");
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
@@ -218,24 +218,24 @@ public class ReaderServiceImpl implements ReaderService {
|
||||
String phone = reader.getPhone();
|
||||
String email = reader.getEmail();
|
||||
if ((phone == null || phone.isEmpty()) && (email == null || email.isEmpty())) {
|
||||
errors.put("phone", "Phone or email is required.");
|
||||
errors.put("phone", "请填写电话或邮箱。");
|
||||
return;
|
||||
}
|
||||
if (phone != null && !phone.isEmpty() && !PHONE_PATTERN.matcher(phone).matches()) {
|
||||
errors.put("phone", "Phone must include a digit and use 6 to 32 digits or common phone symbols.");
|
||||
errors.put("phone", "电话必须包含数字,并使用 6 到 32 位数字或常见电话符号。");
|
||||
}
|
||||
if (email != null && !email.isEmpty() && !EMAIL_PATTERN.matcher(email).matches()) {
|
||||
errors.put("email", "Email must be a valid address.");
|
||||
errors.put("email", "邮箱格式不正确。");
|
||||
}
|
||||
}
|
||||
|
||||
private void requireLength(Map<String, String> errors, String field, String value, String label, int maxLength) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
errors.put(field, label + " is required.");
|
||||
errors.put(field, "请填写" + label + "。");
|
||||
return;
|
||||
}
|
||||
if (value.length() > maxLength) {
|
||||
errors.put(field, label + " must be " + maxLength + " characters or fewer.");
|
||||
errors.put(field, label + "不能超过 " + maxLength + " 个字符。");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ import java.util.logging.Logger;
|
||||
public class ReportServiceImpl implements ReportService {
|
||||
private static final Logger LOGGER = Logger.getLogger(ReportServiceImpl.class.getName());
|
||||
private static final String UNAVAILABLE_MESSAGE =
|
||||
"Report service is temporarily unavailable. Please try again later.";
|
||||
private static final String DENIED_MESSAGE = "You do not have permission to view reports.";
|
||||
"报表服务暂时不可用,请稍后重试。";
|
||||
private static final String DENIED_MESSAGE = "您无权查看报表。";
|
||||
private static final int POPULAR_BOOK_LIMIT = 10;
|
||||
|
||||
private final ReportDao reportDao;
|
||||
|
||||
@@ -20,9 +20,9 @@ import java.util.logging.Logger;
|
||||
public class SystemLogServiceImpl implements SystemLogService {
|
||||
private static final Logger LOGGER = Logger.getLogger(SystemLogServiceImpl.class.getName());
|
||||
private static final String UNAVAILABLE_MESSAGE =
|
||||
"System log service is temporarily unavailable. Please try again later.";
|
||||
private static final String DENIED_MESSAGE = "You do not have permission to view system logs.";
|
||||
private static final String VALIDATION_MESSAGE = "Please correct the system log search filters.";
|
||||
"系统日志服务暂时不可用,请稍后重试。";
|
||||
private static final String DENIED_MESSAGE = "您无权查看系统日志。";
|
||||
private static final String VALIDATION_MESSAGE = "请修正系统日志检索筛选条件。";
|
||||
|
||||
private final SystemLogDao systemLogDao;
|
||||
private final PermissionPolicy permissionPolicy;
|
||||
@@ -62,18 +62,18 @@ public class SystemLogServiceImpl implements SystemLogService {
|
||||
private Map<String, String> validate(SystemLogSearchCriteria criteria) {
|
||||
Map<String, String> errors = new LinkedHashMap<>();
|
||||
if (criteria.getOperationType().length() > 64) {
|
||||
errors.put("operationType", "Operation type must be 64 characters or fewer.");
|
||||
errors.put("operationType", "操作类型不能超过 64 个字符。");
|
||||
}
|
||||
if (criteria.getKeyword().length() > 120) {
|
||||
errors.put("keyword", "Keyword must be 120 characters or fewer.");
|
||||
errors.put("keyword", "关键词不能超过 120 个字符。");
|
||||
}
|
||||
|
||||
parseDate(criteria.getCreatedFromText(), "createdFrom", "Start date", errors, criteria, true);
|
||||
parseDate(criteria.getCreatedToText(), "createdTo", "End date", errors, criteria, false);
|
||||
parseDate(criteria.getCreatedFromText(), "createdFrom", "开始日期", errors, criteria, true);
|
||||
parseDate(criteria.getCreatedToText(), "createdTo", "结束日期", errors, criteria, false);
|
||||
if (criteria.getCreatedFrom() != null
|
||||
&& criteria.getCreatedTo() != null
|
||||
&& criteria.getCreatedFrom().isAfter(criteria.getCreatedTo())) {
|
||||
errors.put("createdTo", "End date must be on or after start date.");
|
||||
errors.put("createdTo", "结束日期必须晚于或等于开始日期。");
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
@@ -91,7 +91,7 @@ public class SystemLogServiceImpl implements SystemLogService {
|
||||
criteria.setCreatedTo(parsed);
|
||||
}
|
||||
} catch (DateTimeParseException ex) {
|
||||
errors.put(field, label + " must use YYYY-MM-DD.");
|
||||
errors.put(field, label + "必须使用 YYYY-MM-DD 格式。");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,12 +30,12 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(UserAccountServiceImpl.class.getName());
|
||||
private static final String UNAVAILABLE_MESSAGE =
|
||||
"User management service is temporarily unavailable. Please try again later.";
|
||||
private static final String VALIDATION_MESSAGE = "Please correct the highlighted account fields.";
|
||||
private static final String SEARCH_VALIDATION_MESSAGE = "Please correct the account search filters.";
|
||||
private static final String DENIED_MESSAGE = "You do not have permission to manage users.";
|
||||
private static final String SELF_DEACTIVATE_MESSAGE = "You cannot deactivate your own administrator account.";
|
||||
private static final String SELF_ROLE_MESSAGE = "You cannot change your own administrator role.";
|
||||
"用户管理服务暂时不可用,请稍后重试。";
|
||||
private static final String VALIDATION_MESSAGE = "请修正高亮的账户字段。";
|
||||
private static final String SEARCH_VALIDATION_MESSAGE = "请修正账户检索筛选条件。";
|
||||
private static final String DENIED_MESSAGE = "您无权管理用户。";
|
||||
private static final String SELF_DEACTIVATE_MESSAGE = "不能停用您自己的管理员账户。";
|
||||
private static final String SELF_ROLE_MESSAGE = "不能修改您自己的管理员角色。";
|
||||
|
||||
private final UserAccountDao userAccountDao;
|
||||
private final SystemLogDao systemLogDao;
|
||||
@@ -80,7 +80,7 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
return ServiceResult.failure(DENIED_MESSAGE);
|
||||
}
|
||||
if (id <= 0) {
|
||||
return ServiceResult.failure("Select a valid user account.");
|
||||
return ServiceResult.failure("请选择有效的用户账户。");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -105,7 +105,7 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
|
||||
try {
|
||||
if (userAccountDao.findByUsername(user.getUsername()).isPresent()) {
|
||||
errors.put("username", "Username is already in use.");
|
||||
errors.put("username", "用户名已被使用。");
|
||||
return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
|
||||
}
|
||||
|
||||
@@ -113,10 +113,10 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
return transactionExecutor.execute(connection -> {
|
||||
long id = userAccountDao.create(connection, user);
|
||||
systemLogDao.create(connection, auditLog(actor, "user.create", id,
|
||||
"Created account username=" + user.getUsername() + " role=" + user.getRole().getCode(),
|
||||
"创建账户:用户名=" + user.getUsername() + ",角色=" + user.getRole().getDisplayName(),
|
||||
requestIp));
|
||||
LOGGER.info("Created user id=" + id + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(id, "User account created.");
|
||||
return ServiceResult.success(id, "用户账户已创建。");
|
||||
});
|
||||
} catch (DaoException | IllegalStateException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to create user actorId=" + actor.getId()
|
||||
@@ -140,7 +140,7 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
try {
|
||||
Optional<User> existingResult = userAccountDao.findById(user.getId());
|
||||
if (!existingResult.isPresent()) {
|
||||
return ServiceResult.failure("User account was not found.");
|
||||
return ServiceResult.failure("未找到用户账户。");
|
||||
}
|
||||
|
||||
protectCurrentAdministrator(actor, user, errors);
|
||||
@@ -158,15 +158,15 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
final boolean passwordChanged = updatePassword;
|
||||
return transactionExecutor.execute(connection -> {
|
||||
if (!userAccountDao.update(connection, user, passwordChanged)) {
|
||||
return ServiceResult.failure("User account was not found.");
|
||||
return ServiceResult.failure("未找到用户账户。");
|
||||
}
|
||||
systemLogDao.create(connection, auditLog(actor, "user.update", user.getId(),
|
||||
"Updated account username=" + user.getUsername() + " role=" + user.getRole().getCode()
|
||||
+ " active=" + user.isActive()
|
||||
+ (passwordChanged ? " passwordReset=true" : ""),
|
||||
"更新账户:用户名=" + user.getUsername() + ",角色=" + user.getRole().getDisplayName()
|
||||
+ ",状态=" + (user.isActive() ? "启用" : "停用")
|
||||
+ (passwordChanged ? ",已重置密码" : ""),
|
||||
requestIp));
|
||||
LOGGER.info("Updated user id=" + user.getId() + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(null, "User account updated.");
|
||||
return ServiceResult.success(null, "用户账户已更新。");
|
||||
});
|
||||
} catch (DaoException | IllegalStateException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to update user id=" + user.getId() + " actorId=" + actor.getId(), ex);
|
||||
@@ -180,7 +180,7 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
return ServiceResult.failure(DENIED_MESSAGE);
|
||||
}
|
||||
if (id <= 0) {
|
||||
return ServiceResult.failure("Select a valid user account.");
|
||||
return ServiceResult.failure("请选择有效的用户账户。");
|
||||
}
|
||||
if (actor.getId() == id) {
|
||||
Map<String, String> errors = new LinkedHashMap<>();
|
||||
@@ -191,20 +191,20 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
try {
|
||||
Optional<User> existingResult = userAccountDao.findById(id);
|
||||
if (!existingResult.isPresent()) {
|
||||
return ServiceResult.failure("User account was not found.");
|
||||
return ServiceResult.failure("未找到用户账户。");
|
||||
}
|
||||
|
||||
User user = existingResult.get();
|
||||
user.setActive(false);
|
||||
return transactionExecutor.execute(connection -> {
|
||||
if (!userAccountDao.update(connection, user, false)) {
|
||||
return ServiceResult.failure("User account was not found.");
|
||||
return ServiceResult.failure("未找到用户账户。");
|
||||
}
|
||||
systemLogDao.create(connection, auditLog(actor, "user.deactivate", id,
|
||||
"Deactivated account username=" + user.getUsername(),
|
||||
"停用账户:用户名=" + user.getUsername(),
|
||||
requestIp));
|
||||
LOGGER.info("Deactivated user id=" + id + " actorId=" + actor.getId());
|
||||
return ServiceResult.success(null, "User account deactivated.");
|
||||
return ServiceResult.success(null, "用户账户已停用。");
|
||||
});
|
||||
} catch (DaoException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to deactivate user id=" + id + " actorId=" + actor.getId(), ex);
|
||||
@@ -218,7 +218,7 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
try {
|
||||
criteria.setRoleCode(Role.fromCode(criteria.getRoleCode()).getCode());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
errors.put("role", "Select a valid role.");
|
||||
errors.put("role", "请选择有效的角色。");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
if (!activeStatus.isEmpty()
|
||||
&& !UserSearchCriteria.ACTIVE_STATUS.equals(activeStatus)
|
||||
&& !UserSearchCriteria.INACTIVE_STATUS.equals(activeStatus)) {
|
||||
errors.put("active", "Select a valid active state.");
|
||||
errors.put("active", "请选择有效的启用状态。");
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
@@ -234,19 +234,19 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
private Map<String, String> validateUser(User user, boolean requireId, String password, boolean requirePassword) {
|
||||
Map<String, String> errors = new LinkedHashMap<>();
|
||||
if (user == null) {
|
||||
errors.put("user", "User account details are required.");
|
||||
errors.put("user", "请填写用户账户详情。");
|
||||
return errors;
|
||||
}
|
||||
|
||||
if (requireId && user.getId() <= 0) {
|
||||
errors.put("id", "Select a valid user account.");
|
||||
errors.put("id", "请选择有效的用户账户。");
|
||||
}
|
||||
if (!requireId) {
|
||||
requireLength(errors, "username", user.getUsername(), "Username", 64);
|
||||
requireLength(errors, "username", user.getUsername(), "用户名", 64);
|
||||
}
|
||||
requireLength(errors, "displayName", user.getDisplayName(), "Display name", 100);
|
||||
requireLength(errors, "displayName", user.getDisplayName(), "显示名称", 100);
|
||||
if (user.getRole() == null) {
|
||||
errors.put("role", "Select a role.");
|
||||
errors.put("role", "请选择角色。");
|
||||
}
|
||||
validatePassword(errors, password, requirePassword);
|
||||
return errors;
|
||||
@@ -256,12 +256,12 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
String trimmed = password == null ? "" : password.trim();
|
||||
if (trimmed.isEmpty()) {
|
||||
if (required) {
|
||||
errors.put("password", "Password is required.");
|
||||
errors.put("password", "请填写密码。");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (password.length() > 128) {
|
||||
errors.put("password", "Password must be 128 characters or fewer.");
|
||||
errors.put("password", "密码不能超过 128 个字符。");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,11 +279,11 @@ public class UserAccountServiceImpl implements UserAccountService {
|
||||
|
||||
private void requireLength(Map<String, String> errors, String field, String value, String label, int maxLength) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
errors.put(field, label + " is required.");
|
||||
errors.put(field, "请填写" + label + "。");
|
||||
return;
|
||||
}
|
||||
if (value.length() > maxLength) {
|
||||
errors.put(field, label + " must be " + maxLength + " characters or fewer.");
|
||||
errors.put(field, label + "不能超过 " + maxLength + " 个字符。");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><c:out value="${formTitle}" /> - MZH Library</title>
|
||||
<title><c:out value="${formTitle}" /> - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
<%@ include file="/WEB-INF/jsp/common/header.jspf" %>
|
||||
<main class="page-shell">
|
||||
<section class="form-panel" aria-labelledby="user-form-title">
|
||||
<p class="eyebrow">Administration</p>
|
||||
<p class="eyebrow">系统管理</p>
|
||||
<h1 id="user-form-title"><c:out value="${formTitle}" /></h1>
|
||||
|
||||
<c:if test="${not empty errorMessage}">
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<div class="form-grid">
|
||||
<div class="form-field">
|
||||
<label for="username">Username</label>
|
||||
<label for="username">用户名</label>
|
||||
<c:choose>
|
||||
<c:when test="${user.id > 0}">
|
||||
<input id="username" type="text" value="${fn:escapeXml(usernameValue)}" disabled>
|
||||
@@ -51,7 +51,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="displayName">Display name</label>
|
||||
<label for="displayName">显示名称</label>
|
||||
<input id="displayName" name="displayName" type="text"
|
||||
value="${fn:escapeXml(displayNameValue)}" required>
|
||||
<c:if test="${not empty errors.displayName}">
|
||||
@@ -60,9 +60,9 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="role">Role</label>
|
||||
<label for="role">角色</label>
|
||||
<select id="role" name="role" required>
|
||||
<option value="">Select role</option>
|
||||
<option value="">请选择角色</option>
|
||||
<c:forEach var="role" items="${roles}">
|
||||
<option value="${role.code}" <c:if test="${roleValue == role.code}">selected</c:if>>
|
||||
<c:out value="${role.displayName}" />
|
||||
@@ -75,13 +75,13 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="active">Active state</label>
|
||||
<label for="active">启用状态</label>
|
||||
<select id="active" name="active" required>
|
||||
<option value="true" <c:if test="${activeValue == true or activeValue == 'true'}">selected</c:if>>
|
||||
Active
|
||||
启用
|
||||
</option>
|
||||
<option value="false" <c:if test="${activeValue == false or activeValue == 'false'}">selected</c:if>>
|
||||
Inactive
|
||||
停用
|
||||
</option>
|
||||
</select>
|
||||
<c:if test="${not empty errors.active}">
|
||||
@@ -92,8 +92,8 @@
|
||||
<div class="form-field">
|
||||
<label for="password">
|
||||
<c:choose>
|
||||
<c:when test="${user.id > 0}">New password</c:when>
|
||||
<c:otherwise>Password</c:otherwise>
|
||||
<c:when test="${user.id > 0}">新密码</c:when>
|
||||
<c:otherwise>密码</c:otherwise>
|
||||
</c:choose>
|
||||
</label>
|
||||
<c:choose>
|
||||
@@ -111,8 +111,8 @@
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button class="button button-primary" type="submit">Save</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/users">Cancel</a>
|
||||
<button class="button button-primary" type="submit">保存</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/users">取消</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Manage Users - MZH Library</title>
|
||||
<title>用户管理 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -14,11 +14,11 @@
|
||||
<main class="page-shell">
|
||||
<section class="dashboard-hero catalog-hero" aria-labelledby="manage-users-title">
|
||||
<div>
|
||||
<p class="eyebrow">Administration</p>
|
||||
<h1 id="manage-users-title">Manage users</h1>
|
||||
<p>Create, update, deactivate, and review administrator, librarian, and reader accounts.</p>
|
||||
<p class="eyebrow">系统管理</p>
|
||||
<h1 id="manage-users-title">管理用户</h1>
|
||||
<p>创建、更新、停用和查看管理员、馆员与读者账户。</p>
|
||||
</div>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/admin/users/new">New user</a>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/admin/users/new">新增用户</a>
|
||||
</section>
|
||||
|
||||
<c:if test="${not empty successMessage}">
|
||||
@@ -32,10 +32,10 @@
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<section class="toolbar-panel" aria-label="User management search">
|
||||
<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">Keyword</label>
|
||||
<label for="keyword">关键词</label>
|
||||
<input id="keyword" name="keyword" type="text" value="${fn:escapeXml(criteria.keyword)}">
|
||||
<c:if test="${not empty errors.keyword}">
|
||||
<span class="field-error"><c:out value="${errors.keyword}" /></span>
|
||||
@@ -43,9 +43,9 @@
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="role">Role</label>
|
||||
<label for="role">角色</label>
|
||||
<select id="role" name="role">
|
||||
<option value="">All roles</option>
|
||||
<option value="">全部角色</option>
|
||||
<c:forEach var="role" items="${roles}">
|
||||
<option value="${role.code}" <c:if test="${criteria.roleCode == role.code}">selected</c:if>>
|
||||
<c:out value="${role.displayName}" />
|
||||
@@ -58,40 +58,40 @@
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="active">Active state</label>
|
||||
<label for="active">启用状态</label>
|
||||
<select id="active" name="active">
|
||||
<option value="">All states</option>
|
||||
<option value="active" <c:if test="${criteria.activeStatus == 'active'}">selected</c:if>>Active</option>
|
||||
<option value="inactive" <c:if test="${criteria.activeStatus == 'inactive'}">selected</c:if>>Inactive</option>
|
||||
<option value="">全部状态</option>
|
||||
<option value="active" <c:if test="${criteria.activeStatus == 'active'}">selected</c:if>>启用</option>
|
||||
<option value="inactive" <c:if test="${criteria.activeStatus == 'inactive'}">selected</c:if>>停用</option>
|
||||
</select>
|
||||
<c:if test="${not empty errors.active}">
|
||||
<span class="field-error"><c:out value="${errors.active}" /></span>
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<button class="button button-primary" type="submit">Search</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/users">Clear</a>
|
||||
<button class="button button-primary" type="submit">检索</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/users">清空</a>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="table-panel" aria-labelledby="user-results-title">
|
||||
<h2 id="user-results-title">User accounts</h2>
|
||||
<h2 id="user-results-title">用户账户</h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty users}">
|
||||
<p class="empty-state">No user accounts match the current filters.</p>
|
||||
<p class="empty-state">没有符合当前筛选条件的用户账户。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table user-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Username</th>
|
||||
<th scope="col">Display name</th>
|
||||
<th scope="col">Role</th>
|
||||
<th scope="col">State</th>
|
||||
<th scope="col">Created</th>
|
||||
<th scope="col">Updated</th>
|
||||
<th scope="col">Actions</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>
|
||||
@@ -110,17 +110,17 @@
|
||||
<td>
|
||||
<div class="table-actions">
|
||||
<a class="button button-secondary"
|
||||
href="${pageContext.request.contextPath}/admin/users/edit?id=${account.id}">Edit</a>
|
||||
href="${pageContext.request.contextPath}/admin/users/edit?id=${account.id}">编辑</a>
|
||||
<c:choose>
|
||||
<c:when test="${account.id == sessionScope.authenticatedUser.id or not account.active}">
|
||||
<button class="button button-secondary" type="button" disabled>Deactivate</button>
|
||||
<button class="button button-secondary" type="button" disabled>停用</button>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<form action="${pageContext.request.contextPath}/admin/users/deactivate"
|
||||
method="post"
|
||||
onsubmit="return confirm('Deactivate this user account?');">
|
||||
onsubmit="return confirm('确定停用这个用户账户吗?');">
|
||||
<input type="hidden" name="id" value="${account.id}">
|
||||
<button class="button button-danger" type="submit">Deactivate</button>
|
||||
<button class="button button-danger" type="submit">停用</button>
|
||||
</form>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Login - MZH Library</title>
|
||||
<title>登录 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body class="auth-page">
|
||||
@@ -14,8 +14,8 @@
|
||||
<main class="auth-shell">
|
||||
<section class="login-panel" aria-labelledby="login-title">
|
||||
<div>
|
||||
<p class="eyebrow">Library Management</p>
|
||||
<h1 id="login-title">Sign in</h1>
|
||||
<p class="eyebrow">图书馆管理</p>
|
||||
<h1 id="login-title">登录</h1>
|
||||
</div>
|
||||
|
||||
<c:if test="${not empty errorMessage}">
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<form class="login-form" action="${pageContext.request.contextPath}/login" method="post" novalidate>
|
||||
<input type="hidden" name="redirect" value="${fn:escapeXml(redirect)}">
|
||||
<label for="username">Username</label>
|
||||
<label for="username">用户名</label>
|
||||
<input id="username"
|
||||
name="username"
|
||||
type="text"
|
||||
@@ -34,14 +34,14 @@
|
||||
autocomplete="username"
|
||||
required>
|
||||
|
||||
<label for="password">Password</label>
|
||||
<label for="password">密码</label>
|
||||
<input id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
required>
|
||||
|
||||
<button class="button button-primary" type="submit">Sign in</button>
|
||||
<button class="button button-primary" type="submit">登录</button>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Unauthorized - MZH Library</title>
|
||||
<title>无权限 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
<%@ include file="/WEB-INF/jsp/common/header.jspf" %>
|
||||
<main class="page-shell">
|
||||
<section class="notice-panel" aria-labelledby="unauthorized-title">
|
||||
<h1 id="unauthorized-title">Access denied</h1>
|
||||
<h1 id="unauthorized-title">无权访问</h1>
|
||||
<p>
|
||||
<c:choose>
|
||||
<c:when test="${not empty errorMessage}">
|
||||
<c:out value="${errorMessage}" />
|
||||
</c:when>
|
||||
<c:otherwise>You do not have permission to access this page.</c:otherwise>
|
||||
<c:otherwise>您无权访问此页面。</c:otherwise>
|
||||
</c:choose>
|
||||
</p>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/dashboard">Back to dashboard</a>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/dashboard">返回控制台</a>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Catalog - MZH Library</title>
|
||||
<title>馆藏检索 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
<%@ 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">Catalog</p>
|
||||
<h1 id="catalog-title">Book catalog</h1>
|
||||
<p>Search the library collection by identifier, title, author, or category.</p>
|
||||
<p class="eyebrow">馆藏</p>
|
||||
<h1 id="catalog-title">馆藏检索</h1>
|
||||
<p>按图书编号、书名、作者或分类检索馆藏。</p>
|
||||
</section>
|
||||
|
||||
<c:if test="${not empty errorMessage}">
|
||||
@@ -24,27 +24,27 @@
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<section class="toolbar-panel" aria-label="Catalog search">
|
||||
<section class="toolbar-panel" aria-label="馆藏检索">
|
||||
<form class="search-form" action="${pageContext.request.contextPath}/catalog" method="get">
|
||||
<div class="search-field">
|
||||
<label for="identifier">Book ID</label>
|
||||
<label for="identifier">图书编号</label>
|
||||
<input id="identifier" name="identifier" type="text" value="${fn:escapeXml(criteria.identifier)}">
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="title">Title</label>
|
||||
<label for="title">书名</label>
|
||||
<input id="title" name="title" type="text" value="${fn:escapeXml(criteria.title)}">
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="author">Author</label>
|
||||
<label for="author">作者</label>
|
||||
<input id="author" name="author" type="text" value="${fn:escapeXml(criteria.author)}">
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="categoryId">Category</label>
|
||||
<label for="categoryId">分类</label>
|
||||
<select id="categoryId" name="categoryId">
|
||||
<option value="">All categories</option>
|
||||
<option value="">全部分类</option>
|
||||
<c:forEach var="category" items="${categories}">
|
||||
<option value="${category.id}" <c:if test="${criteria.categoryId == category.id}">selected</c:if>>
|
||||
<c:out value="${category.name}" />
|
||||
@@ -56,31 +56,31 @@
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<button class="button button-primary" type="submit">Search</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/catalog">Clear</a>
|
||||
<button class="button button-primary" type="submit">检索</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/catalog">清空</a>
|
||||
<c:if test="${canManageBooks}">
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">Manage books</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">管理图书</a>
|
||||
</c:if>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="table-panel" aria-labelledby="catalog-results-title">
|
||||
<h2 id="catalog-results-title">Results</h2>
|
||||
<h2 id="catalog-results-title">检索结果</h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty books}">
|
||||
<p class="empty-state">No books match the current filters.</p>
|
||||
<p class="empty-state">没有符合当前筛选条件的图书。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Book ID</th>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">Author</th>
|
||||
<th scope="col">Category</th>
|
||||
<th scope="col">Copies</th>
|
||||
<th scope="col">Status</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>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Manage Categories - MZH Library</title>
|
||||
<title>分类管理 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -13,13 +13,13 @@
|
||||
<main class="page-shell">
|
||||
<section class="dashboard-hero catalog-hero" aria-labelledby="category-title">
|
||||
<div>
|
||||
<p class="eyebrow">Book Management</p>
|
||||
<h1 id="category-title">Manage categories</h1>
|
||||
<p>Maintain catalog groupings used by book records and search filters.</p>
|
||||
<p class="eyebrow">图书管理</p>
|
||||
<h1 id="category-title">管理分类</h1>
|
||||
<p>维护图书记录和检索筛选使用的馆藏分组。</p>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/book-categories/new">New category</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">Manage books</a>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/book-categories/new">新增分类</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">管理图书</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -35,19 +35,19 @@
|
||||
</c:if>
|
||||
|
||||
<section class="table-panel" aria-labelledby="category-results-title">
|
||||
<h2 id="category-results-title">Category records</h2>
|
||||
<h2 id="category-results-title">分类记录</h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty categories}">
|
||||
<p class="empty-state">No categories have been created yet.</p>
|
||||
<p class="empty-state">尚未创建分类。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table category-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Description</th>
|
||||
<th scope="col">Actions</th>
|
||||
<th scope="col">名称</th>
|
||||
<th scope="col">说明</th>
|
||||
<th scope="col">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -57,7 +57,7 @@
|
||||
<td>
|
||||
<c:choose>
|
||||
<c:when test="${empty category.description}">
|
||||
<span class="muted-text">No description</span>
|
||||
<span class="muted-text">无说明</span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:out value="${category.description}" />
|
||||
@@ -67,12 +67,12 @@
|
||||
<td>
|
||||
<div class="table-actions">
|
||||
<a class="button button-secondary"
|
||||
href="${pageContext.request.contextPath}/book-categories/edit?id=${category.id}">Edit</a>
|
||||
href="${pageContext.request.contextPath}/book-categories/edit?id=${category.id}">编辑</a>
|
||||
<form action="${pageContext.request.contextPath}/book-categories/delete"
|
||||
method="post"
|
||||
onsubmit="return confirm('Delete this category?');">
|
||||
onsubmit="return confirm('确定删除这个分类吗?');">
|
||||
<input type="hidden" name="id" value="${category.id}">
|
||||
<button class="button button-danger" type="submit">Delete</button>
|
||||
<button class="button button-danger" type="submit">删除</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><c:out value="${formTitle}" /> - MZH Library</title>
|
||||
<title><c:out value="${formTitle}" /> - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
<%@ include file="/WEB-INF/jsp/common/header.jspf" %>
|
||||
<main class="page-shell">
|
||||
<section class="form-panel" aria-labelledby="category-form-title">
|
||||
<p class="eyebrow">Book Management</p>
|
||||
<p class="eyebrow">图书管理</p>
|
||||
<h1 id="category-form-title"><c:out value="${formTitle}" /></h1>
|
||||
|
||||
<c:if test="${not empty errorMessage}">
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
<div class="form-grid">
|
||||
<div class="form-field">
|
||||
<label for="name">Category name</label>
|
||||
<label for="name">分类名称</label>
|
||||
<input id="name" name="name" type="text" value="${fn:escapeXml(nameValue)}" required>
|
||||
<c:if test="${not empty errors.name}">
|
||||
<span class="field-error"><c:out value="${errors.name}" /></span>
|
||||
@@ -41,7 +41,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field form-field-wide">
|
||||
<label for="description">Description</label>
|
||||
<label for="description">说明</label>
|
||||
<textarea id="description" name="description" rows="4">${fn:escapeXml(descriptionValue)}</textarea>
|
||||
<c:if test="${not empty errors.description}">
|
||||
<span class="field-error"><c:out value="${errors.description}" /></span>
|
||||
@@ -56,8 +56,8 @@
|
||||
</c:if>
|
||||
|
||||
<div class="form-actions">
|
||||
<button class="button button-primary" type="submit">Save</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/book-categories">Cancel</a>
|
||||
<button class="button button-primary" type="submit">保存</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/book-categories">取消</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><c:out value="${formTitle}" /> - MZH Library</title>
|
||||
<title><c:out value="${formTitle}" /> - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
<%@ include file="/WEB-INF/jsp/common/header.jspf" %>
|
||||
<main class="page-shell">
|
||||
<section class="form-panel" aria-labelledby="book-form-title">
|
||||
<p class="eyebrow">Book Management</p>
|
||||
<p class="eyebrow">图书管理</p>
|
||||
<h1 id="book-form-title"><c:out value="${formTitle}" /></h1>
|
||||
|
||||
<c:if test="${not empty errorMessage}">
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
<div class="form-grid">
|
||||
<div class="form-field">
|
||||
<label for="identifier">Book ID</label>
|
||||
<label for="identifier">图书编号</label>
|
||||
<input id="identifier" name="identifier" type="text" value="${fn:escapeXml(identifierValue)}" required>
|
||||
<c:if test="${not empty errors.identifier}">
|
||||
<span class="field-error"><c:out value="${errors.identifier}" /></span>
|
||||
@@ -46,7 +46,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="title">Title</label>
|
||||
<label for="title">书名</label>
|
||||
<input id="title" name="title" type="text" value="${fn:escapeXml(titleValue)}" required>
|
||||
<c:if test="${not empty errors.title}">
|
||||
<span class="field-error"><c:out value="${errors.title}" /></span>
|
||||
@@ -54,7 +54,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="author">Author</label>
|
||||
<label for="author">作者</label>
|
||||
<input id="author" name="author" type="text" value="${fn:escapeXml(authorValue)}" required>
|
||||
<c:if test="${not empty errors.author}">
|
||||
<span class="field-error"><c:out value="${errors.author}" /></span>
|
||||
@@ -62,9 +62,9 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="categoryId">Category</label>
|
||||
<label for="categoryId">分类</label>
|
||||
<select id="categoryId" name="categoryId" required>
|
||||
<option value="">Select category</option>
|
||||
<option value="">请选择分类</option>
|
||||
<c:forEach var="category" items="${categories}">
|
||||
<option value="${category.id}" <c:if test="${categoryValue == category.id}">selected</c:if>>
|
||||
<c:out value="${category.name}" />
|
||||
@@ -77,7 +77,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="totalCopies">Total copies</label>
|
||||
<label for="totalCopies">馆藏总数</label>
|
||||
<input id="totalCopies" name="totalCopies" type="number" min="0" value="${fn:escapeXml(totalCopiesValue)}" required>
|
||||
<c:if test="${not empty errors.totalCopies}">
|
||||
<span class="field-error"><c:out value="${errors.totalCopies}" /></span>
|
||||
@@ -85,7 +85,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="availableCopies">Available copies</label>
|
||||
<label for="availableCopies">可借数量</label>
|
||||
<input id="availableCopies" name="availableCopies" type="number" min="0" value="${fn:escapeXml(availableCopiesValue)}" required>
|
||||
<c:if test="${not empty errors.availableCopies}">
|
||||
<span class="field-error"><c:out value="${errors.availableCopies}" /></span>
|
||||
@@ -93,9 +93,9 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="status">Status</label>
|
||||
<label for="status">状态</label>
|
||||
<select id="status" name="status" required>
|
||||
<option value="">Select status</option>
|
||||
<option value="">请选择状态</option>
|
||||
<c:forEach var="status" items="${statuses}">
|
||||
<option value="${status.code}" <c:if test="${statusValue == status.code}">selected</c:if>>
|
||||
<c:out value="${status.displayName}" />
|
||||
@@ -109,8 +109,8 @@
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button class="button button-primary" type="submit">Save</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">Cancel</a>
|
||||
<button class="button button-primary" type="submit">保存</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">取消</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
@@ -2,23 +2,23 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Manage Books - MZH Library</title>
|
||||
<title>图书管理 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
<%@ 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">Book Management</p>
|
||||
<h1 id="manage-title">Manage books</h1>
|
||||
<p>Create, update, delete, and review inventory for catalog records.</p>
|
||||
<p class="eyebrow">图书管理</p>
|
||||
<h1 id="manage-title">管理图书</h1>
|
||||
<p>创建、更新、删除和查看馆藏记录的库存信息。</p>
|
||||
<div class="hero-actions">
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/books/new">New book</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/book-categories">Categories</a>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/books/new">新增图书</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/book-categories">分类</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -33,27 +33,27 @@
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<section class="toolbar-panel" aria-label="Book management search">
|
||||
<section class="toolbar-panel" aria-label="图书管理检索">
|
||||
<form class="search-form" action="${pageContext.request.contextPath}/books" method="get">
|
||||
<div class="search-field">
|
||||
<label for="identifier">Book ID</label>
|
||||
<label for="identifier">图书编号</label>
|
||||
<input id="identifier" name="identifier" type="text" value="${fn:escapeXml(criteria.identifier)}">
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="title">Title</label>
|
||||
<label for="title">书名</label>
|
||||
<input id="title" name="title" type="text" value="${fn:escapeXml(criteria.title)}">
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="author">Author</label>
|
||||
<label for="author">作者</label>
|
||||
<input id="author" name="author" type="text" value="${fn:escapeXml(criteria.author)}">
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="categoryId">Category</label>
|
||||
<label for="categoryId">分类</label>
|
||||
<select id="categoryId" name="categoryId">
|
||||
<option value="">All categories</option>
|
||||
<option value="">全部分类</option>
|
||||
<c:forEach var="category" items="${categories}">
|
||||
<option value="${category.id}" <c:if test="${criteria.categoryId == category.id}">selected</c:if>>
|
||||
<c:out value="${category.name}" />
|
||||
@@ -65,31 +65,31 @@
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<button class="button button-primary" type="submit">Search</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">Clear</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/catalog">View catalog</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/book-categories">Categories</a>
|
||||
<button class="button button-primary" type="submit">检索</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">清空</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/catalog">查看馆藏</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/book-categories">分类</a>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="table-panel" aria-labelledby="management-results-title">
|
||||
<h2 id="management-results-title">Book records</h2>
|
||||
<h2 id="management-results-title">图书记录</h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty books}">
|
||||
<p class="empty-state">No book records match the current filters.</p>
|
||||
<p class="empty-state">没有符合当前筛选条件的图书记录。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Book ID</th>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">Author</th>
|
||||
<th scope="col">Category</th>
|
||||
<th scope="col">Copies</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col">Actions</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>
|
||||
@@ -108,12 +108,12 @@
|
||||
<td>
|
||||
<div class="table-actions">
|
||||
<a class="button button-secondary"
|
||||
href="${pageContext.request.contextPath}/books/edit?id=${book.id}">Edit</a>
|
||||
href="${pageContext.request.contextPath}/books/edit?id=${book.id}">编辑</a>
|
||||
<form action="${pageContext.request.contextPath}/books/delete"
|
||||
method="post"
|
||||
onsubmit="return confirm('Delete this book record?');">
|
||||
onsubmit="return confirm('确定删除这条图书记录吗?');">
|
||||
<input type="hidden" name="id" value="${book.id}">
|
||||
<button class="button button-danger" type="submit">Delete</button>
|
||||
<button class="button button-danger" type="submit">删除</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>New Borrow - MZH Library</title>
|
||||
<title>新增借阅 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
<%@ include file="/WEB-INF/jsp/common/header.jspf" %>
|
||||
<main class="page-shell">
|
||||
<section class="form-panel" aria-labelledby="borrow-form-title">
|
||||
<p class="eyebrow">Borrowing Management</p>
|
||||
<h1 id="borrow-form-title">New borrow</h1>
|
||||
<p class="eyebrow">借阅管理</p>
|
||||
<h1 id="borrow-form-title">新增借阅</h1>
|
||||
|
||||
<c:if test="${not empty errorMessage}">
|
||||
<div class="message message-error" role="alert">
|
||||
@@ -28,7 +28,7 @@
|
||||
<form class="borrow-form" action="${pageContext.request.contextPath}/borrowing/create" method="post" novalidate>
|
||||
<div class="form-grid">
|
||||
<div class="form-field">
|
||||
<label for="readerIdentifier">Reader ID</label>
|
||||
<label for="readerIdentifier">读者编号</label>
|
||||
<input id="readerIdentifier" name="readerIdentifier" type="text"
|
||||
value="${fn:escapeXml(readerIdentifierValue)}" required>
|
||||
<c:if test="${not empty errors.readerIdentifier}">
|
||||
@@ -37,7 +37,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="bookIdentifier">Book ID</label>
|
||||
<label for="bookIdentifier">图书编号</label>
|
||||
<input id="bookIdentifier" name="bookIdentifier" type="text"
|
||||
value="${fn:escapeXml(bookIdentifierValue)}" required>
|
||||
<c:if test="${not empty errors.bookIdentifier}">
|
||||
@@ -47,8 +47,8 @@
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button class="button button-primary" type="submit">Borrow</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/borrowing">Cancel</a>
|
||||
<button class="button button-primary" type="submit">借出</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/borrowing">取消</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Borrowing Management - MZH Library</title>
|
||||
<title>借阅管理 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -14,11 +14,11 @@
|
||||
<main class="page-shell">
|
||||
<section class="dashboard-hero catalog-hero" aria-labelledby="borrowing-title">
|
||||
<div>
|
||||
<p class="eyebrow">Borrowing Management</p>
|
||||
<h1 id="borrowing-title">Manage borrowing</h1>
|
||||
<p>Create borrow records, process returns, renew active loans, and review overdue items.</p>
|
||||
<p class="eyebrow">借阅管理</p>
|
||||
<h1 id="borrowing-title">管理借阅</h1>
|
||||
<p>创建借阅记录、处理归还、续借有效借阅并查看逾期项目。</p>
|
||||
</div>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/borrowing/new">New borrow</a>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/borrowing/new">新增借阅</a>
|
||||
</section>
|
||||
|
||||
<c:if test="${not empty successMessage}">
|
||||
@@ -32,31 +32,31 @@
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<section class="toolbar-panel" aria-label="Borrowing search">
|
||||
<section class="toolbar-panel" aria-label="借阅检索">
|
||||
<form class="search-form borrowing-search-form" action="${pageContext.request.contextPath}/borrowing" method="get">
|
||||
<div class="search-field">
|
||||
<label for="readerIdentifier">Reader ID</label>
|
||||
<label for="readerIdentifier">读者编号</label>
|
||||
<input id="readerIdentifier" name="readerIdentifier" type="text"
|
||||
value="${fn:escapeXml(criteria.readerIdentifier)}">
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="bookIdentifier">Book ID</label>
|
||||
<label for="bookIdentifier">图书编号</label>
|
||||
<input id="bookIdentifier" name="bookIdentifier" type="text"
|
||||
value="${fn:escapeXml(criteria.bookIdentifier)}">
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="status">Status</label>
|
||||
<label for="status">状态</label>
|
||||
<select id="status" name="status">
|
||||
<option value="">All statuses</option>
|
||||
<option value="">全部状态</option>
|
||||
<c:forEach var="status" items="${statuses}">
|
||||
<option value="${status.code}" <c:if test="${criteria.statusCode == status.code}">selected</c:if>>
|
||||
<c:out value="${status.displayName}" />
|
||||
</option>
|
||||
</c:forEach>
|
||||
<option value="${overdueStatus}" <c:if test="${criteria.statusCode == overdueStatus}">selected</c:if>>
|
||||
Overdue
|
||||
逾期
|
||||
</option>
|
||||
</select>
|
||||
<c:if test="${not empty errors.status}">
|
||||
@@ -64,30 +64,30 @@
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<button class="button button-primary" type="submit">Search</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/borrowing">Clear</a>
|
||||
<button class="button button-primary" type="submit">检索</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/borrowing">清空</a>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="table-panel" aria-labelledby="borrowing-results-title">
|
||||
<h2 id="borrowing-results-title">Borrowing records</h2>
|
||||
<h2 id="borrowing-results-title">借阅记录</h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty borrowRecords}">
|
||||
<p class="empty-state">No borrowing records match the current filters.</p>
|
||||
<p class="empty-state">没有符合当前筛选条件的借阅记录。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table borrowing-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Reader</th>
|
||||
<th scope="col">Book</th>
|
||||
<th scope="col">Borrowed</th>
|
||||
<th scope="col">Due</th>
|
||||
<th scope="col">Returned</th>
|
||||
<th scope="col">Renewals</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col">Actions</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>
|
||||
<th scope="col">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -108,7 +108,7 @@
|
||||
<c:when test="${not empty record.returnedAtText}">
|
||||
<c:out value="${record.returnedAtText}" />
|
||||
</c:when>
|
||||
<c:otherwise>Not returned</c:otherwise>
|
||||
<c:otherwise>未归还</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
<td><c:out value="${record.renewalCount}" /> / <c:out value="${maxRenewals}" /></td>
|
||||
@@ -123,22 +123,22 @@
|
||||
<div class="table-actions">
|
||||
<form action="${pageContext.request.contextPath}/borrowing/return"
|
||||
method="post"
|
||||
onsubmit="return confirm('Return this book?');">
|
||||
onsubmit="return confirm('确定归还这本书吗?');">
|
||||
<input type="hidden" name="id" value="${record.id}">
|
||||
<button class="button button-secondary" type="submit">Return</button>
|
||||
<button class="button button-secondary" type="submit">归还</button>
|
||||
</form>
|
||||
<c:if test="${record.renewalCount < maxRenewals}">
|
||||
<form action="${pageContext.request.contextPath}/borrowing/renew"
|
||||
method="post"
|
||||
onsubmit="return confirm('Renew this loan?');">
|
||||
onsubmit="return confirm('确定续借这条记录吗?');">
|
||||
<input type="hidden" name="id" value="${record.id}">
|
||||
<button class="button button-secondary" type="submit">Renew</button>
|
||||
<button class="button button-secondary" type="submit">续借</button>
|
||||
</form>
|
||||
</c:if>
|
||||
</div>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span class="muted-text">Complete</span>
|
||||
<span class="muted-text">已完成</span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<header class="app-header">
|
||||
<a class="brand" href="${pageContext.request.contextPath}/dashboard">MZH Library</a>
|
||||
<a class="brand" href="${pageContext.request.contextPath}/dashboard">MZH 图书馆</a>
|
||||
<c:if test="${not empty sessionScope.authenticatedUser}">
|
||||
<nav class="top-nav" aria-label="Primary">
|
||||
<a href="${pageContext.request.contextPath}/dashboard">Dashboard</a>
|
||||
<a href="${pageContext.request.contextPath}/catalog">Catalog</a>
|
||||
<nav class="top-nav" aria-label="主导航">
|
||||
<a href="${pageContext.request.contextPath}/dashboard">控制台</a>
|
||||
<a href="${pageContext.request.contextPath}/catalog">馆藏检索</a>
|
||||
<c:if test="${sessionScope.userRole == 'administrator'}">
|
||||
<a href="${pageContext.request.contextPath}/admin/home">Admin</a>
|
||||
<a href="${pageContext.request.contextPath}/admin/users">Users</a>
|
||||
<a href="${pageContext.request.contextPath}/admin/system-logs">Logs</a>
|
||||
<a href="${pageContext.request.contextPath}/admin/home">管理</a>
|
||||
<a href="${pageContext.request.contextPath}/admin/users">用户</a>
|
||||
<a href="${pageContext.request.contextPath}/admin/system-logs">日志</a>
|
||||
</c:if>
|
||||
<c:if test="${sessionScope.userRole == 'administrator' or sessionScope.userRole == 'librarian'}">
|
||||
<a href="${pageContext.request.contextPath}/librarian/home">Librarian</a>
|
||||
<a href="${pageContext.request.contextPath}/books">Books</a>
|
||||
<a href="${pageContext.request.contextPath}/book-categories">Categories</a>
|
||||
<a href="${pageContext.request.contextPath}/readers">Readers</a>
|
||||
<a href="${pageContext.request.contextPath}/borrowing">Borrowing</a>
|
||||
<a href="${pageContext.request.contextPath}/reports">Reports</a>
|
||||
<a href="${pageContext.request.contextPath}/librarian/home">馆员</a>
|
||||
<a href="${pageContext.request.contextPath}/books">图书</a>
|
||||
<a href="${pageContext.request.contextPath}/book-categories">分类</a>
|
||||
<a href="${pageContext.request.contextPath}/readers">读者</a>
|
||||
<a href="${pageContext.request.contextPath}/borrowing">借阅</a>
|
||||
<a href="${pageContext.request.contextPath}/reports">报表</a>
|
||||
</c:if>
|
||||
<a href="${pageContext.request.contextPath}/reader/home">Reader</a>
|
||||
<a href="${pageContext.request.contextPath}/reader/home">读者中心</a>
|
||||
<c:if test="${sessionScope.userRole == 'reader'}">
|
||||
<a href="${pageContext.request.contextPath}/reader/loans">My Loans</a>
|
||||
<a href="${pageContext.request.contextPath}/reader/loans">我的借阅</a>
|
||||
</c:if>
|
||||
<span class="user-pill">
|
||||
<c:out value="${sessionScope.authenticatedUser.displayName}" />
|
||||
</span>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/logout">Logout</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/logout">退出</a>
|
||||
</nav>
|
||||
</c:if>
|
||||
</header>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Dashboard - MZH Library</title>
|
||||
<title>控制台 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -15,86 +15,86 @@
|
||||
<p class="eyebrow">
|
||||
<c:out value="${sessionScope.authenticatedUser.role.displayName}" />
|
||||
</p>
|
||||
<h1 id="dashboard-title">Dashboard</h1>
|
||||
<p>Signed in as <strong><c:out value="${sessionScope.authenticatedUser.displayName}" /></strong>.</p>
|
||||
<h1 id="dashboard-title">控制台</h1>
|
||||
<p>当前登录:<strong><c:out value="${sessionScope.authenticatedUser.displayName}" /></strong></p>
|
||||
</section>
|
||||
|
||||
<section class="card-grid" aria-label="Role workspaces">
|
||||
<section class="card-grid" aria-label="角色工作区">
|
||||
<c:if test="${sessionScope.userRole == 'administrator'}">
|
||||
<article class="workspace-card">
|
||||
<h2>Administration</h2>
|
||||
<p>Account, role, permission, and system-maintenance entry point.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/home">Open</a>
|
||||
<h2>系统管理</h2>
|
||||
<p>账户、角色、权限和系统维护入口。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/home">打开</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>User Management</h2>
|
||||
<p>Create, update, deactivate, and review login accounts.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/users">Open</a>
|
||||
<h2>用户管理</h2>
|
||||
<p>创建、更新、停用和查看登录账户。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/users">打开</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>System Logs</h2>
|
||||
<p>Review read-only audit entries for account and maintenance actions.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/system-logs">Open</a>
|
||||
<h2>系统日志</h2>
|
||||
<p>查看账户与维护操作的只读审计记录。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/system-logs">打开</a>
|
||||
</article>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${sessionScope.userRole == 'administrator' or sessionScope.userRole == 'librarian'}">
|
||||
<article class="workspace-card">
|
||||
<h2>Librarian Workspace</h2>
|
||||
<p>Book, reader, borrowing, return, renewal, and overdue entry point.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/librarian/home">Open</a>
|
||||
<h2>馆员工作台</h2>
|
||||
<p>图书、读者、借阅、归还、续借和逾期处理入口。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/librarian/home">打开</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Book Management</h2>
|
||||
<p>Create, update, delete, and review book inventory records.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">Open</a>
|
||||
<h2>图书管理</h2>
|
||||
<p>创建、更新、删除和查看图书库存记录。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">打开</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Category Maintenance</h2>
|
||||
<p>Maintain catalog categories used by book records and search filters.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/book-categories">Open</a>
|
||||
<h2>分类维护</h2>
|
||||
<p>维护图书记录和检索筛选使用的馆藏分类。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/book-categories">打开</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Reader Management</h2>
|
||||
<p>Create, update, deactivate, and review reader eligibility records.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/readers">Open</a>
|
||||
<h2>读者管理</h2>
|
||||
<p>创建、更新、停用和查看读者借阅资格记录。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/readers">打开</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Borrowing Management</h2>
|
||||
<p>Create loans, process returns, renew active records, and review overdue items.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/borrowing">Open</a>
|
||||
<h2>借阅管理</h2>
|
||||
<p>创建借阅、处理归还、续借有效记录并查看逾期项目。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/borrowing">打开</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Report Center</h2>
|
||||
<p>Review inventory health, borrowing counts, overdue records, and popular books.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/reports">Open</a>
|
||||
<h2>报表中心</h2>
|
||||
<p>查看库存状况、借阅统计、逾期记录和热门图书。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/reports">打开</a>
|
||||
</article>
|
||||
</c:if>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Book Catalog</h2>
|
||||
<p>Search books by title, author, category, or book identifier.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/catalog">Search</a>
|
||||
<h2>馆藏检索</h2>
|
||||
<p>按书名、作者、分类或图书编号检索图书。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/catalog">检索</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Reader Center</h2>
|
||||
<p>Reader self-service entry point for catalog access and loan history.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/reader/home">Open</a>
|
||||
<h2>读者中心</h2>
|
||||
<p>读者自助访问馆藏和借阅历史的入口。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/reader/home">打开</a>
|
||||
</article>
|
||||
|
||||
<c:if test="${sessionScope.userRole == 'reader'}">
|
||||
<article class="workspace-card">
|
||||
<h2>My Loan History</h2>
|
||||
<p>Review your active, returned, and overdue borrowing records.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/reader/loans">Open</a>
|
||||
<h2>我的借阅历史</h2>
|
||||
<p>查看您的在借、已还和逾期借阅记录。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/reader/loans">打开</a>
|
||||
</article>
|
||||
</c:if>
|
||||
</section>
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>System Logs - MZH Library</title>
|
||||
<title>系统日志 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -14,9 +14,9 @@
|
||||
<main class="page-shell">
|
||||
<section class="dashboard-hero catalog-hero" aria-labelledby="system-logs-title">
|
||||
<div>
|
||||
<p class="eyebrow">System Maintenance</p>
|
||||
<h1 id="system-logs-title">System logs</h1>
|
||||
<p>Review administrative account changes and maintenance audit records.</p>
|
||||
<p class="eyebrow">系统维护</p>
|
||||
<h1 id="system-logs-title">系统日志</h1>
|
||||
<p>查看管理账户变更和维护审计记录。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -26,17 +26,22 @@
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<section class="toolbar-panel" aria-label="System log search">
|
||||
<section class="toolbar-panel" aria-label="系统日志检索">
|
||||
<form class="search-form system-log-search-form"
|
||||
action="${pageContext.request.contextPath}/admin/system-logs" method="get">
|
||||
<div class="search-field">
|
||||
<label for="operationType">Operation</label>
|
||||
<label for="operationType">操作</label>
|
||||
<select id="operationType" name="operationType">
|
||||
<option value="">All operations</option>
|
||||
<option value="">全部操作</option>
|
||||
<c:forEach var="operationType" items="${operationTypes}">
|
||||
<option value="${fn:escapeXml(operationType)}"
|
||||
<c:if test="${criteria.operationType == operationType}">selected</c:if>>
|
||||
<c:out value="${operationType}" />
|
||||
<c:choose>
|
||||
<c:when test="${operationType == 'user.create'}">创建用户</c:when>
|
||||
<c:when test="${operationType == 'user.update'}">更新用户</c:when>
|
||||
<c:when test="${operationType == 'user.deactivate'}">停用用户</c:when>
|
||||
<c:otherwise><c:out value="${operationType}" /></c:otherwise>
|
||||
</c:choose>
|
||||
</option>
|
||||
</c:forEach>
|
||||
<c:if test="${not empty criteria.operationType and empty operationTypes}">
|
||||
@@ -51,7 +56,7 @@
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="keyword">Keyword</label>
|
||||
<label for="keyword">关键词</label>
|
||||
<input id="keyword" name="keyword" type="text" value="${fn:escapeXml(criteria.keyword)}">
|
||||
<c:if test="${not empty errors.keyword}">
|
||||
<span class="field-error"><c:out value="${errors.keyword}" /></span>
|
||||
@@ -59,7 +64,7 @@
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="createdFrom">From</label>
|
||||
<label for="createdFrom">开始日期</label>
|
||||
<input id="createdFrom" name="createdFrom" type="date"
|
||||
value="${fn:escapeXml(criteria.createdFromText)}">
|
||||
<c:if test="${not empty errors.createdFrom}">
|
||||
@@ -68,7 +73,7 @@
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="createdTo">To</label>
|
||||
<label for="createdTo">结束日期</label>
|
||||
<input id="createdTo" name="createdTo" type="date"
|
||||
value="${fn:escapeXml(criteria.createdToText)}">
|
||||
<c:if test="${not empty errors.createdTo}">
|
||||
@@ -76,29 +81,29 @@
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<button class="button button-primary" type="submit">Search</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/system-logs">Clear</a>
|
||||
<button class="button button-primary" type="submit">检索</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/system-logs">清空</a>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="table-panel" aria-labelledby="system-log-results-title">
|
||||
<h2 id="system-log-results-title">Log entries</h2>
|
||||
<h2 id="system-log-results-title">日志记录</h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty logs}">
|
||||
<p class="empty-state">No system logs match the current filters.</p>
|
||||
<p class="empty-state">没有符合当前筛选条件的系统日志。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table system-log-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Time</th>
|
||||
<th scope="col">Operator</th>
|
||||
<th scope="col">Operation</th>
|
||||
<th scope="col">Target</th>
|
||||
<th scope="col">Result</th>
|
||||
<th scope="col">IP address</th>
|
||||
<th scope="col">Detail</th>
|
||||
<th scope="col">时间</th>
|
||||
<th scope="col">操作人</th>
|
||||
<th scope="col">操作</th>
|
||||
<th scope="col">目标</th>
|
||||
<th scope="col">结果</th>
|
||||
<th scope="col">IP 地址</th>
|
||||
<th scope="col">详情</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -111,9 +116,16 @@
|
||||
<div class="muted-text"><c:out value="${log.operatorMetaText}" /></div>
|
||||
</c:if>
|
||||
</td>
|
||||
<td><c:out value="${log.operationType}" /></td>
|
||||
<td>
|
||||
<c:out value="${log.targetTable}" />
|
||||
<c:choose>
|
||||
<c:when test="${log.operationType == 'user.create'}">创建用户</c:when>
|
||||
<c:when test="${log.operationType == 'user.update'}">更新用户</c:when>
|
||||
<c:when test="${log.operationType == 'user.deactivate'}">停用用户</c:when>
|
||||
<c:otherwise><c:out value="${log.operationType}" /></c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
<td>
|
||||
<c:out value="${log.targetTableName}" />
|
||||
<c:if test="${not empty log.targetId}">
|
||||
#<c:out value="${log.targetId}" />
|
||||
</c:if>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Loan History - MZH Library</title>
|
||||
<title>借阅历史 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -13,11 +13,11 @@
|
||||
<main class="page-shell">
|
||||
<section class="dashboard-hero catalog-hero" aria-labelledby="loan-history-title">
|
||||
<div>
|
||||
<p class="eyebrow">Reader Center</p>
|
||||
<h1 id="loan-history-title">Loan history</h1>
|
||||
<p>Review your active, returned, and overdue borrowing records.</p>
|
||||
<p class="eyebrow">读者中心</p>
|
||||
<h1 id="loan-history-title">借阅历史</h1>
|
||||
<p>查看您的在借、已还和逾期借阅记录。</p>
|
||||
</div>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/catalog">Search catalog</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/catalog">检索馆藏</a>
|
||||
</section>
|
||||
|
||||
<c:if test="${not empty successMessage}">
|
||||
@@ -32,23 +32,23 @@
|
||||
</c:if>
|
||||
|
||||
<section class="table-panel" aria-labelledby="loan-results-title">
|
||||
<h2 id="loan-results-title">Borrowing records</h2>
|
||||
<h2 id="loan-results-title">借阅记录</h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty borrowRecords}">
|
||||
<p class="empty-state">No borrowing records are available for this account.</p>
|
||||
<p class="empty-state">此账户暂无借阅记录。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table borrowing-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Book ID</th>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">Borrowed</th>
|
||||
<th scope="col">Due</th>
|
||||
<th scope="col">Returned</th>
|
||||
<th scope="col">Renewals</th>
|
||||
<th scope="col">Status</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>
|
||||
@@ -63,7 +63,7 @@
|
||||
<c:when test="${not empty record.returnedAtText}">
|
||||
<c:out value="${record.returnedAtText}" />
|
||||
</c:when>
|
||||
<c:otherwise>Not returned</c:otherwise>
|
||||
<c:otherwise>未归还</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
<td><c:out value="${record.renewalCount}" /></td>
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><c:out value="${formTitle}" /> - MZH Library</title>
|
||||
<title><c:out value="${formTitle}" /> - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
<%@ include file="/WEB-INF/jsp/common/header.jspf" %>
|
||||
<main class="page-shell">
|
||||
<section class="form-panel" aria-labelledby="reader-form-title">
|
||||
<p class="eyebrow">Reader Management</p>
|
||||
<p class="eyebrow">读者管理</p>
|
||||
<h1 id="reader-form-title"><c:out value="${formTitle}" /></h1>
|
||||
|
||||
<c:if test="${not empty errorMessage}">
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
<div class="form-grid">
|
||||
<div class="form-field">
|
||||
<label for="identifier">Reader ID</label>
|
||||
<label for="identifier">读者编号</label>
|
||||
<input id="identifier" name="identifier" type="text" value="${fn:escapeXml(identifierValue)}" required>
|
||||
<c:if test="${not empty errors.identifier}">
|
||||
<span class="field-error"><c:out value="${errors.identifier}" /></span>
|
||||
@@ -46,7 +46,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="fullName">Full name</label>
|
||||
<label for="fullName">姓名</label>
|
||||
<input id="fullName" name="fullName" type="text" value="${fn:escapeXml(fullNameValue)}" required>
|
||||
<c:if test="${not empty errors.fullName}">
|
||||
<span class="field-error"><c:out value="${errors.fullName}" /></span>
|
||||
@@ -54,7 +54,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="phone">Phone</label>
|
||||
<label for="phone">电话</label>
|
||||
<input id="phone" name="phone" type="tel" value="${fn:escapeXml(phoneValue)}">
|
||||
<c:if test="${not empty errors.phone}">
|
||||
<span class="field-error"><c:out value="${errors.phone}" /></span>
|
||||
@@ -62,7 +62,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="email">Email</label>
|
||||
<label for="email">邮箱</label>
|
||||
<input id="email" name="email" type="email" value="${fn:escapeXml(emailValue)}">
|
||||
<c:if test="${not empty errors.email}">
|
||||
<span class="field-error"><c:out value="${errors.email}" /></span>
|
||||
@@ -70,7 +70,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="userId">Linked account ID</label>
|
||||
<label for="userId">关联账户 ID</label>
|
||||
<input id="userId" name="userId" type="number" min="1" value="${fn:escapeXml(userIdValue)}">
|
||||
<c:if test="${not empty errors.userId}">
|
||||
<span class="field-error"><c:out value="${errors.userId}" /></span>
|
||||
@@ -78,7 +78,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="maxBorrowCount">Max borrow count</label>
|
||||
<label for="maxBorrowCount">最大借阅数量</label>
|
||||
<input id="maxBorrowCount" name="maxBorrowCount" type="number" min="1" max="50"
|
||||
value="${fn:escapeXml(maxBorrowCountValue)}" required>
|
||||
<c:if test="${not empty errors.maxBorrowCount}">
|
||||
@@ -87,9 +87,9 @@
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="status">Status</label>
|
||||
<label for="status">状态</label>
|
||||
<select id="status" name="status" required>
|
||||
<option value="">Select status</option>
|
||||
<option value="">请选择状态</option>
|
||||
<c:forEach var="status" items="${statuses}">
|
||||
<option value="${status.code}" <c:if test="${statusValue == status.code}">selected</c:if>>
|
||||
<c:out value="${status.displayName}" />
|
||||
@@ -103,8 +103,8 @@
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button class="button button-primary" type="submit">Save</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/readers">Cancel</a>
|
||||
<button class="button button-primary" type="submit">保存</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/readers">取消</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Manage Readers - MZH Library</title>
|
||||
<title>读者管理 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</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">Reader Management</p>
|
||||
<h1 id="manage-readers-title">Manage readers</h1>
|
||||
<p>Create, update, and review reader eligibility and contact records.</p>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/readers/new">New reader</a>
|
||||
<p class="eyebrow">读者管理</p>
|
||||
<h1 id="manage-readers-title">管理读者</h1>
|
||||
<p>创建、更新和查看读者资格及联系方式记录。</p>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/readers/new">新增读者</a>
|
||||
</section>
|
||||
|
||||
<c:if test="${not empty successMessage}">
|
||||
@@ -30,27 +30,27 @@
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<section class="toolbar-panel" aria-label="Reader management search">
|
||||
<section class="toolbar-panel" aria-label="读者管理检索">
|
||||
<form class="search-form" action="${pageContext.request.contextPath}/readers" method="get">
|
||||
<div class="search-field">
|
||||
<label for="identifier">Reader ID</label>
|
||||
<label for="identifier">读者编号</label>
|
||||
<input id="identifier" name="identifier" type="text" value="${fn:escapeXml(criteria.identifier)}">
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="name">Name</label>
|
||||
<label for="name">姓名</label>
|
||||
<input id="name" name="name" type="text" value="${fn:escapeXml(criteria.name)}">
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="contact">Phone or email</label>
|
||||
<label for="contact">电话或邮箱</label>
|
||||
<input id="contact" name="contact" type="text" value="${fn:escapeXml(criteria.contact)}">
|
||||
</div>
|
||||
|
||||
<div class="search-field">
|
||||
<label for="status">Status</label>
|
||||
<label for="status">状态</label>
|
||||
<select id="status" name="status">
|
||||
<option value="">All statuses</option>
|
||||
<option value="">全部状态</option>
|
||||
<c:forEach var="status" items="${statuses}">
|
||||
<option value="${status.code}" <c:if test="${criteria.statusCode == status.code}">selected</c:if>>
|
||||
<c:out value="${status.displayName}" />
|
||||
@@ -62,29 +62,29 @@
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<button class="button button-primary" type="submit">Search</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/readers">Clear</a>
|
||||
<button class="button button-primary" type="submit">检索</button>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/readers">清空</a>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="table-panel" aria-labelledby="reader-results-title">
|
||||
<h2 id="reader-results-title">Reader records</h2>
|
||||
<h2 id="reader-results-title">读者记录</h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty readers}">
|
||||
<p class="empty-state">No reader records match the current filters.</p>
|
||||
<p class="empty-state">没有符合当前筛选条件的读者记录。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Reader ID</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Contact</th>
|
||||
<th scope="col">Account</th>
|
||||
<th scope="col">Borrow limit</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col">Actions</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>
|
||||
@@ -105,7 +105,7 @@
|
||||
<c:when test="${not empty reader.username}">
|
||||
<c:out value="${reader.username}" />
|
||||
</c:when>
|
||||
<c:otherwise>Unlinked</c:otherwise>
|
||||
<c:otherwise>未关联</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
<td><c:out value="${reader.maxBorrowCount}" /></td>
|
||||
@@ -117,12 +117,12 @@
|
||||
<td>
|
||||
<div class="table-actions">
|
||||
<a class="button button-secondary"
|
||||
href="${pageContext.request.contextPath}/readers/edit?id=${reader.id}">Edit</a>
|
||||
href="${pageContext.request.contextPath}/readers/edit?id=${reader.id}">编辑</a>
|
||||
<form action="${pageContext.request.contextPath}/readers/delete"
|
||||
method="post"
|
||||
onsubmit="return confirm('Deactivate this reader profile?');">
|
||||
onsubmit="return confirm('确定停用这个读者档案吗?');">
|
||||
<input type="hidden" name="id" value="${reader.id}">
|
||||
<button class="button button-danger" type="submit">Deactivate</button>
|
||||
<button class="button button-danger" type="submit">停用</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Reports - MZH Library</title>
|
||||
<title>报表 - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -13,11 +13,11 @@
|
||||
<main class="page-shell">
|
||||
<section class="dashboard-hero catalog-hero" aria-labelledby="reports-title">
|
||||
<div>
|
||||
<p class="eyebrow">Reports</p>
|
||||
<h1 id="reports-title">Report center</h1>
|
||||
<p>Review collection inventory, borrowing health, overdue loans, and popular books.</p>
|
||||
<p class="eyebrow">报表</p>
|
||||
<h1 id="reports-title">报表中心</h1>
|
||||
<p>查看馆藏库存、借阅状况、逾期借阅和热门图书。</p>
|
||||
</div>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/borrowing">Borrowing records</a>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/borrowing">借阅记录</a>
|
||||
</section>
|
||||
|
||||
<c:if test="${not empty errorMessage}">
|
||||
@@ -27,59 +27,59 @@
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty reportCenter}">
|
||||
<section class="report-grid" aria-label="Report summary">
|
||||
<section class="report-grid" aria-label="报表摘要">
|
||||
<article class="report-card">
|
||||
<p class="eyebrow">Inventory</p>
|
||||
<h2>Total titles</h2>
|
||||
<p class="eyebrow">库存</p>
|
||||
<h2>图书种类总数</h2>
|
||||
<p class="report-metric"><c:out value="${reportCenter.inventorySummary.totalTitles}" /></p>
|
||||
</article>
|
||||
<article class="report-card">
|
||||
<p class="eyebrow">Inventory</p>
|
||||
<h2>Total copies</h2>
|
||||
<p class="eyebrow">库存</p>
|
||||
<h2>馆藏总册数</h2>
|
||||
<p class="report-metric"><c:out value="${reportCenter.inventorySummary.totalCopies}" /></p>
|
||||
</article>
|
||||
<article class="report-card">
|
||||
<p class="eyebrow">Inventory</p>
|
||||
<h2>Available copies</h2>
|
||||
<p class="eyebrow">库存</p>
|
||||
<h2>可借册数</h2>
|
||||
<p class="report-metric"><c:out value="${reportCenter.inventorySummary.availableCopies}" /></p>
|
||||
</article>
|
||||
<article class="report-card">
|
||||
<p class="eyebrow">Attention</p>
|
||||
<h2>Unavailable or empty</h2>
|
||||
<p class="eyebrow">需关注</p>
|
||||
<h2>不可借或无库存</h2>
|
||||
<p class="report-metric"><c:out value="${reportCenter.inventorySummary.unavailableOrEmptyTitles}" /></p>
|
||||
</article>
|
||||
<article class="report-card">
|
||||
<p class="eyebrow">Borrowing</p>
|
||||
<h2>Currently borrowed</h2>
|
||||
<p class="eyebrow">借阅</p>
|
||||
<h2>当前借出</h2>
|
||||
<p class="report-metric"><c:out value="${reportCenter.borrowingSummary.activeLoans}" /></p>
|
||||
</article>
|
||||
<article class="report-card">
|
||||
<p class="eyebrow">Borrowing</p>
|
||||
<h2>Returned records</h2>
|
||||
<p class="eyebrow">借阅</p>
|
||||
<h2>已归还记录</h2>
|
||||
<p class="report-metric"><c:out value="${reportCenter.borrowingSummary.returnedLoans}" /></p>
|
||||
</article>
|
||||
<article class="report-card report-card-alert">
|
||||
<p class="eyebrow">Borrowing</p>
|
||||
<h2>Overdue loans</h2>
|
||||
<p class="eyebrow">借阅</p>
|
||||
<h2>逾期借阅</h2>
|
||||
<p class="report-metric"><c:out value="${reportCenter.borrowingSummary.overdueLoans}" /></p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="table-panel" aria-labelledby="overdue-report-title">
|
||||
<h2 id="overdue-report-title">Overdue list</h2>
|
||||
<h2 id="overdue-report-title">逾期列表</h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty reportCenter.overdueRows}">
|
||||
<p class="empty-state">No active overdue borrowing records.</p>
|
||||
<p class="empty-state">当前没有逾期未还的借阅记录。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Reader</th>
|
||||
<th scope="col">Book</th>
|
||||
<th scope="col">Due date</th>
|
||||
<th scope="col">Overdue days</th>
|
||||
<th scope="col">读者</th>
|
||||
<th scope="col">图书</th>
|
||||
<th scope="col">应还日期</th>
|
||||
<th scope="col">逾期天数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -96,7 +96,7 @@
|
||||
<td><c:out value="${row.dueAtText}" /></td>
|
||||
<td>
|
||||
<span class="status-pill status-overdue">
|
||||
<c:out value="${row.overdueDays}" /> days
|
||||
<c:out value="${row.overdueDays}" /> 天
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -109,19 +109,19 @@
|
||||
</section>
|
||||
|
||||
<section class="table-panel" aria-labelledby="popular-report-title">
|
||||
<h2 id="popular-report-title">Popular borrowing ranking</h2>
|
||||
<h2 id="popular-report-title">热门借阅排行</h2>
|
||||
<c:choose>
|
||||
<c:when test="${empty reportCenter.popularBooks}">
|
||||
<p class="empty-state">No borrowing records are available for ranking yet.</p>
|
||||
<p class="empty-state">暂无可用于排行的借阅记录。</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="table-scroll">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Book</th>
|
||||
<th scope="col">Author</th>
|
||||
<th scope="col">Borrow records</th>
|
||||
<th scope="col">图书</th>
|
||||
<th scope="col">作者</th>
|
||||
<th scope="col">借阅次数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><c:out value="${areaName}" /> - MZH Library</title>
|
||||
<title><c:out value="${areaName}" /> - MZH 图书馆</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/app.css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -17,67 +17,67 @@
|
||||
</p>
|
||||
<h1 id="area-title"><c:out value="${areaName}" /></h1>
|
||||
<p><c:out value="${areaSummary}" /></p>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/dashboard">Back to dashboard</a>
|
||||
<a class="button button-primary" href="${pageContext.request.contextPath}/dashboard">返回控制台</a>
|
||||
</section>
|
||||
|
||||
<section class="card-grid role-actions" aria-label="Workspace actions">
|
||||
<section class="card-grid role-actions" aria-label="工作区操作">
|
||||
<article class="workspace-card">
|
||||
<h2>Book Catalog</h2>
|
||||
<p>Search available collection records by title, author, category, or book identifier.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/catalog">Search catalog</a>
|
||||
<h2>馆藏检索</h2>
|
||||
<p>按书名、作者、分类或图书编号检索可用馆藏记录。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/catalog">检索馆藏</a>
|
||||
</article>
|
||||
|
||||
<c:if test="${sessionScope.userRole == 'administrator' or sessionScope.userRole == 'librarian'}">
|
||||
<c:if test="${sessionScope.userRole == 'administrator'}">
|
||||
<article class="workspace-card">
|
||||
<h2>User Management</h2>
|
||||
<p>Create, update, deactivate, and review login accounts.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/users">Manage users</a>
|
||||
<h2>用户管理</h2>
|
||||
<p>创建、更新、停用和查看登录账户。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/users">管理用户</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>System Logs</h2>
|
||||
<p>Review read-only audit entries for account and maintenance actions.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/system-logs">View logs</a>
|
||||
<h2>系统日志</h2>
|
||||
<p>查看账户与维护操作的只读审计记录。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/admin/system-logs">查看日志</a>
|
||||
</article>
|
||||
</c:if>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Book Management</h2>
|
||||
<p>Create, update, delete, and review inventory fields for book records.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">Manage books</a>
|
||||
<h2>图书管理</h2>
|
||||
<p>创建、更新、删除和查看图书记录的库存字段。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/books">管理图书</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Category Maintenance</h2>
|
||||
<p>Create, update, and retire catalog categories used by book records.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/book-categories">Manage categories</a>
|
||||
<h2>分类维护</h2>
|
||||
<p>创建、更新和停用图书记录使用的馆藏分类。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/book-categories">管理分类</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Reader Management</h2>
|
||||
<p>Create, update, deactivate, and review eligibility fields for reader records.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/readers">Manage readers</a>
|
||||
<h2>读者管理</h2>
|
||||
<p>创建、更新、停用和查看读者记录的资格字段。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/readers">管理读者</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Borrowing Management</h2>
|
||||
<p>Create loans, process returns, renew records, and review overdue items.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/borrowing">Manage borrowing</a>
|
||||
<h2>借阅管理</h2>
|
||||
<p>创建借阅、处理归还、续借记录并查看逾期项目。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/borrowing">管理借阅</a>
|
||||
</article>
|
||||
|
||||
<article class="workspace-card">
|
||||
<h2>Report Center</h2>
|
||||
<p>Review inventory summaries, borrowing health, overdue lists, and popular books.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/reports">View reports</a>
|
||||
<h2>报表中心</h2>
|
||||
<p>查看库存摘要、借阅状况、逾期列表和热门图书。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/reports">查看报表</a>
|
||||
</article>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${sessionScope.userRole == 'reader'}">
|
||||
<article class="workspace-card">
|
||||
<h2>My Loan History</h2>
|
||||
<p>Review active loans, returned records, renewal counts, and overdue status.</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/reader/loans">View history</a>
|
||||
<h2>我的借阅历史</h2>
|
||||
<p>查看在借记录、已还记录、续借次数和逾期状态。</p>
|
||||
<a class="button button-secondary" href="${pageContext.request.contextPath}/reader/loans">查看历史</a>
|
||||
</article>
|
||||
</c:if>
|
||||
</section>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
||||
version="4.0">
|
||||
|
||||
<display-name>MZH Library Management</display-name>
|
||||
<display-name>MZH 图书馆管理系统</display-name>
|
||||
|
||||
<filter>
|
||||
<filter-name>CharacterEncodingFilter</filter-name>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="960" viewBox="0 0 1440 960" role="img" aria-label="Library shelves">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="960" viewBox="0 0 1440 960" role="img" aria-label="图书馆书架">
|
||||
<rect width="1440" height="960" fill="#e8edf1"/>
|
||||
<rect x="0" y="705" width="1440" height="255" fill="#d4ddd8"/>
|
||||
<g opacity="0.92">
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Reference in New Issue
Block a user