|
|
@@ -25,7 +25,6 @@ import { Separator } from '@d8d/shared-ui-components/components/ui/separator';
|
|
|
import {
|
|
|
Form,
|
|
|
FormControl,
|
|
|
- FormDescription,
|
|
|
FormField,
|
|
|
FormItem,
|
|
|
FormLabel,
|
|
|
@@ -39,47 +38,35 @@ import {
|
|
|
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 { orderClientManager } from '../api/orderClient';
|
|
|
import type { OrderDetail } from '../api/types';
|
|
|
import type { DisabledPersonData } from '@d8d/allin-disability-person-management-ui';
|
|
|
|
|
|
-// 人员信息Schema
|
|
|
+// 人员信息Schema - 与后端BatchAddPersonItemSchema保持一致
|
|
|
const personInfoSchema = z.object({
|
|
|
personId: z.number().int().positive('请选择人员'),
|
|
|
joinDate: z.string().datetime('请选择有效的入职日期'),
|
|
|
- salaryDetail: z.string().min(1, '薪资详情不能为空'),
|
|
|
+ salaryDetail: z.coerce.number<number>().positive('薪资必须为正数'),
|
|
|
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
|
|
|
+// 订单表单Schema - 与后端实体和schema保持一致
|
|
|
const orderFormSchema = z.object({
|
|
|
- orderName: z.string().min(1, '订单名称不能为空').max(100, '订单名称不能超过100个字符'),
|
|
|
+ orderName: z.string().min(1, '订单名称不能为空').max(50, '订单名称不能超过50个字符'),
|
|
|
platformId: z.number().int().positive('请选择平台'),
|
|
|
companyId: z.number().int().positive('请选择公司'),
|
|
|
- channelId: z.number().int().positive('请选择渠道'),
|
|
|
- expectedStartDate: z.string().datetime('请选择有效的开始日期'),
|
|
|
- expectedEndDate: z.string().datetime('请选择有效的结束日期').optional(),
|
|
|
+ channelId: z.number().int().positive('请选择渠道').optional(),
|
|
|
+ expectedStartDate: 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, '至少选择一名人员'),
|
|
|
});
|
|
|
|
|
|
@@ -128,18 +115,10 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
orderName: '',
|
|
|
platformId: 0,
|
|
|
companyId: 0,
|
|
|
- channelId: 0,
|
|
|
- expectedStartDate: new Date().toISOString(),
|
|
|
- expectedEndDate: '',
|
|
|
+ channelId: undefined,
|
|
|
+ expectedStartDate: undefined,
|
|
|
orderStatus: OrderStatus.DRAFT,
|
|
|
workStatus: WorkStatus.NOT_WORKING,
|
|
|
- provinceId: undefined,
|
|
|
- cityId: undefined,
|
|
|
- districtId: undefined,
|
|
|
- address: '',
|
|
|
- contactPerson: '',
|
|
|
- contactPhone: '',
|
|
|
- remark: '',
|
|
|
orderPersons: [],
|
|
|
},
|
|
|
});
|
|
|
@@ -153,18 +132,10 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
orderName: orderData.orderName || '',
|
|
|
platformId: orderData.platformId || 0,
|
|
|
companyId: orderData.companyId || 0,
|
|
|
- channelId: orderData.channelId || 0,
|
|
|
- expectedStartDate: orderData.expectedStartDate || new Date().toISOString(),
|
|
|
- expectedEndDate: orderData.expectedEndDate || '',
|
|
|
+ channelId: orderData.channelId || undefined,
|
|
|
+ expectedStartDate: orderData.expectedStartDate || undefined,
|
|
|
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: [],
|
|
|
});
|
|
|
// 编辑模式下清空已选择的人员
|
|
|
@@ -174,18 +145,10 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
orderName: '',
|
|
|
platformId: 0,
|
|
|
companyId: 0,
|
|
|
- channelId: 0,
|
|
|
- expectedStartDate: new Date().toISOString(),
|
|
|
- expectedEndDate: '',
|
|
|
+ channelId: undefined,
|
|
|
+ expectedStartDate: undefined,
|
|
|
orderStatus: OrderStatus.DRAFT,
|
|
|
workStatus: WorkStatus.NOT_WORKING,
|
|
|
- provinceId: undefined,
|
|
|
- cityId: undefined,
|
|
|
- districtId: undefined,
|
|
|
- address: '',
|
|
|
- contactPerson: '',
|
|
|
- contactPhone: '',
|
|
|
- remark: '',
|
|
|
orderPersons: [],
|
|
|
});
|
|
|
// 创建模式下清空已选择的人员
|
|
|
@@ -193,9 +156,9 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
}
|
|
|
}, [order, open, form]);
|
|
|
|
|
|
- // 创建订单Mutation
|
|
|
+ // 创建订单Mutation - 只接受订单基本信息,不包含orderPersons
|
|
|
const createMutation = useMutation({
|
|
|
- mutationFn: async (data: OrderFormValues) => {
|
|
|
+ mutationFn: async (data: Omit<OrderFormValues, 'orderPersons'>) => {
|
|
|
const response = await orderClientManager.get().create.$post({
|
|
|
json: data,
|
|
|
});
|
|
|
@@ -255,18 +218,8 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
// 提取订单基本信息(不包含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('订单创建成功');
|
|
|
+ // 使用createMutation创建订单
|
|
|
+ const createdOrder = await createMutation.mutateAsync(orderData);
|
|
|
|
|
|
// 如果有人员信息,批量添加人员
|
|
|
if (orderPersons && orderPersons.length > 0) {
|
|
|
@@ -288,10 +241,8 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 刷新订单列表
|
|
|
- queryClient.invalidateQueries({ queryKey: ['orders'] });
|
|
|
- onOpenChange(false);
|
|
|
- form.reset();
|
|
|
+ // createMutation的onSuccess已经处理了刷新列表和重置表单
|
|
|
+ // 这里只需要调用onSuccess回调
|
|
|
onSuccess?.();
|
|
|
}
|
|
|
} catch (error) {
|
|
|
@@ -301,12 +252,12 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- // 处理区域选择变化
|
|
|
- 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 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[]) => {
|
|
|
@@ -322,11 +273,9 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
const newFormPersons = newPersons.map(person => ({
|
|
|
personId: person.id,
|
|
|
joinDate: new Date().toISOString(), // 默认当前时间
|
|
|
- salaryDetail: '待定', // 默认值
|
|
|
+ salaryDetail: 0, // 默认值,需要用户填写
|
|
|
leaveDate: undefined,
|
|
|
workStatus: WorkStatus.WORKING,
|
|
|
- role: '',
|
|
|
- remark: ''
|
|
|
}));
|
|
|
form.setValue('orderPersons', [...currentPersons, ...newFormPersons]);
|
|
|
} else {
|
|
|
@@ -342,11 +291,9 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
{
|
|
|
personId: person.id,
|
|
|
joinDate: new Date().toISOString(), // 默认当前时间
|
|
|
- salaryDetail: '待定', // 默认值
|
|
|
+ salaryDetail: 0, // 默认值,需要用户填写
|
|
|
leaveDate: undefined,
|
|
|
workStatus: WorkStatus.WORKING,
|
|
|
- role: '',
|
|
|
- remark: ''
|
|
|
}
|
|
|
]);
|
|
|
}
|
|
|
@@ -364,7 +311,7 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
};
|
|
|
|
|
|
// 处理人员详情更新
|
|
|
- const handlePersonDetailChange = (personId: number, field: keyof OrderFormValues['orderPersons'][0], value: string) => {
|
|
|
+ const handlePersonDetailChange = (personId: number, field: keyof OrderFormValues['orderPersons'][0], value: string | number) => {
|
|
|
const currentPersons = form.getValues('orderPersons') || [];
|
|
|
const updatedPersons = currentPersons.map(person =>
|
|
|
person.personId === personId ? { ...person, [field]: value } : person
|
|
|
@@ -487,7 +434,7 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
type="datetime-local"
|
|
|
{...field}
|
|
|
value={field.value ? field.value.slice(0, 16) : ''}
|
|
|
- onChange={(e) => field.onChange(e.target.value + ':00.000Z')}
|
|
|
+ onChange={(e) => field.onChange(e.target.value ? e.target.value + ':00.000Z' : undefined)}
|
|
|
/>
|
|
|
</FormControl>
|
|
|
<FormMessage />
|
|
|
@@ -495,24 +442,6 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
)}
|
|
|
/>
|
|
|
|
|
|
- <FormField
|
|
|
- control={form.control}
|
|
|
- name="expectedEndDate"
|
|
|
- render={({ field }) => (
|
|
|
- <FormItem>
|
|
|
- <FormLabel>预计结束日期</FormLabel>
|
|
|
- <FormControl>
|
|
|
- <Input
|
|
|
- type="datetime-local"
|
|
|
- {...field}
|
|
|
- value={field.value ? field.value.slice(0, 16) : ''}
|
|
|
- onChange={(e) => field.onChange(e.target.value ? e.target.value + ':00.000Z' : '')}
|
|
|
- />
|
|
|
- </FormControl>
|
|
|
- <FormMessage />
|
|
|
- </FormItem>
|
|
|
- )}
|
|
|
- />
|
|
|
|
|
|
<FormField
|
|
|
control={form.control}
|
|
|
@@ -564,95 +493,6 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
)}
|
|
|
/>
|
|
|
|
|
|
- <div className="col-span-2">
|
|
|
- <FormField
|
|
|
- control={form.control}
|
|
|
- name="provinceId"
|
|
|
- render={() => (
|
|
|
- <FormItem>
|
|
|
- <FormLabel>区域选择</FormLabel>
|
|
|
- <FormControl>
|
|
|
- <AreaSelect
|
|
|
- value={{
|
|
|
- provinceId: form.watch('provinceId'),
|
|
|
- cityId: form.watch('cityId'),
|
|
|
- districtId: form.watch('districtId'),
|
|
|
- }}
|
|
|
- onChange={handleAreaChange}
|
|
|
- />
|
|
|
- </FormControl>
|
|
|
- <FormDescription>
|
|
|
- 选择订单相关的省、市、区信息
|
|
|
- </FormDescription>
|
|
|
- <FormMessage />
|
|
|
- </FormItem>
|
|
|
- )}
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <div className="col-span-2">
|
|
|
- <FormField
|
|
|
- control={form.control}
|
|
|
- name="address"
|
|
|
- render={({ field }) => (
|
|
|
- <FormItem>
|
|
|
- <FormLabel>详细地址</FormLabel>
|
|
|
- <FormControl>
|
|
|
- <Input placeholder="请输入详细地址" {...field} />
|
|
|
- </FormControl>
|
|
|
- <FormMessage />
|
|
|
- </FormItem>
|
|
|
- )}
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <FormField
|
|
|
- control={form.control}
|
|
|
- name="contactPerson"
|
|
|
- render={({ field }) => (
|
|
|
- <FormItem>
|
|
|
- <FormLabel>联系人</FormLabel>
|
|
|
- <FormControl>
|
|
|
- <Input placeholder="请输入联系人" {...field} />
|
|
|
- </FormControl>
|
|
|
- <FormMessage />
|
|
|
- </FormItem>
|
|
|
- )}
|
|
|
- />
|
|
|
-
|
|
|
- <FormField
|
|
|
- control={form.control}
|
|
|
- name="contactPhone"
|
|
|
- render={({ field }) => (
|
|
|
- <FormItem>
|
|
|
- <FormLabel>联系电话</FormLabel>
|
|
|
- <FormControl>
|
|
|
- <Input placeholder="请输入联系电话" {...field} />
|
|
|
- </FormControl>
|
|
|
- <FormMessage />
|
|
|
- </FormItem>
|
|
|
- )}
|
|
|
- />
|
|
|
-
|
|
|
- <div className="col-span-2">
|
|
|
- <FormField
|
|
|
- control={form.control}
|
|
|
- name="remark"
|
|
|
- render={({ field }) => (
|
|
|
- <FormItem>
|
|
|
- <FormLabel>备注</FormLabel>
|
|
|
- <FormControl>
|
|
|
- <Textarea
|
|
|
- placeholder="请输入备注信息"
|
|
|
- className="min-h-[100px]"
|
|
|
- {...field}
|
|
|
- />
|
|
|
- </FormControl>
|
|
|
- <FormMessage />
|
|
|
- </FormItem>
|
|
|
- )}
|
|
|
- />
|
|
|
- </div>
|
|
|
|
|
|
{/* 人员选择区域 - 只在创建订单时显示 */}
|
|
|
{!order?.id && (
|
|
|
@@ -753,7 +593,7 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
</CardDescription>
|
|
|
</CardHeader>
|
|
|
<CardContent className="py-3">
|
|
|
- <div className="grid grid-cols-3 gap-4">
|
|
|
+ <div className="grid grid-cols-4 gap-4">
|
|
|
<div>
|
|
|
<FormLabel className="text-sm">入职日期</FormLabel>
|
|
|
<Input
|
|
|
@@ -764,38 +604,40 @@ export const OrderForm: React.FC<OrderFormProps> = ({
|
|
|
/>
|
|
|
</div>
|
|
|
<div>
|
|
|
- <FormLabel className="text-sm">薪资详情</FormLabel>
|
|
|
- <Input
|
|
|
- placeholder="请输入薪资详情"
|
|
|
- defaultValue="待定"
|
|
|
- onChange={(e) => handlePersonDetailChange(person.id, 'salaryDetail', e.target.value)}
|
|
|
- data-testid={`salary-detail-input-${person.id}`}
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div>
|
|
|
- <FormLabel className="text-sm">工作状态</FormLabel>
|
|
|
+ <FormLabel className="text-sm">离职日期</FormLabel>
|
|
|
<Input
|
|
|
- placeholder="在职"
|
|
|
- defaultValue="在职"
|
|
|
- onChange={(e) => handlePersonDetailChange(person.id, 'workStatus', e.target.value)}
|
|
|
- data-testid={`work-status-input-${person.id}`}
|
|
|
+ type="datetime-local"
|
|
|
+ onChange={(e) => handlePersonDetailChange(person.id, 'leaveDate', e.target.value ? e.target.value + ':00.000Z' : '')}
|
|
|
+ data-testid={`leave-date-input-${person.id}`}
|
|
|
/>
|
|
|
</div>
|
|
|
<div>
|
|
|
- <FormLabel className="text-sm">角色</FormLabel>
|
|
|
+ <FormLabel className="text-sm">薪资详情</FormLabel>
|
|
|
<Input
|
|
|
- placeholder="请输入角色(如:操作员、质检员等)"
|
|
|
- onChange={(e) => handlePersonDetailChange(person.id, 'role', e.target.value)}
|
|
|
- data-testid={`role-input-${person.id}`}
|
|
|
+ type="number"
|
|
|
+ placeholder="请输入薪资"
|
|
|
+ defaultValue="0"
|
|
|
+ onChange={(e) => handlePersonDetailChange(person.id, 'salaryDetail', e.target.value)}
|
|
|
+ data-testid={`salary-detail-input-${person.id}`}
|
|
|
/>
|
|
|
</div>
|
|
|
<div>
|
|
|
- <FormLabel className="text-sm">备注</FormLabel>
|
|
|
- <Input
|
|
|
- placeholder="请输入备注信息"
|
|
|
- onChange={(e) => handlePersonDetailChange(person.id, 'remark', e.target.value)}
|
|
|
- data-testid={`remark-input-${person.id}`}
|
|
|
- />
|
|
|
+ <FormLabel className="text-sm">工作状态</FormLabel>
|
|
|
+ <Select
|
|
|
+ defaultValue={WorkStatus.WORKING}
|
|
|
+ onValueChange={(value) => handlePersonDetailChange(person.id, 'workStatus', value as WorkStatus)}
|
|
|
+ >
|
|
|
+ <SelectTrigger>
|
|
|
+ <SelectValue placeholder="选择工作状态" />
|
|
|
+ </SelectTrigger>
|
|
|
+ <SelectContent>
|
|
|
+ {workStatusOptions.map((option) => (
|
|
|
+ <SelectItem key={option.value} value={option.value}>
|
|
|
+ {option.label}
|
|
|
+ </SelectItem>
|
|
|
+ ))}
|
|
|
+ </SelectContent>
|
|
|
+ </Select>
|
|
|
</div>
|
|
|
</div>
|
|
|
</CardContent>
|