Hair Keeper v1.0.0:一个高度集成、深度定制、约定优于配置的全栈Web应用模板,旨在保持灵活性的同时提供一套基于成熟架构的开发底座,自带身份认证、权限控制、丰富前端组件、文件上传、后台任务、智能体开发等丰富功能,提供AI开发辅助,免于纠结功能如何实现,可快速上手专注于业务逻辑

This commit is contained in:
2025-11-13 15:24:54 +08:00
commit 42be39b343
249 changed files with 38843 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
'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>
)
}