187 lines
5.6 KiB
TypeScript
187 lines
5.6 KiB
TypeScript
'use client'
|
||
|
||
import React, { useState } from 'react'
|
||
import { useForm } from 'react-hook-form'
|
||
import { z } from 'zod'
|
||
import { zodResolver } from '@hookform/resolvers/zod'
|
||
import { trpc } from '@/lib/trpc'
|
||
import { Button } from '@/components/ui/button'
|
||
import { Input } from '@/components/ui/input'
|
||
import { Dialog, DialogTrigger } from '@/components/ui/dialog'
|
||
import { Plus } from 'lucide-react'
|
||
import { toast } from 'sonner'
|
||
import { FormDialog, FormActionBar, FormGridContent, FormCancelAction, FormSubmitAction, type FormFieldConfig } from '@/components/common/form-dialog'
|
||
import {
|
||
AdvancedSelect,
|
||
SelectPopover,
|
||
SelectTrigger,
|
||
SelectContent,
|
||
SelectInput,
|
||
SelectItemList,
|
||
SelectedName
|
||
} from '@/components/common/advanced-select'
|
||
import { useSmartSelectOptions } from '@/hooks/use-smart-select-options'
|
||
import { Textarea } from '@/components/ui/textarea'
|
||
|
||
// 创建院系管理员的 schema
|
||
const createDeptAdminSchema = z.object({
|
||
uid: z.string().min(1, '用户ID不能为空'),
|
||
deptCode: z.string().min(1, '院系代码不能为空'),
|
||
adminEmail: z.string().email('邮箱格式不正确').optional().or(z.literal('')),
|
||
adminLinePhone: z.string().optional(),
|
||
adminMobilePhone: z.string().optional(),
|
||
note: z.string().optional(),
|
||
})
|
||
|
||
type CreateDeptAdminInput = z.input<typeof createDeptAdminSchema>
|
||
|
||
const createDeptAdminDefaultValues: CreateDeptAdminInput = {
|
||
uid: '',
|
||
deptCode: '',
|
||
adminEmail: '',
|
||
adminLinePhone: '',
|
||
adminMobilePhone: '',
|
||
note: '',
|
||
}
|
||
|
||
interface DeptAdminCreateDialogProps {
|
||
onDeptAdminCreated: () => void
|
||
}
|
||
|
||
export function DeptAdminCreateDialog({ onDeptAdminCreated }: DeptAdminCreateDialogProps) {
|
||
// 表单 dialog 控制
|
||
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false)
|
||
|
||
// react-hook-form 管理创建表单
|
||
const createForm = useForm<CreateDeptAdminInput>({
|
||
resolver: zodResolver(createDeptAdminSchema),
|
||
defaultValues: createDeptAdminDefaultValues,
|
||
})
|
||
|
||
// 获取院系列表
|
||
const { data: depts } = trpc.common.getDepts.useQuery()
|
||
|
||
const deptOptions = depts?.map(dept => ({ id: dept.code, name: dept.fullName, shortName: dept.name })) || []
|
||
const { sortedOptions: sortedDeptOptions, logSelection: logDeptSelection } = useSmartSelectOptions({
|
||
options: deptOptions,
|
||
context: 'deptAdmin.create.dept',
|
||
scope: 'personal',
|
||
})
|
||
|
||
// 创建院系管理员 mutation
|
||
const createDeptAdminMutation = trpc.deptAdmin.create.useMutation({
|
||
onSuccess: () => {
|
||
setIsCreateDialogOpen(false)
|
||
createForm.reset(createDeptAdminDefaultValues)
|
||
toast.success('院系管理员创建成功')
|
||
onDeptAdminCreated()
|
||
},
|
||
onError: (error) => {
|
||
toast.error(error.message || '创建院系管理员失败')
|
||
},
|
||
})
|
||
|
||
// 定义字段配置
|
||
const formFields: FormFieldConfig[] = React.useMemo(() => [
|
||
{
|
||
name: 'uid',
|
||
label: '用户ID',
|
||
required: true,
|
||
render: ({ field }) => (
|
||
<Input {...field} placeholder="请输入用户ID(职工号)" />
|
||
),
|
||
},
|
||
{
|
||
name: 'deptCode',
|
||
label: '院系',
|
||
required: true,
|
||
render: ({ field }) => (
|
||
<AdvancedSelect
|
||
{...field}
|
||
options={sortedDeptOptions}
|
||
onChange={(value) => { logDeptSelection(value); field.onChange(value) }}
|
||
filterFunction={(option, searchValue) => {
|
||
const search = searchValue.toLowerCase()
|
||
return option.id.includes(search) || option.name.toLowerCase().includes(search) ||
|
||
(option.shortName && option.shortName.toLowerCase().includes(search))
|
||
}}
|
||
>
|
||
<SelectPopover>
|
||
<SelectTrigger placeholder="请选择院系">
|
||
<SelectedName />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectInput placeholder="搜索院系名称/代码" />
|
||
<SelectItemList />
|
||
</SelectContent>
|
||
</SelectPopover>
|
||
</AdvancedSelect>
|
||
),
|
||
},
|
||
{
|
||
name: 'adminEmail',
|
||
label: '邮箱',
|
||
render: ({ field }) => (
|
||
<Input {...field} type="email" placeholder="请输入邮箱" />
|
||
),
|
||
},
|
||
{
|
||
name: 'adminLinePhone',
|
||
label: '座机',
|
||
render: ({ field }) => (
|
||
<Input {...field} placeholder="请输入座机号码" />
|
||
),
|
||
},
|
||
{
|
||
name: 'adminMobilePhone',
|
||
label: '手机',
|
||
render: ({ field }) => (
|
||
<Input {...field} placeholder="请输入手机号码" />
|
||
),
|
||
},
|
||
{
|
||
name: 'note',
|
||
label: '备注',
|
||
render: ({ field }) => (
|
||
<Textarea {...field} placeholder="请输入备注信息" className="min-h-[80px]" />
|
||
),
|
||
},
|
||
], [sortedDeptOptions, logDeptSelection])
|
||
|
||
const handleSubmit = async (data: CreateDeptAdminInput) => {
|
||
createDeptAdminMutation.mutate(data)
|
||
}
|
||
|
||
const handleClose = () => {
|
||
setIsCreateDialogOpen(false)
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<Dialog open={isCreateDialogOpen} onOpenChange={setIsCreateDialogOpen}>
|
||
<DialogTrigger asChild>
|
||
<Button className="flex items-center gap-2">
|
||
<Plus className="h-4 w-4" />
|
||
创建院系管理员
|
||
</Button>
|
||
</DialogTrigger>
|
||
</Dialog>
|
||
|
||
<FormDialog
|
||
isOpen={isCreateDialogOpen}
|
||
title="创建院系管理员"
|
||
description="请填写院系管理员信息"
|
||
form={createForm}
|
||
fields={formFields}
|
||
onClose={handleClose}
|
||
>
|
||
<FormGridContent />
|
||
<FormActionBar>
|
||
<FormCancelAction />
|
||
<FormSubmitAction onSubmit={handleSubmit} isSubmitting={createDeptAdminMutation.isPending}>创建</FormSubmitAction>
|
||
</FormActionBar>
|
||
</FormDialog>
|
||
</>
|
||
)
|
||
}
|