diff --git a/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBorrowController.kt b/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBorrowController.kt index 232a9f3..8c731f3 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBorrowController.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/controller/AdminBorrowController.kt @@ -6,10 +6,7 @@ import com.msksbr.bookmgr.script.log import com.msksbr.bookmgr.service.AdminBorrowService import com.msksbr.bookmgr.template.Result import jakarta.servlet.http.HttpServletRequest -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.RequestAttribute -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.* /* * 借阅管理接口(面向管理员) @@ -76,4 +73,37 @@ class AdminBorrowController( log.info("[AdminBorrow] user agent: {}", request.getHeader("User-Agent")) return adminBorrowService.getAllBorrows() } + + /* + * POST /api/admin/borrows/borrowbook?bookId=xxx&userId=xxx + * 管理员手动借书 + */ + @RequireRole("admin") + @PostMapping("/borrowbook") + fun borrowBook( + @RequestAttribute(required = false) username: String?, + bookId: Long, + userId: Long, + request: HttpServletRequest + ): Result { + log.info("[AdminBorrow] borrowBook: user={}, bookId={}, userId={}", username ?: "guest", bookId, userId) + log.info("[AdminBorrow] user agent: {}, ip={}", request.getHeader("User-Agent"), ipExtractor.getRealIp(request)) + return adminBorrowService.borrowBook(bookId, userId) + } + + /* + * POST /api/admin/borrows/returnbook?recordId=xxx + * 管理员手动还书 + */ + @RequireRole("admin") + @PostMapping("/returnbook") + fun returnBook( + @RequestAttribute(required = false) username: String?, + recordId: Long, + request: HttpServletRequest + ): Result { + log.info("[AdminBorrow] returnBook: user={}, recordId={}", username ?: "guest", recordId) + log.info("[AdminBorrow] user agent: {}, ip={}", request.getHeader("User-Agent"), ipExtractor.getRealIp(request)) + return adminBorrowService.returnBook(recordId) + } } diff --git a/src/main/kotlin/com/msksbr/bookmgr/service/AdminBorrowService.kt b/src/main/kotlin/com/msksbr/bookmgr/service/AdminBorrowService.kt index b32a7fb..6adf637 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/service/AdminBorrowService.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/service/AdminBorrowService.kt @@ -37,9 +37,8 @@ interface AdminBorrowService { /* * 管理员手动还书 - * @param bookId 要还的图书 ID - * @param userId 还书的用户 ID + * @param recordId 借阅记录 ID * @return 归还结果 */ - fun returnBook(bookId: Long, userId: Long): Result + fun returnBook(recordId: Long): Result } diff --git a/src/main/kotlin/com/msksbr/bookmgr/service/impl/AdminBorrowServiceImpl.kt b/src/main/kotlin/com/msksbr/bookmgr/service/impl/AdminBorrowServiceImpl.kt index d4a6a21..575e00d 100644 --- a/src/main/kotlin/com/msksbr/bookmgr/service/impl/AdminBorrowServiceImpl.kt +++ b/src/main/kotlin/com/msksbr/bookmgr/service/impl/AdminBorrowServiceImpl.kt @@ -18,6 +18,7 @@ import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking import org.springframework.stereotype.Service +import java.util.* /* * 借阅管理服务实现 @@ -131,14 +132,83 @@ class AdminBorrowServiceImpl( * 管理员手动借书 */ override fun borrowBook(bookId: Long, userId: Long): Result { - TODO("Not yet implemented") + val (matchedUser, matchedBook) = runBlocking { + val userDeferred = async(Dispatchers.IO) { + userMapper.selectById(userId) + } + val bookDeferred = async(Dispatchers.IO) { + bookMapper.selectById(bookId) + } + userDeferred.await() to bookDeferred.await() + } + if (matchedUser == null) { + log.warn("[AdminBorrow] borrowBook: user not found, userId={}", userId) + return Result.error("User does not exist") + } + if (matchedBook == null) { + log.warn("[AdminBorrow] borrowBook: book not found, bookId={}", bookId) + return Result.error("Book does not exist") + } + if (matchedBook.stock < 1) { + log.warn("[AdminBorrow] borrowBook: book out of stock, bookId={}, stock={}", bookId, matchedBook.stock) + return Result.conflict("Book is out of stock") + } + val book = Book( + id = matchedBook.id, + name = matchedBook.name, + author = matchedBook.author, + stock = matchedBook.stock - 1, + ) + val borrow = BorrowRecord( + id = null, + userId = userId, + bookId = bookId, + borrowTime = Date(), + returnTime = null, + status = "BORROWED" + ) + bookMapper.updateById(book) + borrowRecordMapper.insert(borrow) + log.info("[AdminBorrow] borrowBook: success, userId={}, bookId={}, book={}", userId, bookId, matchedBook.name) + return Result.success("Book borrowed successfully") } /* * 管理员手动还书 */ - override fun returnBook(bookId: Long, userId: Long): Result { - TODO("Not yet implemented") + override fun returnBook(recordId: Long): Result { + val matchedBorrow = borrowRecordMapper.selectById(recordId) + if (matchedBorrow == null) { + log.warn("[AdminBorrow] returnBook: record not found, recordId={}", recordId) + return Result.error("Borrow record does not exist") + } + if (matchedBorrow.status == "RETURNED") { + log.warn("[AdminBorrow] returnBook: already returned, recordId={}", recordId) + return Result.conflict("Book has already been returned") + } + val borrow = BorrowRecord( + id = matchedBorrow.id, + bookId = matchedBorrow.bookId, + userId = matchedBorrow.userId, + borrowTime = matchedBorrow.borrowTime, + returnTime = Date(), + status = "RETURNED" + ) + val matchedBook = bookMapper.selectById(matchedBorrow.bookId) + if (matchedBook == null) { + log.warn("[AdminBorrow] returnBook: book not found, bookId={}", matchedBorrow.bookId) + return Result.error("Book does not exist") + } + val book = Book( + id = matchedBook.id, + name = matchedBook.name, + author = matchedBook.author, + stock = matchedBook.stock + 1, + ) + bookMapper.updateById(book) + borrowRecordMapper.updateById(borrow) + log.info("[AdminBorrow] returnBook: success, recordId={}, userId={}, book={}", recordId, borrow.userId, matchedBook.name) + return Result.success("Book returned successfully") } // 并发查询用户和图书信息,组装为 BorrowInfoVo 列表