import React, { useState, useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { z } from 'zod'; import { Button } from '@d8d/shared-ui-components/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@d8d/shared-ui-components/components/ui/dialog'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@d8d/shared-ui-components/components/ui/card'; import { Badge } from '@d8d/shared-ui-components/components/ui/badge'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@d8d/shared-ui-components/components/ui/table'; import { Separator } from '@d8d/shared-ui-components/components/ui/separator'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from '@d8d/shared-ui-components/components/ui/form'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@d8d/shared-ui-components/components/ui/select'; import { Input } from '@d8d/shared-ui-components/components/ui/input'; import { Textarea } from '@d8d/shared-ui-components/components/ui/textarea'; import { toast } from 'sonner'; import { User, Users, X } from 'lucide-react'; import { AreaSelect } from '@d8d/area-management-ui'; import { OrderStatus, WorkStatus } from '@d8d/allin-enums'; import { DisabledPersonSelector } from '@d8d/allin-disability-person-management-ui'; import { PlatformSelector } from '@d8d/allin-platform-management-ui'; import { CompanySelector } from '@d8d/allin-company-management-ui'; import { ChannelSelector } from '@d8d/allin-channel-management-ui'; import { orderClient, orderClientManager } from '../api/orderClient'; import type { OrderDetail } from '../api/types'; import type { DisabledPersonData } from '@d8d/allin-disability-person-management-ui'; // 人员信息Schema const personInfoSchema = z.object({ personId: z.number().int().positive('请选择人员'), joinDate: z.string().datetime('请选择有效的入职日期'), salaryDetail: z.string().min(1, '薪资详情不能为空'), leaveDate: z.string().datetime().optional(), workStatus: z.nativeEnum(WorkStatus).optional(), role: z.string().max(50, '角色不能超过50个字符').optional(), remark: z.string().max(200, '备注不能超过200个字符').optional(), }); // 订单表单Schema const orderFormSchema = z.object({ orderName: z.string().min(1, '订单名称不能为空').max(100, '订单名称不能超过100个字符'), platformId: z.number().int().positive('请选择平台'), companyId: z.number().int().positive('请选择公司'), channelId: z.number().int().positive('请选择渠道'), expectedStartDate: z.string().datetime('请选择有效的开始日期'), expectedEndDate: z.string().datetime('请选择有效的结束日期').optional(), orderStatus: z.nativeEnum(OrderStatus), workStatus: z.nativeEnum(WorkStatus), provinceId: z.number().int().positive('请选择省份').optional(), cityId: z.number().int().positive('请选择城市').optional(), districtId: z.number().int().positive('请选择区县').optional(), address: z.string().max(200, '地址不能超过200个字符').optional(), contactPerson: z.string().max(50, '联系人不能超过50个字符').optional(), contactPhone: z.string().regex(/^1[3-9]\d{9}$/, '请输入有效的手机号').optional(), remark: z.string().max(500, '备注不能超过500个字符').optional(), orderPersons: z.array(personInfoSchema).min(1, '至少选择一名人员'), }); type OrderFormValues = z.infer; interface OrderFormProps { order?: OrderDetail; open: boolean; onOpenChange: (open: boolean) => void; onSuccess?: () => void; } export const OrderForm: React.FC = ({ order, open, onOpenChange, onSuccess, }) => { const queryClient = useQueryClient(); const [isSubmitting, setIsSubmitting] = useState(false); const [selectedPersons, setSelectedPersons] = useState([]); const [isPersonSelectorOpen, setIsPersonSelectorOpen] = useState(false); // 当残疾人选择器打开时,防止订单表单关闭 useEffect(() => { // 这个effect只是用于调试 console.debug('OrderForm: isPersonSelectorOpen changed to', isPersonSelectorOpen); }, [isPersonSelectorOpen]); // 处理Dialog的onOpenChange,防止在残疾人选择器打开时关闭订单表单 const handleDialogOpenChange = (newOpen: boolean) => { console.debug('OrderForm: handleDialogOpenChange called with', newOpen, 'isPersonSelectorOpen:', isPersonSelectorOpen); if (isPersonSelectorOpen && !newOpen) { console.debug('OrderForm: 阻止订单表单关闭,因为残疾人选择器正在打开'); return; // 如果残疾人选择器正在打开,阻止订单表单关闭 } onOpenChange(newOpen); }; // 初始化表单 - 根据UI包开发规范,必须使用条件渲染两个独立的Form组件 // 这里使用同一个组件,但通过reset来区分创建和编辑模式 const form = useForm({ resolver: zodResolver(orderFormSchema), defaultValues: { orderName: '', platformId: 0, companyId: 0, channelId: 0, expectedStartDate: new Date().toISOString(), expectedEndDate: '', orderStatus: OrderStatus.DRAFT, workStatus: WorkStatus.NOT_WORKING, provinceId: undefined, cityId: undefined, districtId: undefined, address: '', contactPerson: '', contactPhone: '', remark: '', orderPersons: [], }, }); // 当订单数据变化时,重置表单 useEffect(() => { if (order && open) { // 使用类型断言,因为OrderDetail可能不包含所有表单字段 const orderData = order as any; form.reset({ orderName: orderData.orderName || '', platformId: orderData.platformId || 0, companyId: orderData.companyId || 0, channelId: orderData.channelId || 0, expectedStartDate: orderData.expectedStartDate || new Date().toISOString(), expectedEndDate: orderData.expectedEndDate || '', orderStatus: orderData.orderStatus || OrderStatus.DRAFT, workStatus: orderData.workStatus || WorkStatus.NOT_WORKING, provinceId: orderData.provinceId || undefined, cityId: orderData.cityId || undefined, districtId: orderData.districtId || undefined, address: orderData.address || '', contactPerson: orderData.contactPerson || '', contactPhone: orderData.contactPhone || '', remark: orderData.remark || '', orderPersons: [], }); // 编辑模式下清空已选择的人员 setSelectedPersons([]); } else if (!order && open) { form.reset({ orderName: '', platformId: 0, companyId: 0, channelId: 0, expectedStartDate: new Date().toISOString(), expectedEndDate: '', orderStatus: OrderStatus.DRAFT, workStatus: WorkStatus.NOT_WORKING, provinceId: undefined, cityId: undefined, districtId: undefined, address: '', contactPerson: '', contactPhone: '', remark: '', orderPersons: [], }); // 创建模式下清空已选择的人员 setSelectedPersons([]); } }, [order, open, form]); // 创建订单Mutation const createMutation = useMutation({ mutationFn: async (data: OrderFormValues) => { const response = await orderClientManager.get().create.$post({ json: data, }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '创建订单失败'); } return response.json(); }, onSuccess: () => { toast.success('订单创建成功'); queryClient.invalidateQueries({ queryKey: ['orders'] }); onOpenChange(false); form.reset(); onSuccess?.(); }, onError: (error: Error) => { toast.error(`创建订单失败: ${error.message}`); }, }); // 更新订单Mutation const updateMutation = useMutation({ mutationFn: async (data: OrderFormValues & { id: number }) => { const response = await orderClientManager.get().update[':id'].$put({ param: { id: data.id }, json: data, }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '更新订单失败'); } return response.json(); }, onSuccess: () => { toast.success('订单更新成功'); queryClient.invalidateQueries({ queryKey: ['orders'] }); queryClient.invalidateQueries({ queryKey: ['order', order?.id] }); onOpenChange(false); form.reset(); onSuccess?.(); }, onError: (error: Error) => { toast.error(`更新订单失败: ${error.message}`); }, }); // 处理表单提交 const onSubmit = async (data: OrderFormValues) => { setIsSubmitting(true); try { if (order?.id) { // 编辑订单:只更新订单信息,不处理人员 await updateMutation.mutateAsync({ ...data, id: order.id }); } else { // 创建订单:先创建订单,然后批量添加人员 // 提取订单基本信息(不包含orderPersons) const { orderPersons, ...orderData } = data; // 创建订单 const createResponse = await orderClientManager.get().create.$post({ json: orderData, }); if (!createResponse.ok) { const error = await createResponse.json(); throw new Error(error.message || '创建订单失败'); } const createdOrder = await createResponse.json(); toast.success('订单创建成功'); // 如果有人员信息,批量添加人员 if (orderPersons && orderPersons.length > 0) { try { const batchResponse = await orderClientManager.get()[':orderId'].persons.batch.$post({ param: { orderId: createdOrder.id }, json: { persons: orderPersons }, }); if (!batchResponse.ok) { const error = await batchResponse.json(); throw new Error(error.message || '批量添加人员失败'); } toast.success(`成功添加 ${orderPersons.length} 名人员到订单`); } catch (batchError) { // 人员添加失败,但订单已创建成功 toast.warning(`订单创建成功,但添加人员失败: ${batchError instanceof Error ? batchError.message : '未知错误'}`); } } // 刷新订单列表 queryClient.invalidateQueries({ queryKey: ['orders'] }); onOpenChange(false); form.reset(); onSuccess?.(); } } catch (error) { toast.error(`操作失败: ${error instanceof Error ? error.message : '未知错误'}`); } finally { setIsSubmitting(false); } }; // 处理区域选择变化 const handleAreaChange = (value: { provinceId?: number; cityId?: number; districtId?: number }) => { form.setValue('provinceId', value.provinceId, { shouldValidate: true }); form.setValue('cityId', value.cityId, { shouldValidate: true }); form.setValue('districtId', value.districtId, { shouldValidate: true }); }; // 处理残疾人选择 const handlePersonSelect = (persons: DisabledPersonData | DisabledPersonData[]) => { if (Array.isArray(persons)) { // 多选模式 const newPersons = persons.filter( person => !selectedPersons.some(p => p.id === person.id) ); setSelectedPersons(prev => [...prev, ...newPersons]); // 更新表单值 - 根据后端API要求包含必需字段 const currentPersons = form.getValues('orderPersons') || []; const newFormPersons = newPersons.map(person => ({ personId: person.id, joinDate: new Date().toISOString(), // 默认当前时间 salaryDetail: '待定', // 默认值 leaveDate: undefined, workStatus: WorkStatus.WORKING, role: '', remark: '' })); form.setValue('orderPersons', [...currentPersons, ...newFormPersons]); } else { // 单选模式 const person = persons; if (!selectedPersons.some(p => p.id === person.id)) { setSelectedPersons(prev => [...prev, person]); // 更新表单值 - 根据后端API要求包含必需字段 const currentPersons = form.getValues('orderPersons') || []; form.setValue('orderPersons', [ ...currentPersons, { personId: person.id, joinDate: new Date().toISOString(), // 默认当前时间 salaryDetail: '待定', // 默认值 leaveDate: undefined, workStatus: WorkStatus.WORKING, role: '', remark: '' } ]); } } setIsPersonSelectorOpen(false); }; // 处理移除人员 const handleRemovePerson = (personId: number) => { setSelectedPersons(prev => prev.filter(p => p.id !== personId)); // 更新表单值 const currentPersons = form.getValues('orderPersons') || []; form.setValue('orderPersons', currentPersons.filter(p => p.personId !== personId)); }; // 处理人员详情更新 const handlePersonDetailChange = (personId: number, field: keyof OrderFormValues['orderPersons'][0], value: string) => { const currentPersons = form.getValues('orderPersons') || []; const updatedPersons = currentPersons.map(person => person.personId === personId ? { ...person, [field]: value } : person ); form.setValue('orderPersons', updatedPersons); }; // 订单状态选项 const orderStatusOptions = [ { value: OrderStatus.DRAFT, label: '草稿' }, { value: OrderStatus.CONFIRMED, label: '已确认' }, { value: OrderStatus.IN_PROGRESS, label: '进行中' }, { value: OrderStatus.COMPLETED, label: '已完成' }, { value: OrderStatus.CANCELLED, label: '已取消' }, ]; // 工作状态选项 const workStatusOptions = [ { value: WorkStatus.NOT_WORKING, label: '未就业' }, { value: WorkStatus.PRE_WORKING, label: '待就业' }, { value: WorkStatus.WORKING, label: '已就业' }, { value: WorkStatus.RESIGNED, label: '已离职' }, ]; return ( <> {order?.id ? '编辑订单' : '创建订单'} {order?.id ? '修改订单信息' : '创建新的订单'}
console.debug('表单验证错误:', errors))} className="space-y-4">
( 订单名称 )} /> ( 平台 )} /> ( 公司 )} /> ( 渠道 )} /> ( 预计开始日期 field.onChange(e.target.value + ':00.000Z')} /> )} /> ( 预计结束日期 field.onChange(e.target.value ? e.target.value + ':00.000Z' : '')} /> )} /> ( 订单状态 )} /> ( 工作状态 )} />
( 区域选择 选择订单相关的省、市、区信息 )} />
( 详细地址 )} />
( 联系人 )} /> ( 联系电话 )} />
( 备注