Hair Keeper v1.0.0:一个高度集成、深度定制、约定优于配置的全栈Web应用模板,旨在保持灵活性的同时提供一套基于成熟架构的开发底座,自带身份认证、权限控制、丰富前端组件、文件上传、后台任务、智能体开发等丰富功能,提供AI开发辅助,免于纠结功能如何实现,可快速上手专注于业务逻辑
This commit is contained in:
199
src/app/(main)/users/components/BatchAuthorizationDialog.tsx
Normal file
199
src/app/(main)/users/components/BatchAuthorizationDialog.tsx
Normal file
@@ -0,0 +1,199 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { z } from 'zod'
|
||||
import { trpc } from '@/lib/trpc'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { FormDialog, FormActionBar, FormGridContent, FormCancelAction, FormSubmitAction } from '@/components/common/form-dialog'
|
||||
import {
|
||||
AdvancedSelect,
|
||||
SelectPopover,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectInput,
|
||||
SelectItemList,
|
||||
SelectedName,
|
||||
SelectedBadges
|
||||
} from '@/components/common/advanced-select'
|
||||
import { Users } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
// 定义表单数据结构
|
||||
const batchAuthorizationSchema = z.object({
|
||||
roleId: z.number({ message: '请选择角色' }),
|
||||
deptCodes: z.array(z.string()).optional(),
|
||||
})
|
||||
|
||||
type BatchAuthorizationFormData = z.input<typeof batchAuthorizationSchema>
|
||||
|
||||
export const BatchAuthorizationDialog = function BatchAuthorizationDialog() {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [currentAction, setCurrentAction] = useState<'grant' | 'revoke' | null>(null)
|
||||
const utils = trpc.useUtils()
|
||||
|
||||
// 获取部门列表和角色列表
|
||||
const { data: depts = [] } = trpc.common.getDepts.useQuery(undefined, {
|
||||
enabled: isOpen
|
||||
})
|
||||
const { data: roles = [] } = trpc.users.getRoles.useQuery(undefined, {
|
||||
enabled: isOpen
|
||||
})
|
||||
|
||||
// 初始化表单
|
||||
const form = useForm<BatchAuthorizationFormData>({
|
||||
resolver: zodResolver(batchAuthorizationSchema),
|
||||
defaultValues: {
|
||||
roleId: undefined,
|
||||
deptCodes: [],
|
||||
},
|
||||
})
|
||||
|
||||
// 批量更新角色mutation
|
||||
const batchUpdateRoleMutation = trpc.users.batchUpdateRole.useMutation({
|
||||
onSuccess: (result: { count: number }, variables) => {
|
||||
const action = variables.action === 'grant' ? '授予' : '撤销'
|
||||
toast.success(`成功为 ${result.count} 个用户${action}角色`)
|
||||
utils.users.list.invalidate()
|
||||
setCurrentAction(null)
|
||||
setIsOpen(false)
|
||||
},
|
||||
onError: (error: { message?: string }) => {
|
||||
toast.error(error.message || '批量操作失败')
|
||||
setCurrentAction(null)
|
||||
}
|
||||
})
|
||||
|
||||
// 处理授权
|
||||
const handleGrant = async (values: BatchAuthorizationFormData) => {
|
||||
setCurrentAction('grant')
|
||||
batchUpdateRoleMutation.mutate({
|
||||
roleId: values.roleId,
|
||||
deptCodes: values.deptCodes && values.deptCodes.length > 0 ? values.deptCodes : undefined,
|
||||
action: 'grant'
|
||||
})
|
||||
}
|
||||
|
||||
// 处理撤销
|
||||
const handleRevoke = async (values: BatchAuthorizationFormData) => {
|
||||
setCurrentAction('revoke')
|
||||
batchUpdateRoleMutation.mutate({
|
||||
roleId: values.roleId,
|
||||
deptCodes: values.deptCodes && values.deptCodes.length > 0 ? values.deptCodes : undefined,
|
||||
action: 'revoke'
|
||||
})
|
||||
}
|
||||
|
||||
// 处理对话框关闭
|
||||
const handleClose = () => {
|
||||
setIsOpen(false)
|
||||
setCurrentAction(null)
|
||||
}
|
||||
|
||||
// 处理对话框打开
|
||||
const handleOpen = () => {
|
||||
setIsOpen(true)
|
||||
}
|
||||
|
||||
const isLoading = batchUpdateRoleMutation.isPending
|
||||
|
||||
// 定义表单字段配置
|
||||
const fields = [
|
||||
{
|
||||
name: 'roleId',
|
||||
label: '选择角色',
|
||||
required: true,
|
||||
render: ({ field }: any) => (
|
||||
<div className="space-y-2">
|
||||
<AdvancedSelect
|
||||
options={roles.map(role => ({ ...role, id: role.id.toString() }))}
|
||||
value={field.value?.toString() || ''}
|
||||
onChange={(value) => field.onChange(value ? Number(value) : undefined)}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<SelectPopover>
|
||||
<SelectTrigger placeholder="请选择角色" clearable>
|
||||
<SelectedName />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectInput placeholder="搜索角色..." />
|
||||
<SelectItemList />
|
||||
</SelectContent>
|
||||
</SelectPopover>
|
||||
</AdvancedSelect>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
必选项,选择要授予或撤销的角色
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'deptCodes',
|
||||
label: '选择院系(可选)',
|
||||
render: ({ field }: any) => (
|
||||
<div className="space-y-2">
|
||||
<AdvancedSelect
|
||||
options={depts.map(dept => ({ id: dept.code, name: dept.name }))}
|
||||
value={field.value || []}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
disabled={isLoading}
|
||||
multiple={{ enable: true }}
|
||||
>
|
||||
<SelectPopover>
|
||||
<SelectTrigger placeholder="不选择则针对所有用户" clearable>
|
||||
<SelectedBadges maxDisplay={3} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectInput placeholder="搜索院系..." />
|
||||
<SelectItemList />
|
||||
</SelectContent>
|
||||
</SelectPopover>
|
||||
</AdvancedSelect>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
不选择院系时,将对所有用户进行操作
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button variant="outline" className="flex items-center gap-2" onClick={handleOpen}>
|
||||
<Users className="h-4 w-4" />
|
||||
批量授权
|
||||
</Button>
|
||||
|
||||
<FormDialog
|
||||
isOpen={isOpen}
|
||||
title="批量授权"
|
||||
description="为指定范围的用户批量授予或撤销角色"
|
||||
form={form}
|
||||
fields={fields}
|
||||
onClose={handleClose}
|
||||
className="max-w-md"
|
||||
>
|
||||
<FormGridContent />
|
||||
<FormActionBar>
|
||||
<FormCancelAction />
|
||||
<FormSubmitAction
|
||||
onSubmit={handleRevoke}
|
||||
variant="destructive"
|
||||
isSubmitting={batchUpdateRoleMutation.isPending}
|
||||
showSpinningLoader={currentAction === 'revoke'}
|
||||
>
|
||||
撤销权限
|
||||
</FormSubmitAction>
|
||||
<FormSubmitAction
|
||||
onSubmit={handleGrant}
|
||||
isSubmitting={batchUpdateRoleMutation.isPending}
|
||||
showSpinningLoader={currentAction === 'grant'}
|
||||
>
|
||||
授权
|
||||
</FormSubmitAction>
|
||||
</FormActionBar>
|
||||
</FormDialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user