Просмотр исходного кода

修改作业与流程设计器部分内容

pm 5 месяцев назад
Родитель
Сommit
3bc4d50f5e
3 измененных файлов с 400 добавлено и 171 удалено
  1. 44 6
      src/api/WorkJob.ts
  2. 350 161
      src/components/IsolationWork.tsx
  3. 6 4
      src/components/ProcessDesigner.tsx

+ 44 - 6
src/api/WorkJob.ts

@@ -3,13 +3,18 @@ import axiosInstance from '../utils/axios';
 // 作业管理 VO
 export interface WorkJobVO {
   id?: number;
-  code?: string; // 作业编号
+  orderNo?: string; // 作业编号
+  code?: string; // 作业编号(兼容旧字段)
   name?: string; // 作业名称
-  initiator?: string; // 发起人
-  initiateTime?: number | Date; // 发起时间
-  content?: string; // 作业内容
-  currentNode?: string; // 当前节点
-  status?: string | number; // 作业状态
+  initiatorName?: string; // 发起人
+  initiator?: string; // 发起人(兼容旧字段)
+  initiationTime?: number | Date; // 发起时间
+  initiateTime?: number | Date; // 发起时间(兼容旧字段)
+  description?: string; // 作业内容
+  content?: string; // 作业内容(兼容旧字段)
+  currentNodeId?: string; // 当前节点ID
+  currentNode?: string; // 当前节点(兼容旧字段)
+  status?: string | number; // 作业状态: pending-待执行, running-执行中, completed-执行完成, rejected-已退回, skipped-已跳过
   [key: string]: any;
 }
 
@@ -38,6 +43,17 @@ export interface InsertWorkflowWorkParam {
   [key: string]: any;
 }
 
+// 更新作业参数
+export interface UpdateWorkflowWorkParam {
+  id: number; // 作业ID(必填)
+  name: string; // 作业名称
+  type: string; // 作业分类
+  designId: number; // 流程设计ID
+  description: string; // 作业内容/描述
+  urgencyLevel?: string; // 紧急程度
+  [key: string]: any;
+}
+
 // 分页参数类型
 export interface PageParam {
   pageNo?: number;
@@ -85,4 +101,26 @@ export const workJobApi = {
   insertWorkflowWork: (data: InsertWorkflowWorkParam) => {
     return axiosInstance.post('/iscs/workflow-work/insertWorkflowWork', data);
   },
+  
+  // 更新作业(更新流程作业)
+  updateWorkflowWork: (data: UpdateWorkflowWorkParam) => {
+    return axiosInstance.put('/iscs/workflow-work/updateWorkflowWork', data);
+  },
+  
+  // 查询作业列表(分页)
+  getWorkflowWorkPage: (params?: PageParam) => {
+    return axiosInstance.get<PageResponse<WorkJobVO>>('/iscs/workflow-work/getWorkflowWorkPage', { params });
+  },
+  
+  // 查询作业详情
+  selectWorkflowWorkById: (id: number) => {
+    return axiosInstance.get<WorkJobVO>(`/iscs/workflow-work/selectWorkflowWorkById?id=${id}`);
+  },
+  
+  // 删除作业列表
+  deleteWorkflowWorkList: (ids: number[]) => {
+    // 将数组转换为逗号分隔的字符串作为URL参数
+    const idsStr = ids.join(',');
+    return axiosInstance.delete(`/iscs/workflow-work/deleteWorkflowWorkList?ids=${idsStr}`);
+  },
 };

+ 350 - 161
src/components/IsolationWork.tsx

@@ -307,6 +307,7 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
   const [workJobBasicForm] = Form.useForm(); // 基本信息表单
   const [workJobPublishForm] = Form.useForm(); // 发布作业表单
   const [workflowJson, setWorkflowJson] = useState<any>(null); // 流程设计JSON
+  const [workflowWorkId, setWorkflowWorkId] = useState<number | null>(null); // 作业票ID(新增后返回)
   
   // ReactFlow相关状态(用于流程管理tab)
   const [workflowNodes, setWorkflowNodes, onWorkflowNodesChange] = useNodesState([]);
@@ -592,7 +593,6 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
   // 流程设计搜索参数
   const [processDesignQuery, setProcessDesignQuery] = useState({
     name: '',
-    status: undefined as string | undefined,
   });
   const [processDesignPagination, setProcessDesignPagination] = useState({
     pageNo: 1,
@@ -609,70 +609,6 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
     pageSize: 10,
   });
 
-  // 作业管理模拟数据
-  const workJobMockData: WorkJobVO[] = [
-    {
-      id: 1,
-      code: 'WORK-2024-001',
-      name: '2024年1月设备检修作业',
-      initiator: '张三',
-      initiateTime: new Date('2024-01-15 10:30:00').getTime(),
-      content: '对1号生产线进行定期检修,包括设备清洁、润滑、检查等',
-      currentNode: '审核/确认',
-      status: '进行中',
-    },
-    {
-      id: 2,
-      code: 'WORK-2024-002',
-      name: '安全隔离作业',
-      initiator: '李四',
-      initiateTime: new Date('2024-01-14 14:20:00').getTime(),
-      content: '对2号设备进行安全隔离,执行上锁挂牌操作',
-      currentNode: '隔离/方案',
-      status: '进行中',
-    },
-    {
-      id: 3,
-      code: 'WORK-2024-003',
-      name: '设备维护作业',
-      initiator: '王五',
-      initiateTime: new Date('2024-01-13 09:15:00').getTime(),
-      content: '对3号设备进行日常维护保养',
-      currentNode: '完成/结束',
-      status: '已完成',
-    },
-    {
-      id: 4,
-      code: 'WORK-2024-004',
-      name: '紧急维修作业',
-      initiator: '赵六',
-      initiateTime: new Date('2024-01-12 16:45:00').getTime(),
-      content: '对故障设备进行紧急维修',
-      currentNode: '提交/开始',
-      status: '待开始',
-    },
-    {
-      id: 5,
-      code: 'WORK-2024-005',
-      name: '年度大修作业',
-      initiator: '钱七',
-      initiateTime: new Date('2024-01-11 11:20:00').getTime(),
-      content: '对主要生产设备进行年度大修,包括全面检查、更换易损件等',
-      currentNode: '-',
-      status: '已完成',
-    },
-    {
-      id: 6,
-      code: 'WORK-2024-006',
-      name: '设备调试作业',
-      initiator: '孙八',
-      initiateTime: new Date('2024-01-10 08:30:00').getTime(),
-      content: '对新安装设备进行调试和测试',
-      currentNode: '-',
-      status: '已取消',
-    },
-  ];
-
   // 作业管理数据(旧数据,保留用于兼容)
   const workData: TableRow[] = [
     { 
@@ -863,7 +799,6 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
   const resetProcessDesignQuery = () => {
     setProcessDesignQuery({
       name: '',
-      status: undefined,
     });
     setProcessDesignPagination({ pageNo: 1, pageSize: 10 });
     // 立即调用接口刷新数据
@@ -877,7 +812,7 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
       // 重置分页到第一页
       setProcessDesignPagination({ pageNo: 1, pageSize: 10 });
       // 重置查询条件
-      setProcessDesignQuery({ name: '', status: undefined });
+      setProcessDesignQuery({ name: '' });
       // 加载数据
       getProcessDesignList();
     } else if (subMenu === '作业管理') {
@@ -909,7 +844,7 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
   const getWorkJobList = async () => {
     setWorkJobLoading(true);
     try {
-      const response = await workJobApi.getWorkJobPage({
+      const response = await workJobApi.getWorkflowWorkPage({
         pageNo: workJobPagination.pageNo,
         pageSize: workJobPagination.pageSize,
         name: workJobQuery.name || undefined,
@@ -918,28 +853,10 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
       setWorkJobList(response.list || []);
       setWorkJobTotal(response.total || 0);
     } catch (error: any) {
-      console.error('获取作业列表失败,使用模拟数据:', error);
-      // API 调用失败时使用模拟数据
-      let filteredData = workJobMockData;
-      
-      // 如果有搜索条件,进行过滤
-      if (workJobQuery.name) {
-        filteredData = filteredData.filter(item =>
-          item.name?.toLowerCase().includes(workJobQuery.name.toLowerCase())
-        );
-      }
-      if (workJobQuery.status) {
-        filteredData = filteredData.filter(item => item.status === workJobQuery.status);
-      }
-      
-      // 分页处理
-      const startIndex = (workJobPagination.pageNo - 1) * workJobPagination.pageSize;
-      const endIndex = startIndex + workJobPagination.pageSize;
-      const pageData = filteredData.slice(startIndex, endIndex);
-      
-      setWorkJobList(pageData);
-      setWorkJobTotal(filteredData.length);
-      // 不显示错误提示,静默使用模拟数据
+      console.error('获取作业列表失败:', error);
+      message.error(error?.message || '获取作业列表失败');
+      setWorkJobList([]);
+      setWorkJobTotal(0);
     } finally {
       setWorkJobLoading(false);
     }
@@ -1359,7 +1276,7 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
       cancelText: '取消',
       onOk: async () => {
         try {
-          await workJobApi.deleteWorkJobList([id]);
+          await workJobApi.deleteWorkflowWorkList([id]);
           message.success('删除成功');
           // 删除成功后刷新列表
           if (workJobList.length === 1 && workJobPagination.pageNo > 1) {
@@ -1376,19 +1293,238 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
   };
 
   // 作业管理编辑处理
-  const handleWorkJobEdit = (item: WorkJobVO) => {
-    setEditingItem(item as TableRow);
-    form.setFieldsValue({
-      name: item.name || '',
-      content: item.content || '',
-    });
-    setShowAddModal(true);
+  const handleWorkJobEdit = async (item: WorkJobVO) => {
+    try {
+      // 调用详情接口获取完整数据
+      const response = await workJobApi.selectWorkflowWorkById(item.id!);
+      // axios拦截器可能已经处理了数据格式,直接使用response
+      const detail = response as any;
+      
+      // 设置作业ID,这样点击"下一步"时会调用更新接口
+      setWorkflowWorkId(detail.id);
+      
+      // 重置表单和步骤
+      setWorkJobStep(0);
+      workJobBasicForm.resetFields();
+      workJobPublishForm.resetFields();
+      
+      // 加载字典数据和流程模板列表
+      await Promise.all([
+        getWorkTypeDictList(),
+        getUrgencyLevelDictList(),
+        getWorkflowTemplateList(),
+      ]);
+      
+      // 回显基本信息表单数据
+      workJobBasicForm.setFieldsValue({
+        workflowTemplate: detail.designId || undefined,
+        jobCategory: detail.type || undefined,
+        jobName: detail.name || '',
+        jobContent: detail.description || '',
+        urgency: detail.urgencyLevel || undefined,
+      });
+      
+      // 如果有流程设计内容,加载流程设计JSON
+      // 优先使用 designContent(如果存在),否则使用 designId 调用接口
+      if (detail.designContent) {
+        try {
+          // 如果详情中直接包含流程设计内容,直接解析并设置
+          const jsonData = typeof detail.designContent === 'string' 
+            ? JSON.parse(detail.designContent) 
+            : detail.designContent;
+          setWorkflowJson(jsonData);
+          
+          // 调用 loadWorkflowJson 的逻辑来渲染节点和连线
+          // 这里直接使用已有的 loadWorkflowJson 函数,但需要先设置 workflowJson
+          // 然后手动触发渲染逻辑
+          if (jsonData && jsonData.nodes && Array.isArray(jsonData.nodes) && jsonData.edges && Array.isArray(jsonData.edges)) {
+            // 使用 loadWorkflowJson 中的渲染逻辑
+            const importedNodes: Node[] = jsonData.nodes.map((node: any) => {
+              const nodeData = node.data || {};
+              const nodeId = node.id || node.uuid;
+              
+              return {
+                id: nodeId,
+                type: node.type || 'createJob',
+                position: node.position || { x: 0, y: 0 },
+                data: {
+                  ...nodeData,
+                  label: nodeData.label || node.label || nodeConfigs.find(c => c.type === (node.type || nodeData.type))?.label || '节点',
+                  type: node.type || nodeData.type || 'createJob',
+                },
+              };
+            });
+            
+            const importedEdges: Edge[] = jsonData.edges.map((edge: any) => {
+              let sourceHandle = edge.sourceHandle;
+              let targetHandle = edge.targetHandle;
+              
+              if (!sourceHandle && edge.id) {
+                const sourceMatch = edge.id.match(/right-source|left-source|top-source|bottom-source/);
+                if (sourceMatch) {
+                  sourceHandle = sourceMatch[0].replace('-source', '');
+                } else {
+                  sourceHandle = 'right-source';
+                }
+              } else if (!sourceHandle) {
+                sourceHandle = 'right-source';
+              }
+              
+              if (!targetHandle && edge.id) {
+                const targetMatch = edge.id.match(/right-target|left-target|top-target|bottom-target/);
+                if (targetMatch) {
+                  targetHandle = targetMatch[0].replace('-target', '');
+                } else {
+                  targetHandle = 'left-target';
+                }
+              } else if (!targetHandle) {
+                targetHandle = 'left-target';
+              }
+              
+              return {
+                id: edge.id || `${edge.source}-${edge.target}`,
+                source: edge.source,
+                target: edge.target,
+                sourceHandle: sourceHandle,
+                targetHandle: targetHandle,
+                type: 'straight',
+                style: { strokeWidth: 2, stroke: '#94a3b8' },
+              };
+            });
+            
+            setWorkflowNodes(importedNodes);
+            setWorkflowEdges(importedEdges);
+            
+            // 清空之前的缓存和完成状态
+            setWorkflowNodeConfigCache(new Map());
+            setCompletedNodeIds(new Set());
+            
+            // 自动选中第一个节点
+            if (importedNodes.length > 0) {
+              setTimeout(() => {
+                const firstNode = importedNodes[0];
+                setSelectedWorkflowNode(firstNode);
+                const source = firstNode.data || {};
+                const config = nodeConfigs.find(c => c.type === source.type);
+                setWorkflowNodeConfig({
+                  nodeName: source.label || config?.label || '',
+                  nodeIcon: source.icon || '',
+                  responsible: source.responsible || '',
+                  remark: source.remark || '',
+                  submitForm: source.submitForm || '',
+                  isolationMethod: source.isolationMethod || '',
+                  isolationPoints: source.isolationPoints || [],
+                  isolationNode: source.isolationNode || [],
+                  selectedIsolationNodeId: source.selectedIsolationNodeId || '',
+                  lockPerson: source.lockPerson || '',
+                  coLockPersons: source.coLockPersons || [],
+                  notificationMethods: source.notificationMethods || {
+                    sms: false,
+                    message: false,
+                    email: false,
+                    app: false,
+                  },
+                  notificationContent: source.notificationContent || '',
+                });
+                setWorkflowNodes(prev => prev.map(n => ({
+                  ...n,
+                  selected: n.id === firstNode.id,
+                })));
+              }, 100);
+            }
+          }
+        } catch (error: any) {
+          console.error('解析流程设计内容失败:', error);
+          // 如果解析失败,尝试使用 designId 调用接口
+          if (detail.designId) {
+            try {
+              await loadWorkflowJson(detail.designId);
+            } catch (loadError: any) {
+              console.error('加载流程设计失败:', loadError);
+            }
+          }
+        }
+      } else if (detail.designId) {
+        try {
+          await loadWorkflowJson(detail.designId);
+        } catch (error: any) {
+          console.error('加载流程设计失败:', error);
+          // 不阻止弹框打开,只是不加载流程设计
+        }
+      }
+      
+      // 打开多步骤弹框
+      setShowAddModal(true);
+      setEditingItem(null); // 确保不是编辑模式(使用新增的多步骤弹框)
+    } catch (error: any) {
+      console.error('获取作业详情失败:', error);
+      message.error(error?.message || '获取作业详情失败');
+    }
   };
 
   // 作业管理查看处理
-  const handleWorkJobView = (item: WorkJobVO) => {
-    // TODO: 实现查看详情功能
-    message.info('查看功能待实现');
+  const handleWorkJobView = async (item: WorkJobVO) => {
+    try {
+      // 调用详情接口获取完整数据
+      const response = await workJobApi.selectWorkflowWorkById(item.id!);
+      // axios拦截器可能已经处理了数据格式,直接使用response
+      const detail = response as any;
+      Modal.info({
+        title: '作业详情',
+        width: 600,
+        content: (
+          <div className="space-y-3 mt-4">
+            <div>
+              <span className="text-gray-600">作业名称:</span>
+              <span className="font-medium">{detail.name || '-'}</span>
+            </div>
+            <div>
+              <span className="text-gray-600">作业编号:</span>
+              <span className="font-medium">{detail.orderNo || detail.code || '-'}</span>
+            </div>
+            <div>
+              <span className="text-gray-600">发起人:</span>
+              <span className="font-medium">{detail.initiatorName || detail.initiator || '-'}</span>
+            </div>
+            <div>
+              <span className="text-gray-600">发起时间:</span>
+              <span className="font-medium">
+                {(detail.initiationTime || detail.initiateTime)
+                  ? new Date(detail.initiationTime || detail.initiateTime).toLocaleString('zh-CN')
+                  : '-'}
+              </span>
+            </div>
+            <div>
+              <span className="text-gray-600">作业内容:</span>
+              <div className="mt-1">{detail.description || detail.content || '-'}</div>
+            </div>
+            <div>
+              <span className="text-gray-600">当前节点:</span>
+              <span className="font-medium">{detail.currentNodeId || detail.currentNode || '-'}</span>
+            </div>
+            <div>
+              <span className="text-gray-600">作业状态:</span>
+              <span className="font-medium">
+                {(() => {
+                  const statusMap: Record<string, string> = {
+                    'pending': '待执行',
+                    'running': '执行中',
+                    'completed': '执行完成',
+                    'rejected': '已退回',
+                    'skipped': '已跳过',
+                  };
+                  const statusStr = String(detail.status || '').toLowerCase();
+                  return statusMap[statusStr] || detail.status || '-';
+                })()}
+              </span>
+            </div>
+          </div>
+        ),
+      });
+    } catch (error: any) {
+      console.error('获取作业详情失败:', error);
+      message.error(error?.message || '获取作业详情失败');
+    }
   };
 
   // 根据当前子菜单获取数据和列配置
@@ -1424,9 +1560,6 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
           item.name.toLowerCase().includes(processDesignQuery.name.toLowerCase())
         );
       }
-      if (processDesignQuery.status) {
-        filtered = filtered.filter(item => item.status === processDesignQuery.status);
-      }
       return {
         data: filtered,
         columns: [
@@ -2012,6 +2145,12 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
 
   // 作业管理表格列配置
   const workJobColumns: ColumnsType<WorkJobVO> = [
+    {
+      title: '作业编号',
+      dataIndex: 'orderNo',
+      width: '12%',
+      render: (orderNo: string, record: WorkJobVO) => orderNo || record.code || '-',
+    },
     {
       title: '作业名称',
       dataIndex: 'name',
@@ -2019,22 +2158,24 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
     },
     {
       title: '发起人',
-      dataIndex: 'initiator',
+      dataIndex: 'initiatorName',
       width: '10%',
+      render: (initiatorName: string, record: WorkJobVO) => initiatorName || record.initiator || '-',
     },
     {
       title: '发起时间',
-      dataIndex: 'initiateTime',
+      dataIndex: 'initiationTime',
       width: '16%',
-      render: (time: string | Date | number) => {
-        if (!time) return '-';
+      render: (time: string | Date | number, record: WorkJobVO) => {
+        const actualTime = time || record.initiateTime;
+        if (!actualTime) return '-';
         let date: Date;
-        if (typeof time === 'number') {
-          date = new Date(time);
-        } else if (typeof time === 'string') {
-          date = new Date(time);
+        if (typeof actualTime === 'number') {
+          date = new Date(actualTime);
+        } else if (typeof actualTime === 'string') {
+          date = new Date(actualTime);
         } else {
-          date = time;
+          date = actualTime;
         }
         return date.toLocaleString('zh-CN', {
           year: 'numeric',
@@ -2048,33 +2189,37 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
     },
     {
       title: '作业内容',
-      dataIndex: 'content',
+      dataIndex: 'description',
       width: '26%',
       ellipsis: true,
-      render: (content: string) => content || '-',
+      render: (description: string, record: WorkJobVO) => description || record.content || '-',
     },
     {
       title: '当前节点',
-      dataIndex: 'currentNode',
+      dataIndex: 'currentNodeId',
       width: '12%',
-      render: (node: string) => node || '-',
+      render: (currentNodeId: string, record: WorkJobVO) => currentNodeId || record.currentNode || '-',
     },
     {
       title: '作业状态',
       dataIndex: 'status',
       width: '10%',
       render: (status: string | number) => {
-        const statusMap: Record<string | number, { text: string; className: string }> = {
+        // 状态转义映射
+        const statusMap: Record<string, { text: string; className: string }> = {
+          'pending': { text: '待执行', className: 'bg-orange-100 text-orange-700' },
+          'running': { text: '执行中', className: 'bg-blue-100 text-blue-700' },
+          'completed': { text: '执行完成', className: 'bg-green-100 text-green-700' },
+          'rejected': { text: '已退回', className: 'bg-red-100 text-red-700' },
+          'skipped': { text: '已跳过', className: 'bg-gray-100 text-gray-700' },
+          // 兼容旧的状态值
           '进行中': { text: '进行中', className: 'bg-blue-100 text-blue-700' },
           '已完成': { text: '已完成', className: 'bg-green-100 text-green-700' },
           '待开始': { text: '待开始', className: 'bg-orange-100 text-orange-700' },
           '已取消': { text: '已取消', className: 'bg-gray-100 text-gray-700' },
-          1: { text: '进行中', className: 'bg-blue-100 text-blue-700' },
-          2: { text: '已完成', className: 'bg-green-100 text-green-700' },
-          3: { text: '待开始', className: 'bg-orange-100 text-orange-700' },
-          4: { text: '已取消', className: 'bg-gray-100 text-gray-700' },
         };
-        const statusInfo = statusMap[status] || { text: String(status), className: 'bg-gray-100 text-gray-700' };
+        const statusStr = String(status).toLowerCase();
+        const statusInfo = statusMap[statusStr] || { text: String(status), className: 'bg-gray-100 text-gray-700' };
         return (
           <span className={`inline-flex px-3 py-1 rounded-lg text-xs ${statusInfo.className}`}>
             {statusInfo.text}
@@ -2355,17 +2500,6 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
                   />
                 </div>
                 <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
-                  <label className="text-sm font-medium text-gray-700 whitespace-nowrap">状态:</label>
-                  <Select
-                    value={processDesignQuery.status}
-                    onChange={(value) => setProcessDesignQuery({ ...processDesignQuery, status: value })}
-                    placeholder="请选择状态"
-                    className="min-w-[150px] max-w-[200px]"
-                    allowClear
-                  >
-                    <Select.Option value="启用">启用</Select.Option>
-                    <Select.Option value="停用">停用</Select.Option>
-                  </Select>
                 </div>
               </div>
 
@@ -2621,7 +2755,7 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
             <div className="flex flex-wrap items-center justify-between gap-3 lg:gap-4">
               <div className="flex flex-wrap items-center gap-3 lg:gap-4">
                 <div className="flex items-center gap-2">
-                  <label className="text-sm font-medium text-gray-700 whitespace-nowrap">搜索作业名称:</label>
+                  <label className="text-sm font-medium text-gray-700 whitespace-nowrap">作业名称:</label>
                   <Input
                     value={workJobQuery.name}
                     onChange={(e) => setWorkJobQuery({ ...workJobQuery, name: e.target.value })}
@@ -2631,20 +2765,23 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
                     className="min-w-[200px] max-w-[300px]"
                   />
                 </div>
-                <Select
-                  value={workJobQuery.status ?? ''}
-                  onChange={(value) => setWorkJobQuery({ ...workJobQuery, status: value || undefined })}
-                  placeholder="全部状态"
-                  allowClear
-                  className="w-32"
-                  options={[
-                    { label: '全部状态', value: '' },
-                    { label: '进行中', value: '进行中' },
-                    { label: '已完成', value: '已完成' },
-                    { label: '待开始', value: '待开始' },
-                    { label: '已取消', value: '已取消' },
-                  ]}
-                />
+                <div className="flex items-center gap-2">
+                  <label className="text-sm font-medium text-gray-700 whitespace-nowrap">作业状态:</label>
+                  <Select
+                    value={workJobQuery.status ?? ''}
+                    onChange={(value) => setWorkJobQuery({ ...workJobQuery, status: value || undefined })}
+                    placeholder="请选择作业状态"
+                    allowClear
+                    className="w-32"
+                    options={[
+                      { label: '待执行', value: 'pending' },
+                      { label: '执行中', value: 'running' },
+                      { label: '执行完成', value: 'completed' },
+                      { label: '已退回', value: 'rejected' },
+                      { label: '已跳过', value: 'skipped' },
+                    ]}
+                  />
+                </div>
               </div>
               <Space>
                 <Button
@@ -2722,7 +2859,7 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
           </div>
         )}
 
-        {/* 发起作业多步骤弹窗 */}
+        {/* 发起作业多步骤弹窗(新增和编辑共用) */}
         {subMenu === '作业管理' && showAddModal && !editingItem ? (
           <Modal
             title={null}
@@ -2733,6 +2870,13 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
               workJobBasicForm.resetFields();
               workJobPublishForm.resetFields();
               setWorkflowJson(null);
+              setWorkflowWorkId(null); // 清空作业ID
+              // 清空流程管理相关状态
+              setWorkflowNodes([]);
+              setWorkflowEdges([]);
+              setSelectedWorkflowNode(null);
+              setWorkflowNodeConfigCache(new Map());
+              setCompletedNodeIds(new Set());
             }}
             footer={null}
             width={1400}
@@ -3445,6 +3589,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
                       setShowAddModal(false);
                       setWorkJobStep(0);
                       workJobBasicForm.resetFields();
+                      workJobPublishForm.resetFields();
+                      setWorkflowJson(null);
+                      setWorkflowWorkId(null); // 清空作业ID
+                      // 清空流程管理相关状态
+                      setWorkflowNodes([]);
+                      setWorkflowEdges([]);
+                      setSelectedWorkflowNode(null);
+                      setWorkflowNodeConfigCache(new Map());
+                      setCompletedNodeIds(new Set());
                     }}>
                       取消
                     </Button>
@@ -3455,17 +3608,43 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
                           // 验证必填项
                           const values = await workJobBasicForm.validateFields();
                           
-                          // 调用接口创建流程作业
-                          await workJobApi.insertWorkflowWork({
-                            name: values.jobName, // 作业名称
-                            type: values.jobCategory, // 作业分类
-                            designId: values.workflowTemplate, // 流程设计ID
-                            description: values.jobContent, // 作业内容
-                            urgencyLevel: values.urgency, // 紧急程度
-                          });
+                          // 判断是新增还是更新
+                          if (workflowWorkId) {
+                            // 已有ID,调用更新接口
+                            await workJobApi.updateWorkflowWork({
+                              id: workflowWorkId, // 作业票ID
+                              name: values.jobName, // 作业名称
+                              type: values.jobCategory, // 作业分类
+                              designId: values.workflowTemplate, // 流程设计ID
+                              description: values.jobContent, // 作业内容
+                              urgencyLevel: values.urgency, // 紧急程度
+                            });
+                            message.success('基本信息更新成功');
+                          } else {
+                            // 没有ID,调用新增接口
+                            const response = await workJobApi.insertWorkflowWork({
+                              name: values.jobName, // 作业名称
+                              type: values.jobCategory, // 作业分类
+                              designId: values.workflowTemplate, // 流程设计ID
+                              description: values.jobContent, // 作业内容
+                              urgencyLevel: values.urgency, // 紧急程度
+                            });
+                            
+                            // 保存返回的作业ID
+                            // 响应格式: { code: 0, data: 13, msg: "" }
+                            // axios拦截器可能已经处理了数据格式,直接使用response
+                            const responseData = response as any;
+                            // 尝试多种方式获取ID
+                            const workId = responseData?.data || responseData?.id || (typeof responseData === 'number' ? responseData : null);
+                            if (workId) {
+                              setWorkflowWorkId(Number(workId));
+                              console.log('保存作业ID:', workId);
+                            }
+                            
+                            message.success('基本信息保存成功');
+                          }
                           
                           // 成功后进入下一步
-                          message.success('基本信息保存成功');
                           setWorkJobStep(1);
                         } catch (error: any) {
                           if (error.errorFields) {
@@ -3629,6 +3808,13 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
                           workJobBasicForm.resetFields();
                           workJobPublishForm.resetFields();
                           setWorkflowJson(null);
+                          setWorkflowWorkId(null); // 清空作业ID
+                          // 清空流程管理相关状态
+                          setWorkflowNodes([]);
+                          setWorkflowEdges([]);
+                          setSelectedWorkflowNode(null);
+                          setWorkflowNodeConfigCache(new Map());
+                          setCompletedNodeIds(new Set());
                           getWorkJobList();
                         } catch (error: any) {
                           if (error.errorFields) {
@@ -3661,10 +3847,13 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
             onOk={async () => {
               try {
                 const values = await form.validateFields();
-                await workJobApi.updateWorkJob({
+                await workJobApi.updateWorkflowWork({
                   id: editingItem.id!,
                   name: values.name,
-                  content: values.content || '',
+                  type: values.type || editingItem.type || '',
+                  designId: values.designId || editingItem.designId || editingItem.workflowDesignId || 0,
+                  description: values.content || '',
+                  urgencyLevel: values.urgencyLevel || editingItem.urgencyLevel || '',
                 });
                 message.success('更新作业成功');
                 setShowAddModal(false);

+ 6 - 4
src/components/ProcessDesigner.tsx

@@ -1515,8 +1515,9 @@ export default function ProcessDesigner() {
         const targetUuid = nodeIdMap.get(e.target) || e.target;
         if (!adjacency[sourceUuid]) adjacency[sourceUuid] = { parentUuid: [], childrenUuid: [] };
         if (!adjacency[targetUuid]) adjacency[targetUuid] = { parentUuid: [], childrenUuid: [] };
-        adjacency[sourceUuid].childrenUuid.push(targetUuid);
-        adjacency[targetUuid].parentUuid.push(sourceUuid);
+        // 调换字段:原来childrenUuid的地方现在用parentUuid,原来parentUuid的地方现在用childrenUuid
+        adjacency[sourceUuid].parentUuid.push(targetUuid);
+        adjacency[targetUuid].childrenUuid.push(sourceUuid);
       });
 
       const exportData = {
@@ -1621,8 +1622,9 @@ export default function ProcessDesigner() {
       const targetUuid = nodeIdMap.get(e.target) || e.target;
       if (!adjacency[sourceUuid]) adjacency[sourceUuid] = { parentUuid: [], childrenUuid: [] };
       if (!adjacency[targetUuid]) adjacency[targetUuid] = { parentUuid: [], childrenUuid: [] };
-      adjacency[sourceUuid].childrenUuid.push(targetUuid);
-      adjacency[targetUuid].parentUuid.push(sourceUuid);
+      // 调换字段:原来childrenUuid的地方现在用parentUuid,原来parentUuid的地方现在用childrenUuid
+      adjacency[sourceUuid].parentUuid.push(targetUuid);
+      adjacency[targetUuid].childrenUuid.push(sourceUuid);
     });
 
     const exportData = {