新增儀表板快速操作功能

This commit is contained in:
2025-08-05 12:35:41 +08:00
parent 279720e276
commit d0c4adf243
3 changed files with 93 additions and 10 deletions

View File

@@ -13,6 +13,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import { Label } from "@/components/ui/label"
import { Alert, AlertDescription } from "@/components/ui/alert"
import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination"
import {
Search,
MoreHorizontal,
@@ -67,6 +68,12 @@ export function UserManagement() {
totalApps: 0,
totalReviews: 0
})
// Pagination state
const [currentPage, setCurrentPage] = useState(1)
const [totalPages, setTotalPages] = useState(1)
const [totalUsers, setTotalUsers] = useState(0)
const [itemsPerPage] = useState(10) // Default to 10 items per page
// 載入用戶資料
useEffect(() => {
@@ -74,8 +81,8 @@ export function UserManagement() {
try {
setIsLoading(true)
// 獲取用戶列表
const usersResponse = await fetch('/api/users', {
// 獲取用戶列表 with pagination
const usersResponse = await fetch(`/api/users?page=${currentPage}&limit=${itemsPerPage}`, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
@@ -84,6 +91,8 @@ export function UserManagement() {
if (usersResponse.ok) {
const usersData = await usersResponse.json()
setUsers(usersData.users || [])
setTotalPages(usersData.pagination?.totalPages || 1)
setTotalUsers(usersData.pagination?.total || 0)
} else {
const errorData = await usersResponse.json().catch(() => ({}))
console.error('獲取用戶列表失敗:', errorData.error || usersResponse.statusText)
@@ -105,14 +114,15 @@ export function UserManagement() {
console.error('獲取統計資料失敗:', errorData.error || statsResponse.statusText)
}
} catch (error) {
console.error('載入資料失敗:', error)
console.error('載入用戶資料失敗:', error)
setError('載入用戶資料失敗')
} finally {
setIsLoading(false)
}
}
fetchUsers()
}, [])
}, [currentPage, itemsPerPage]) // Re-fetch when page changes
// 重新獲取統計數據的函數
const refreshStats = async () => {
@@ -734,8 +744,11 @@ export function UserManagement() {
{/* Users Table */}
<Card>
<CardHeader>
<CardTitle> ({filteredUsers.length})</CardTitle>
<CardDescription></CardDescription>
<CardTitle> ({totalUsers} )</CardTitle>
<CardDescription>
- {currentPage} {totalPages}
{totalPages > 1 && ` (每頁 ${itemsPerPage} 筆)`}
</CardDescription>
</CardHeader>
<CardContent>
{isLoading ? (
@@ -859,6 +872,66 @@ export function UserManagement() {
</CardContent>
</Card>
{/* Pagination */}
{totalPages > 1 && (
<div className="flex justify-center items-center py-4">
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
href="#"
onClick={(e) => {
e.preventDefault()
if (currentPage > 1) setCurrentPage(currentPage - 1)
}}
className={currentPage === 1 ? "pointer-events-none opacity-50" : ""}
/>
</PaginationItem>
{/* Page numbers */}
{Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
let pageNum
if (totalPages <= 5) {
pageNum = i + 1
} else if (currentPage <= 3) {
pageNum = i + 1
} else if (currentPage >= totalPages - 2) {
pageNum = totalPages - 4 + i
} else {
pageNum = currentPage - 2 + i
}
return (
<PaginationItem key={pageNum}>
<PaginationLink
href="#"
onClick={(e) => {
e.preventDefault()
setCurrentPage(pageNum)
}}
isActive={currentPage === pageNum}
>
{pageNum}
</PaginationLink>
</PaginationItem>
)
})}
<PaginationItem>
<PaginationNext
href="#"
onClick={(e) => {
e.preventDefault()
if (currentPage < totalPages) setCurrentPage(currentPage + 1)
}}
className={currentPage === totalPages ? "pointer-events-none opacity-50" : ""}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
</div>
)}
{/* Invite User Dialog - 包含角色選擇 */}
<Dialog open={showInviteUser} onOpenChange={setShowInviteUser}>
<DialogContent className="max-w-md">