|
|
@@ -32,8 +32,9 @@ import {
|
|
|
SelectValue,
|
|
|
} from "@d8d/shared-ui-components/components/ui/select";
|
|
|
import { Badge } from "@d8d/shared-ui-components/components/ui/badge";
|
|
|
+import { Input } from "@d8d/shared-ui-components/components/ui/input";
|
|
|
import { toast } from "sonner";
|
|
|
-import { Users, FileText, Calendar, Play, CheckCircle } from "lucide-react";
|
|
|
+import { Users, FileText, Calendar, Play, CheckCircle, X } from "lucide-react";
|
|
|
import {
|
|
|
OrderStatus,
|
|
|
WorkStatus,
|
|
|
@@ -52,6 +53,31 @@ interface OrderDetailModalProps {
|
|
|
onSuccess?: () => void;
|
|
|
}
|
|
|
|
|
|
+interface PendingPerson {
|
|
|
+ personId: number;
|
|
|
+ name: string;
|
|
|
+ gender: string;
|
|
|
+ disabilityType: string;
|
|
|
+ phone: string;
|
|
|
+ salaryDetail: number;
|
|
|
+ province?: string; // 原系统使用字符串
|
|
|
+ city?: string; // 原系统使用字符串
|
|
|
+}
|
|
|
+
|
|
|
+interface OrderPerson {
|
|
|
+ opId: number;
|
|
|
+ orderId: number;
|
|
|
+ personId: number;
|
|
|
+ joinDate?: string;
|
|
|
+ leaveDate?: string;
|
|
|
+ workStatus?: number;
|
|
|
+ salaryDetail?: number;
|
|
|
+ personName?: string;
|
|
|
+ gender?: string;
|
|
|
+ disabilityType?: string;
|
|
|
+ phone?: string;
|
|
|
+}
|
|
|
+
|
|
|
const OrderDetailModal: React.FC<OrderDetailModalProps> = ({
|
|
|
open,
|
|
|
onOpenChange,
|
|
|
@@ -62,7 +88,8 @@ const OrderDetailModal: React.FC<OrderDetailModalProps> = ({
|
|
|
const [isAssetAssociationOpen, setIsAssetAssociationOpen] = useState(false);
|
|
|
const [selectedPersonId, setSelectedPersonId] = useState<number | null>(null);
|
|
|
const [isActionLoading, setIsActionLoading] = useState(false);
|
|
|
- const [orderPersons, setOrderPersons] = useState<any[]>([]);
|
|
|
+ const [orderPersons, setOrderPersons] = useState<OrderPerson[]>([]);
|
|
|
+ const [pendingPersons, setPendingPersons] = useState<PendingPerson[]>([]);
|
|
|
|
|
|
// 查询订单详情
|
|
|
const {
|
|
|
@@ -86,11 +113,23 @@ const OrderDetailModal: React.FC<OrderDetailModalProps> = ({
|
|
|
enabled: open && !!orderId,
|
|
|
});
|
|
|
|
|
|
- // 查询订单人员(简化处理,实际应该从订单详情API获取或单独查询)
|
|
|
+ // 从订单详情中获取人员信息
|
|
|
useEffect(() => {
|
|
|
- // 这里应该调用API查询订单人员,暂时使用空数组
|
|
|
- setOrderPersons([]);
|
|
|
- }, [orderId]);
|
|
|
+ if (order && order.orderPersons) {
|
|
|
+ // 这里需要获取人员详细信息(姓名、性别等)
|
|
|
+ // 暂时使用基本信息
|
|
|
+ const personsWithDetails = order.orderPersons.map(person => ({
|
|
|
+ ...person,
|
|
|
+ personName: `人员${person.personId}`, // 实际应该从API获取姓名
|
|
|
+ gender: '未知', // 实际应该从API获取
|
|
|
+ disabilityType: '未知', // 实际应该从API获取
|
|
|
+ phone: '未知', // 实际应该从API获取
|
|
|
+ }));
|
|
|
+ setOrderPersons(personsWithDetails);
|
|
|
+ } else {
|
|
|
+ setOrderPersons([]);
|
|
|
+ }
|
|
|
+ }, [order]);
|
|
|
|
|
|
// 激活订单
|
|
|
const activateMutation = useMutation({
|
|
|
@@ -165,14 +204,14 @@ const OrderDetailModal: React.FC<OrderDetailModalProps> = ({
|
|
|
|
|
|
// 批量添加人员
|
|
|
const batchAddPersonsMutation = useMutation({
|
|
|
- mutationFn: async (persons: DisabledPersonData[]) => {
|
|
|
+ mutationFn: async (persons: PendingPerson[]) => {
|
|
|
if (!orderId) throw new Error("订单ID不能为空");
|
|
|
|
|
|
const batchData = {
|
|
|
persons: persons.map(person => ({
|
|
|
- personId: person.id,
|
|
|
- joinDate: new Date().toISOString(), // 默认当前时间
|
|
|
- salaryDetail: 0, // 默认薪资为0
|
|
|
+ personId: person.personId,
|
|
|
+ joinDate: new Date().toISOString().split('T')[0], // 当前日期,格式:YYYY-MM-DD
|
|
|
+ salaryDetail: person.salaryDetail,
|
|
|
workStatus: WorkStatus.NOT_WORKING, // 默认未入职
|
|
|
})),
|
|
|
};
|
|
|
@@ -191,6 +230,7 @@ const OrderDetailModal: React.FC<OrderDetailModalProps> = ({
|
|
|
onSuccess: () => {
|
|
|
toast.success("批量添加人员成功");
|
|
|
setIsPersonSelectorOpen(false);
|
|
|
+ setPendingPersons([]); // 清空待添加列表
|
|
|
refetch();
|
|
|
onSuccess?.();
|
|
|
},
|
|
|
@@ -199,16 +239,80 @@ const OrderDetailModal: React.FC<OrderDetailModalProps> = ({
|
|
|
},
|
|
|
});
|
|
|
|
|
|
+ // 模拟薪资查询功能(根据省、市信息查询默认薪资)
|
|
|
+ // 支持字符串(原系统格式)和数字ID两种格式
|
|
|
+ const getSalaryByLocation = (province?: string | number, city?: string | number): number => {
|
|
|
+ // 模拟逻辑:根据地区返回默认薪资
|
|
|
+ // 实际应该调用API查询薪资配置
|
|
|
+
|
|
|
+ // 处理字符串格式(原系统使用汉字)
|
|
|
+ if (typeof province === 'string') {
|
|
|
+ if (province === "北京" || province === "上海" || province === "广州" || province === "深圳") {
|
|
|
+ return 8000;
|
|
|
+ }
|
|
|
+ if (province === "江苏" || province === "浙江" || province === "广东") {
|
|
|
+ return 6000;
|
|
|
+ }
|
|
|
+ return 5000;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理数字ID格式
|
|
|
+ if (typeof province === 'number') {
|
|
|
+ if (province === 1 || province === 2 || province === 3 || province === 4) {
|
|
|
+ return 8000; // 一线城市
|
|
|
+ }
|
|
|
+ if (province === 5 || province === 6 || province === 7) {
|
|
|
+ return 6000; // 二线城市
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 5000; // 默认薪资
|
|
|
+ };
|
|
|
+
|
|
|
// 处理添加人员
|
|
|
const handleAddPersons = () => {
|
|
|
if (!orderId) return;
|
|
|
setIsPersonSelectorOpen(true);
|
|
|
};
|
|
|
|
|
|
- // 处理残疾人选择
|
|
|
+ // 处理残疾人选择 - 将选择的人员添加到待添加列表
|
|
|
const handlePersonSelect = (persons: DisabledPersonData | DisabledPersonData[]) => {
|
|
|
const personsArray = Array.isArray(persons) ? persons : [persons];
|
|
|
- batchAddPersonsMutation.mutate(personsArray);
|
|
|
+
|
|
|
+ // 获取已绑定人员的ID列表
|
|
|
+ const existingPersonIds = orderPersons.map(p => p.personId);
|
|
|
+ // 获取待添加人员的ID列表
|
|
|
+ const pendingPersonIds = pendingPersons.map(p => p.personId);
|
|
|
+
|
|
|
+ const newPendingPersons: PendingPerson[] = [];
|
|
|
+
|
|
|
+ personsArray.forEach(person => {
|
|
|
+ // 检查是否已在订单中或已在待添加列表中
|
|
|
+ if (existingPersonIds.includes(person.id) || pendingPersonIds.includes(person.id)) {
|
|
|
+ toast.warning(`人员 ${person.name} 已存在,跳过添加`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据省、市信息查询默认薪资
|
|
|
+ // 注意:原系统使用字符串存储省市信息
|
|
|
+ const defaultSalary = getSalaryByLocation(person.province, person.city);
|
|
|
+
|
|
|
+ newPendingPersons.push({
|
|
|
+ personId: person.id,
|
|
|
+ name: person.name,
|
|
|
+ gender: person.gender,
|
|
|
+ disabilityType: person.disabilityType,
|
|
|
+ phone: person.phone,
|
|
|
+ salaryDetail: defaultSalary,
|
|
|
+ province: person.province,
|
|
|
+ city: person.city,
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ if (newPendingPersons.length > 0) {
|
|
|
+ setPendingPersons(prev => [...prev, ...newPendingPersons]);
|
|
|
+ toast.success(`已添加 ${newPendingPersons.length} 名人员到待添加列表`);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
// 处理添加资产
|
|
|
@@ -217,6 +321,30 @@ const OrderDetailModal: React.FC<OrderDetailModalProps> = ({
|
|
|
setIsAssetAssociationOpen(true);
|
|
|
};
|
|
|
|
|
|
+ // 更新待添加人员的薪资
|
|
|
+ const updatePendingPersonSalary = (personId: number, salary: number) => {
|
|
|
+ setPendingPersons(prev =>
|
|
|
+ prev.map(person =>
|
|
|
+ person.personId === personId ? { ...person, salaryDetail: salary } : person
|
|
|
+ )
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
+ // 从待添加列表中移除人员
|
|
|
+ const removePendingPerson = (personId: number) => {
|
|
|
+ setPendingPersons(prev => prev.filter(person => person.personId !== personId));
|
|
|
+ };
|
|
|
+
|
|
|
+ // 确认添加待添加人员
|
|
|
+ const handleConfirmAddPersons = () => {
|
|
|
+ if (pendingPersons.length === 0) {
|
|
|
+ toast.warning("没有待添加的人员");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ batchAddPersonsMutation.mutate(pendingPersons);
|
|
|
+ };
|
|
|
+
|
|
|
// 处理激活订单
|
|
|
const handleActivateOrder = () => {
|
|
|
if (!orderId) return;
|
|
|
@@ -280,6 +408,13 @@ const OrderDetailModal: React.FC<OrderDetailModalProps> = ({
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ // 当弹窗关闭时清空待添加人员列表
|
|
|
+ useEffect(() => {
|
|
|
+ if (!open) {
|
|
|
+ setPendingPersons([]);
|
|
|
+ }
|
|
|
+ }, [open]);
|
|
|
+
|
|
|
// 人员列表表格列
|
|
|
const personColumns = [
|
|
|
{ key: "personId", label: "ID", width: "60px" },
|
|
|
@@ -419,6 +554,86 @@ const OrderDetailModal: React.FC<OrderDetailModalProps> = ({
|
|
|
</CardContent>
|
|
|
</Card>
|
|
|
|
|
|
+ {/* 待添加人员列表 */}
|
|
|
+ {pendingPersons.length > 0 && (
|
|
|
+ <Card data-testid="pending-persons-card">
|
|
|
+ <CardHeader>
|
|
|
+ <div className="flex items-center justify-between">
|
|
|
+ <div>
|
|
|
+ <CardTitle>待添加人员列表</CardTitle>
|
|
|
+ <CardDescription>
|
|
|
+ 已选择但尚未添加到订单的人员,可编辑薪资后确认添加
|
|
|
+ </CardDescription>
|
|
|
+ </div>
|
|
|
+ <Button
|
|
|
+ onClick={handleConfirmAddPersons}
|
|
|
+ size="sm"
|
|
|
+ disabled={batchAddPersonsMutation.isPending}
|
|
|
+ data-testid="confirm-add-persons-button"
|
|
|
+ >
|
|
|
+ <CheckCircle className="mr-2 h-4 w-4" />
|
|
|
+ 确认添加 ({pendingPersons.length})
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </CardHeader>
|
|
|
+ <CardContent>
|
|
|
+ <div className="border rounded-md">
|
|
|
+ <Table>
|
|
|
+ <TableHeader>
|
|
|
+ <TableRow>
|
|
|
+ <TableHead style={{ width: "60px" }}>ID</TableHead>
|
|
|
+ <TableHead>姓名</TableHead>
|
|
|
+ <TableHead style={{ width: "80px" }}>性别</TableHead>
|
|
|
+ <TableHead>残疾类型</TableHead>
|
|
|
+ <TableHead>联系电话</TableHead>
|
|
|
+ <TableHead style={{ width: "120px" }}>薪资(可编辑)</TableHead>
|
|
|
+ <TableHead style={{ width: "80px" }}>操作</TableHead>
|
|
|
+ </TableRow>
|
|
|
+ </TableHeader>
|
|
|
+ <TableBody>
|
|
|
+ {pendingPersons.map((person) => (
|
|
|
+ <TableRow
|
|
|
+ key={person.personId}
|
|
|
+ data-testid={`pending-person-${person.personId}`}
|
|
|
+ >
|
|
|
+ <TableCell>{person.personId}</TableCell>
|
|
|
+ <TableCell>{person.name}</TableCell>
|
|
|
+ <TableCell>{person.gender}</TableCell>
|
|
|
+ <TableCell>{person.disabilityType}</TableCell>
|
|
|
+ <TableCell>{person.phone}</TableCell>
|
|
|
+ <TableCell>
|
|
|
+ <Input
|
|
|
+ type="number"
|
|
|
+ value={person.salaryDetail}
|
|
|
+ onChange={(e) =>
|
|
|
+ updatePendingPersonSalary(
|
|
|
+ person.personId,
|
|
|
+ parseInt(e.target.value) || 0
|
|
|
+ )
|
|
|
+ }
|
|
|
+ className="w-full"
|
|
|
+ data-testid={`pending-person-salary-input-${person.personId}`}
|
|
|
+ />
|
|
|
+ </TableCell>
|
|
|
+ <TableCell>
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="sm"
|
|
|
+ onClick={() => removePendingPerson(person.personId)}
|
|
|
+ data-testid={`remove-pending-person-button-${person.personId}`}
|
|
|
+ >
|
|
|
+ <X className="h-4 w-4" />
|
|
|
+ </Button>
|
|
|
+ </TableCell>
|
|
|
+ </TableRow>
|
|
|
+ ))}
|
|
|
+ </TableBody>
|
|
|
+ </Table>
|
|
|
+ </div>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+ )}
|
|
|
+
|
|
|
{/* 绑定人员列表 */}
|
|
|
<Card>
|
|
|
<CardHeader>
|
|
|
@@ -430,7 +645,7 @@ const OrderDetailModal: React.FC<OrderDetailModalProps> = ({
|
|
|
<Button
|
|
|
onClick={handleAddPersons}
|
|
|
size="sm"
|
|
|
- data-testid="order-detail-add-persons-button"
|
|
|
+ data-testid="order-detail-card-add-persons-button"
|
|
|
>
|
|
|
<Users className="mr-2 h-4 w-4" />
|
|
|
添加人员
|