diff --git a/src/components/layout/AdminLayout.tsx b/src/components/layout/AdminLayout.tsx
index 6110724..94af0c4 100644
--- a/src/components/layout/AdminLayout.tsx
+++ b/src/components/layout/AdminLayout.tsx
@@ -31,7 +31,7 @@ export default function AdminLayout() {
if (!isMobile) {
return (
-
@@ -120,6 +125,9 @@ export default function AdminBooksPage() {
+
@@ -133,6 +141,7 @@ export default function AdminBooksPage() {
{del.book && (
setDel({ open: false, book: null })} />
)}
+ {borrow && setBorrow(null)} />}
)
}
@@ -302,6 +311,45 @@ function DeleteBookDialog({ book, open, onClose }: { book: Book; open: boolean;
)
}
+// ---- Manual Borrow Dialog ----
+function BorrowDialog_({ book, open, onClose }: { book: Book; open: boolean; onClose: () => void }) {
+ const mutation = useAdminBorrowBook()
+ const [userId, setUserId] = useState("")
+
+ useEffect(() => {
+ if (!open) setUserId("")
+ }, [open])
+
+ async function submit(e: FormEvent) {
+ e.preventDefault()
+ if (!userId.trim()) return
+ await mutation.mutateAsync({ bookId: book.id!, userId: Number(userId) })
+ onClose()
+ }
+
+ return (
+
+ )
+}
+
// ---- Skeleton ----
function AdminBooksSkeleton({ isMobile }: { isMobile: boolean }) {
if (isMobile) {
diff --git a/src/features/admin/hooks.ts b/src/features/admin/hooks.ts
index 2f0040a..fdf7962 100644
--- a/src/features/admin/hooks.ts
+++ b/src/features/admin/hooks.ts
@@ -2,7 +2,7 @@ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
import { toast } from "sonner"
import { getAllBooks } from "@/api/books"
import { addBook, deleteBook, updateBook, updateStock } from "@/api/admin/books"
-import { getAllBorrows, searchBorrows, returnBook } from "@/api/admin/borrows"
+import { getAllBorrows, searchBorrows, returnBook, borrowBook as adminBorrowBook } from "@/api/admin/borrows"
export function useAdminBooks() {
return useQuery({
@@ -96,3 +96,18 @@ export function useAdminReturnBook() {
},
})
}
+
+export function useAdminBorrowBook() {
+ const qc = useQueryClient()
+ return useMutation({
+ mutationFn: ({ bookId, userId }: { bookId: number; userId: number }) =>
+ adminBorrowBook(bookId, userId),
+ onSuccess: () => {
+ qc.invalidateQueries({ queryKey: ["admin", "borrows"] })
+ toast.success("借阅成功")
+ },
+ onError: (err) => {
+ toast.error(err instanceof Error ? err.message : "借阅失败")
+ },
+ })
+}
diff --git a/src/router/index.tsx b/src/router/index.tsx
index ad5b123..b824c17 100644
--- a/src/router/index.tsx
+++ b/src/router/index.tsx
@@ -1,5 +1,6 @@
import { createBrowserRouter, Navigate } from "react-router-dom"
import { ProtectedRoute, AdminRoute } from "./guards"
+import { useAuthStore } from "@/store/authStore"
import LoginPage from "@/features/auth/LoginPage"
import BooksPage from "@/features/books/BooksPage"
import MyBorrowsPage from "@/features/borrows/MyBorrowsPage"
@@ -8,6 +9,11 @@ import AdminBorrowsPage from "@/features/admin/AdminBorrowsPage"
import AppLayout from "@/components/layout/AppLayout"
import AdminLayout from "@/components/layout/AdminLayout"
+function RootRedirect() {
+ const isAdmin = useAuthStore((s) => s.isAdmin())
+ return
+}
+
export const router = createBrowserRouter([
{
path: "/login",
@@ -18,7 +24,7 @@ export const router = createBrowserRouter([
children: [
{
path: "/",
- element: ,
+ element: ,
},
{
path: "/books",