feat: 增加DEFAULT_USER_PASSWORD,作为创建用户时的默认密码,添加p-limit库,添加DB_PARALLEL_LIMIT = 32环境变量作为“数据库批次操作默认并发数” 限制只有超级管理员才能创建超级管理员用户 删除用户时可以级联删除SelectionLog 添加zustand全局状态管理 一对多的院系管理功能 ,支持增删改查院系管理员信息、用户可以在header中切换管理的院系
This commit is contained in:
247
src/app/(main)/users/dept-admin/columns.tsx
Normal file
247
src/app/(main)/users/dept-admin/columns.tsx
Normal file
@@ -0,0 +1,247 @@
|
||||
'use client'
|
||||
|
||||
import { ColumnDef } from '@tanstack/react-table'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Edit, Trash2, MoreHorizontal } from 'lucide-react'
|
||||
import { formatDate } from '@/lib/format'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import { DataTableColumnHeader } from '@/components/data-table/column-header'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
import type { DeptAdmin } from '@/server/routers/dept-admin'
|
||||
|
||||
// 操作回调类型
|
||||
export type DeptAdminActions = {
|
||||
onEdit: (id: number) => void
|
||||
onDelete: (id: number) => void
|
||||
}
|
||||
|
||||
// 列定义选项类型
|
||||
export type DeptAdminColumnsOptions = {
|
||||
depts?: Array<{ code: string; name: string; fullName: string }>
|
||||
}
|
||||
|
||||
// 创建院系管理员表格列定义
|
||||
export const createDeptAdminColumns = (
|
||||
actions: DeptAdminActions,
|
||||
options: DeptAdminColumnsOptions = {}
|
||||
): ColumnDef<DeptAdmin>[] => [
|
||||
{
|
||||
id: "select",
|
||||
header: ({ table }) => (
|
||||
<Checkbox
|
||||
checked={
|
||||
table.getIsAllPageRowsSelected() ||
|
||||
(table.getIsSomePageRowsSelected() && "indeterminate")
|
||||
}
|
||||
onCheckedChange={(value) =>
|
||||
table.toggleAllPageRowsSelected(!!value)
|
||||
}
|
||||
aria-label="Select all"
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<Checkbox
|
||||
checked={row.getIsSelected()}
|
||||
onCheckedChange={(value) => row.toggleSelected(!!value)}
|
||||
aria-label="Select row"
|
||||
/>
|
||||
),
|
||||
size: 32,
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
id: 'id',
|
||||
accessorKey: 'id',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="ID" />
|
||||
),
|
||||
cell: ({ row }) => <div className="font-medium">{row.original.id}</div>,
|
||||
meta: {
|
||||
label: 'ID',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'uid',
|
||||
accessorKey: 'uid',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="用户ID" />
|
||||
),
|
||||
cell: ({ row }) => <div className="font-medium">{row.original.uid}</div>,
|
||||
enableColumnFilter: true,
|
||||
meta: {
|
||||
label: '用户ID',
|
||||
filter: {
|
||||
placeholder: '请输入用户ID',
|
||||
variant: 'text',
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'userName',
|
||||
accessorKey: 'user.name',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="姓名" />
|
||||
),
|
||||
cell: ({ row }) => <div>{row.original.user?.name || '-'}</div>,
|
||||
enableColumnFilter: true,
|
||||
meta: {
|
||||
label: '姓名',
|
||||
filter: {
|
||||
placeholder: '请输入姓名',
|
||||
variant: 'text',
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'deptCode',
|
||||
accessorKey: 'deptCode',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="院系" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div>
|
||||
<div className="font-medium">{row.original.dept?.name || '-'}</div>
|
||||
<div className="text-xs text-muted-foreground">{row.original.deptCode}</div>
|
||||
</div>
|
||||
),
|
||||
enableColumnFilter: true,
|
||||
meta: {
|
||||
label: '院系',
|
||||
filter: {
|
||||
variant: 'multiSelect',
|
||||
options: options.depts?.map(dept => ({
|
||||
id: dept.code,
|
||||
name: dept.fullName,
|
||||
})) || [],
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'adminEmail',
|
||||
accessorKey: 'adminEmail',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="邮箱" />
|
||||
),
|
||||
cell: ({ row }) => <div>{row.original.adminEmail || '-'}</div>,
|
||||
enableColumnFilter: true,
|
||||
meta: {
|
||||
label: '邮箱',
|
||||
filter: {
|
||||
placeholder: '请输入邮箱',
|
||||
variant: 'text',
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'adminLinePhone',
|
||||
accessorKey: 'adminLinePhone',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="座机" />
|
||||
),
|
||||
cell: ({ row }) => <div>{row.original.adminLinePhone || '-'}</div>,
|
||||
enableColumnFilter: true,
|
||||
meta: {
|
||||
label: '座机',
|
||||
filter: {
|
||||
placeholder: '请输入座机',
|
||||
variant: 'text',
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'adminMobilePhone',
|
||||
accessorKey: 'adminMobilePhone',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="手机" />
|
||||
),
|
||||
cell: ({ row }) => <div>{row.original.adminMobilePhone || '-'}</div>,
|
||||
enableColumnFilter: true,
|
||||
meta: {
|
||||
label: '手机',
|
||||
filter: {
|
||||
placeholder: '请输入手机',
|
||||
variant: 'text',
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'note',
|
||||
accessorKey: 'note',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="备注" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div className="max-w-[200px] truncate" title={row.original.note || ''}>
|
||||
{row.original.note || '-'}
|
||||
</div>
|
||||
),
|
||||
enableSorting: false,
|
||||
meta: {
|
||||
label: '备注',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'createdAt',
|
||||
accessorKey: 'createdAt',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="创建时间" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
return <div>{formatDate(row.original.createdAt) || '-'}</div>
|
||||
},
|
||||
meta: {
|
||||
label: '创建时间',
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'updatedAt',
|
||||
accessorKey: 'updatedAt',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="更新时间" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
return <div>{formatDate(row.original.updatedAt) || '-'}</div>
|
||||
},
|
||||
meta: {
|
||||
label: '更新时间',
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
cell: ({ row }) => {
|
||||
const deptAdmin = row.original
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="h-6 w-6 md:w-9">
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
<span className="sr-only">打开菜单</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => actions.onEdit(deptAdmin.id)}>
|
||||
<Edit className="h-4 w-4" />
|
||||
编辑
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
variant="destructive"
|
||||
onClick={() => actions.onDelete(deptAdmin.id)}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
删除
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
},
|
||||
size: 32,
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
]
|
||||
Reference in New Issue
Block a user