forked from admin/hair-keeper
151 lines
5.0 KiB
TypeScript
151 lines
5.0 KiB
TypeScript
'use client'
|
||
|
||
import React, { useState, useCallback, useMemo, Suspense } from 'react'
|
||
import { trpc } from '@/lib/trpc'
|
||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||
import { UserCreateDialog } from './components/UserCreateDialog'
|
||
import { UserUpdateDialog } from './components/UserUpdateDialog'
|
||
import { UserDeleteDialog } from './components/UserDeleteDialog'
|
||
import { RoleManagementDialog } from './components/RoleManagementDialog'
|
||
import { BatchAuthorizationDialog } from './components/BatchAuthorizationDialog'
|
||
import { DataTable } from '@/components/data-table/data-table'
|
||
import { DataTableToolbar } from '@/components/data-table/toolbar'
|
||
import { createUserColumns, type UserColumnsOptions } from './columns'
|
||
import type { User } from '@/server/routers/users'
|
||
import { useDataTable } from '@/hooks/use-data-table'
|
||
import { keepPreviousData } from '@tanstack/react-query'
|
||
import { DataTableSortList } from '@/components/data-table/sort-list'
|
||
import { toast } from 'sonner'
|
||
import { DataTableSkeleton } from '@/components/data-table/table-skeleton'
|
||
|
||
interface UsersPageDataTableProps {
|
||
onEdit: (userId: string) => void
|
||
onDelete: (userId: string) => void
|
||
}
|
||
|
||
function UsersPageDataTable({ onEdit, onDelete }: UsersPageDataTableProps) {
|
||
// 获取角色、权限和部门列表用于过滤器选项
|
||
const { data: roles } = trpc.users.getRoles.useQuery()
|
||
const { data: permissions } = trpc.users.getPermissions.useQuery()
|
||
const { data: depts } = trpc.common.getDepts.useQuery()
|
||
|
||
// 创建表格列定义选项
|
||
const columnsOptions: UserColumnsOptions = useMemo(() => ({
|
||
roles: roles || [],
|
||
permissions: permissions || [],
|
||
depts: depts || [],
|
||
}), [roles, permissions, depts])
|
||
|
||
// 创建表格列定义
|
||
const columns = useMemo(() => createUserColumns({
|
||
onEdit,
|
||
onDelete,
|
||
}, columnsOptions), [onEdit, onDelete, columnsOptions])
|
||
|
||
// 使用 useDataTable hook,传入 queryFn
|
||
const { table, queryResult } = useDataTable<User>({
|
||
columns,
|
||
initialState: {
|
||
pagination: { pageIndex: 1, pageSize: 10 },
|
||
columnPinning: { left: ["select"], right: ["actions"] },
|
||
},
|
||
getRowId: (row) => row.id,
|
||
queryFn: useCallback((params) => {
|
||
const result = trpc.users.list.useQuery(params, {
|
||
placeholderData: keepPreviousData,
|
||
})
|
||
if (result.error) {
|
||
toast.error("获取用户数据失败:" + result.error.toString().substring(0, 100))
|
||
}
|
||
return result
|
||
}, []),
|
||
})
|
||
|
||
return (
|
||
<DataTable table={table} isLoading={queryResult.isLoading}>
|
||
<DataTableToolbar table={table}>
|
||
<DataTableSortList table={table} />
|
||
</DataTableToolbar>
|
||
</DataTable>
|
||
)
|
||
}
|
||
|
||
export default function UsersPage() {
|
||
// 更新用户对话框状态
|
||
const [updateUserId, setUpdateUserId] = useState<string | null>(null)
|
||
const [isUpdateDialogOpen, setIsUpdateDialogOpen] = useState(false)
|
||
|
||
// 删除用户对话框状态
|
||
const [deleteUserId, setDeleteUserId] = useState<string | null>(null)
|
||
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false)
|
||
|
||
// 用于刷新数据的 utils
|
||
const utils = trpc.useUtils()
|
||
|
||
// 处理编辑用户
|
||
const handleEditUser = useCallback((userId: string) => {
|
||
setUpdateUserId(userId)
|
||
setIsUpdateDialogOpen(true)
|
||
}, [])
|
||
|
||
// 关闭更新对话框
|
||
const handleCloseUpdateDialog = useCallback(() => {
|
||
setIsUpdateDialogOpen(false)
|
||
setUpdateUserId(null)
|
||
}, [])
|
||
|
||
// 处理删除用户
|
||
const handleDeleteUser = useCallback((userId: string) => {
|
||
setDeleteUserId(userId)
|
||
setIsDeleteDialogOpen(true)
|
||
}, [])
|
||
|
||
// 关闭删除对话框
|
||
const handleCloseDeleteDialog = useCallback(() => {
|
||
setIsDeleteDialogOpen(false)
|
||
setDeleteUserId(null)
|
||
}, [])
|
||
|
||
// 刷新用户列表
|
||
const handleRefreshUsers = useCallback(() => {
|
||
utils.users.list.invalidate()
|
||
}, [utils])
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
{/* 用户列表和创建按钮 */}
|
||
<Card>
|
||
<CardHeader className="flex items-center justify-between">
|
||
<CardTitle className="text-lg">用户列表</CardTitle>
|
||
<div className="flex items-center gap-2">
|
||
<RoleManagementDialog />
|
||
<BatchAuthorizationDialog />
|
||
<UserCreateDialog onUserCreated={handleRefreshUsers} />
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<Suspense fallback={<DataTableSkeleton columnCount={8} rowCount={10} />}>
|
||
<UsersPageDataTable onEdit={handleEditUser} onDelete={handleDeleteUser} />
|
||
</Suspense>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* 更新用户对话框 */}
|
||
<UserUpdateDialog
|
||
userId={updateUserId}
|
||
isOpen={isUpdateDialogOpen}
|
||
onClose={handleCloseUpdateDialog}
|
||
onUserUpdated={handleRefreshUsers}
|
||
/>
|
||
|
||
{/* 删除用户对话框 */}
|
||
<UserDeleteDialog
|
||
userId={deleteUserId}
|
||
isOpen={isDeleteDialogOpen}
|
||
onClose={handleCloseDeleteDialog}
|
||
onUserDeleted={handleRefreshUsers}
|
||
/>
|
||
</div>
|
||
)
|
||
}
|