Преглед изворни кода

修复作业管理紧急情况渲染

pm пре 4 месеци
родитељ
комит
6ea10c8e36

BIN
src/assets/finger.png


+ 210 - 78
src/components/IsolationWork.tsx

@@ -1,6 +1,6 @@
 import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';
 import { useNavigate } from 'react-router-dom';
-import { Plus, Search, Edit2, Trash2, MoreVertical, FileText, Eye, Play, CheckCircle, RefreshCw, Workflow } from 'lucide-react';
+import { Plus, Search, Edit2, Trash2, MoreVertical, FileText, Eye, Play, CheckCircle, RefreshCw, Workflow, Hand } from 'lucide-react';
 import { Button, Input, Space, Select, Table as AntdTable, message, Modal, Form, Row, Col, Tabs, Radio, DatePicker, Checkbox, Tooltip } from 'antd';
 import { Button as UIButton } from './ui/button';
 import type { ColumnsType } from 'antd/es/table';
@@ -3127,6 +3127,46 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
     };
   };
 
+  // 获取紧急程度样式
+  const getUrgencyLevelStyle = (urgencyText: string): React.CSSProperties => {
+    if (!urgencyText || urgencyText === '-') {
+      return {
+        backgroundColor: '#e5e5e5',
+        color: '#333333',
+      };
+    }
+    
+    const urgencyTextLower = urgencyText.toLowerCase();
+    
+    // 正常:蓝色 #1677ff
+    if (urgencyTextLower.includes('正常') || urgencyTextLower.includes('normal') || urgencyTextLower.includes('普通')) {
+      return {
+        backgroundColor: '#1677ff',
+        color: '#ffffff',
+      };
+    }
+    // 紧急:橙色 #fa8c16
+    if (urgencyTextLower.includes('紧急') || urgencyTextLower.includes('urgent')) {
+      return {
+        backgroundColor: '#fa8c16',
+        color: '#ffffff',
+      };
+    }
+    // 非常紧急:红色 #ff4d4f
+    if (urgencyTextLower.includes('非常紧急') || urgencyTextLower.includes('very urgent') || urgencyTextLower.includes('特急')) {
+      return {
+        backgroundColor: '#ff4d4f',
+        color: '#ffffff',
+      };
+    }
+    
+    // 如果没有匹配到,默认灰色
+    return {
+      backgroundColor: '#e5e5e5',
+      color: '#333333',
+    };
+  };
+
   // 作业管理表格列配置
   const workJobColumns: ColumnsType<WorkJobVO> = [
     {
@@ -3174,7 +3214,7 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
     {
       title: '作业内容',
       dataIndex: 'description',
-      width: '26%',
+      width: '20%',
       render: (description: string, record: WorkJobVO) => {
         const content = description || record.content || '-';
         if (content === '-') return content;
@@ -3191,10 +3231,10 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
       },
     },
     {
-      title: '当前节点',
-      dataIndex: 'currentNodeId',
+      title: '当前任务',
+      dataIndex: 'currentNodeName',
       width: '12%',
-      render: (currentNodeId: string, record: WorkJobVO) => currentNodeId || record.currentNode || '-',
+      render: (currentNodeName: string, record: WorkJobVO) => currentNodeName || record.currentNode || '-',
     },
     {
       title: '作业状态',
@@ -3213,6 +3253,30 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
         );
       },
     },
+    {
+      title: '紧急程度',
+      dataIndex: 'urgencyLevel',
+      minWidth: '180px',
+      align: 'center',
+      render: (urgencyLevel: string | number | undefined, record: WorkJobVO) => {
+        const urgencyValue = urgencyLevel || record.urgency || record.urgencyLevel;
+        const urgencyItem = urgencyLevelDictList.find(item => String(item.value) === String(urgencyValue));
+        const urgencyText = urgencyItem ? (urgencyItem.label || '') : (urgencyValue ? String(urgencyValue) : '-');
+        
+        if (!urgencyValue || urgencyText === '-') {
+          return <span>-</span>;
+        }
+        
+        return (
+          <span 
+            className="inline-flex px-3 py-1 rounded-lg text-xs"
+            style={getUrgencyLevelStyle(urgencyText)}
+          >
+            {urgencyText}
+          </span>
+        );
+      },
+    },
     {
       title: '操作',
       width: '20%',
@@ -5260,7 +5324,7 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
               </div>
 
               {/* 底部按钮 */}
-              <div className="px-6 py-4 border-t border-gray-200 flex justify-end gap-2">
+              <div className="px-6 py-4 border-t border-gray-200 flex justify-center gap-2">
                 {workJobStep === 0 && (
                   <>
                     <Button onClick={() => {
@@ -5428,65 +5492,112 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
                   </>
                 )}
                 {workJobStep === 1 && (
-                  <div className="flex items-center justify-between w-full">
-                    <div className="flex items-center text-red-600 text-sm">
-                      <span className="mr-1">⚠️</span>
-                      <span>提示:流程中的每一个节点都需要单独配置并保存,方可点击 "下一步"。</span>
-                    </div>
+                  <div className="flex flex-col items-center w-full gap-2">
                     <div className="flex items-center gap-2">
                       <Button onClick={() => setWorkJobStep(0)}>
                         上一步
                       </Button>
                       {!isViewMode && (
                         <>
-                      <Button
-                        type="primary"
-                        disabled={hasUnsavedNodes}
-                        onClick={async () => {
-                        // 调用检查接口,检查是否有未保存的节点
-                        if (!workflowWorkId) {
-                          message.warning('作业ID不存在,无法检查');
-                          return;
-                        }
-                        
-                        try {
-                          const checkResponse = await workJobApi.checkWorkById(workflowWorkId);
-                          const checkData = (checkResponse as any)?.data || checkResponse;
-                          const errorMessages = Array.isArray(checkData) ? checkData : (checkData ? [checkData] : []);
+                      <div className="flex items-center gap-2">
+                        <Button
+                          type="primary"
+                          disabled={hasUnsavedNodes}
+                          className={!hasUnsavedNodes ? 'next-step-button-focus' : ''}
+                          onClick={async () => {
+                          // 调用检查接口,检查是否有未保存的节点
+                          if (!workflowWorkId) {
+                            message.warning('作业ID不存在,无法检查');
+                            return;
+                          }
                           
-                          // 如果返回的错误信息数组为空或null,表示所有节点配置完毕,可以进入下一个tab
-                          if (!errorMessages || errorMessages.length === 0) {
-                            message.success('所有节点配置已完成');
-                            // 进入下一个tab
-                            setWorkJobStep(2);
-                          } else {
-                            // 有错误信息,显示弹框,不能进入下一个tab
-                            Modal.warning({
-                              title: '节点配置未完成',
-                              width: 500,
-                              content: (
-                                <div style={{ marginTop: 16 }}>
-                                  <p style={{ marginBottom: 12, color: '#666' }}>以下节点配置不完整,请检查:</p>
-                                  <ul style={{ margin: 0, paddingLeft: 20 }}>
-                                    {errorMessages.map((msg: string, index: number) => (
-                                      <li key={index} style={{ marginBottom: 8, color: '#ff4d4f' }}>
-                                        {msg}
-                                      </li>
-                                    ))}
-                                  </ul>
-                                </div>
-                              ),
-                              okText: '我知道了',
-                            });
+                          try {
+                            const checkResponse = await workJobApi.checkWorkById(workflowWorkId);
+                            const checkData = (checkResponse as any)?.data || checkResponse;
+                            const errorMessages = Array.isArray(checkData) ? checkData : (checkData ? [checkData] : []);
+                            
+                            // 如果返回的错误信息数组为空或null,表示所有节点配置完毕,可以进入下一个tab
+                            if (!errorMessages || errorMessages.length === 0) {
+                              message.success('所有节点配置已完成');
+                              // 进入下一个tab
+                              setWorkJobStep(2);
+                            } else {
+                              // 有错误信息,显示弹框,不能进入下一个tab
+                              Modal.warning({
+                                title: '节点配置未完成',
+                                width: 500,
+                                content: (
+                                  <div style={{ marginTop: 16 }}>
+                                    <p style={{ marginBottom: 12, color: '#666' }}>以下节点配置不完整,请检查:</p>
+                                    <ul style={{ margin: 0, paddingLeft: 20 }}>
+                                      {errorMessages.map((msg: string, index: number) => (
+                                        <li key={index} style={{ marginBottom: 8, color: '#ff4d4f' }}>
+                                          {msg}
+                                        </li>
+                                      ))}
+                                    </ul>
+                                  </div>
+                                ),
+                                okText: '我知道了',
+                              });
+                            }
+                          } catch (error: any) {
+                            console.error('检查作业失败:', error);
+                            message.error(error?.message || '检查作业失败');
+                          }
+                        }}
+                      >
+                        下一步
+                      </Button>
+                      {!hasUnsavedNodes && (
+                        <img 
+                          src={new URL('../assets/finger.png', import.meta.url).href}
+                          alt="指向下一步"
+                          className="pointer-hint-icon"
+                          style={{
+                            width: '32px',
+                            height: '32px',
+                            animation: 'pointing 1.5s ease-in-out infinite',
+                            display: 'inline-block',
+                            cursor: 'pointer',
+                            marginLeft: '8px',
+                            objectFit: 'contain'
+                          }}
+                        />
+                      )}
+                      <style>{`
+                        @keyframes focusPulse {
+                          0%, 100% {
+                            box-shadow: 0 0 0 0 rgba(22, 119, 255, 0.7);
+                            transform: scale(1);
+                          }
+                          50% {
+                            box-shadow: 0 0 0 10px rgba(22, 119, 255, 0);
+                            transform: scale(1.05);
                           }
-                        } catch (error: any) {
-                          console.error('检查作业失败:', error);
-                          message.error(error?.message || '检查作业失败');
                         }
-                      }}
-                    >
-                      下一步
-                    </Button>
+                        .next-step-button-focus {
+                          animation: focusPulse 2s ease-in-out infinite;
+                        }
+                        @keyframes pointing {
+                          0%, 100% {
+                            transform: translateX(0);
+                          }
+                          25% {
+                            transform: translateX(-4px);
+                          }
+                          50% {
+                            transform: translateX(0);
+                          }
+                          75% {
+                            transform: translateX(4px);
+                          }
+                        }
+                        .pointer-hint-icon {
+                          cursor: pointer;
+                        }
+                      `}</style>
+                    </div>
                     {/* <Button
                       type="default"
                       onClick={async () => {
@@ -5546,6 +5657,10 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
                         </Button>
                       )}
                     </div>
+                    <div className="flex items-center text-red-600" style={{ fontSize: '12px' }}>
+                      <span className="mr-1">⚠️</span>
+                      <span>提示:流程中的每一个节点都需要单独配置并保存,方可点击 "下一步"。</span>
+                    </div>
                   </div>
                 )}
                 {workJobStep === 2 && (
@@ -5674,34 +5789,51 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
               setEditingItem(null);
               form.resetFields();
             }}
-            onOk={async () => {
-              try {
-                const values = await form.validateFields();
-                await workJobApi.updateWorkflowWork({
-                    id: editingItem.id!,
-                    name: values.name,
-                  type: values.type || editingItem.type || '',
-                  designId: values.designId || editingItem.designId || editingItem.workflowDesignId || 0,
-                  description: values.content || '',
-                  urgencyLevel: values.urgencyLevel || editingItem.urgencyLevel || '',
-                  });
-                  message.success('更新作业成功');
+            footer={[
+              <Button key="cancel" onClick={() => {
                 setShowAddModal(false);
                 setEditingItem(null);
                 form.resetFields();
-                getWorkJobList();
-              } catch (error: any) {
-                if (error.errorFields) {
-                  return;
+              }}>
+                取消
+              </Button>,
+              <Button key="submit" type="primary" onClick={async () => {
+                try {
+                  const values = await form.validateFields();
+                  await workJobApi.updateWorkflowWork({
+                      id: editingItem.id!,
+                      name: values.name,
+                    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);
+                  setEditingItem(null);
+                  form.resetFields();
+                  getWorkJobList();
+                } catch (error: any) {
+                  if (error.errorFields) {
+                    return;
+                  }
+                  console.error('更新作业失败:', error);
+                  message.error(error?.message || '更新作业失败');
                 }
-                console.error('更新作业失败:', error);
-                message.error(error?.message || '更新作业失败');
-              }
-            }}
-            okText="确定"
-            cancelText="取消"
+              }}>
+                确定
+              </Button>
+            ]}
             width={600}
             destroyOnClose
+            styles={{
+              footer: {
+                display: 'flex',
+                justifyContent: 'center',
+                alignItems: 'center',
+                padding: '16px 24px'
+              }
+            }}
           >
             <Form
               form={form}

+ 86 - 1
src/components/MyTask.tsx

@@ -200,6 +200,7 @@ export default function MyTask() {
   });
   const [searchKey, setSearchKey] = useState('');
   const [approvalStatusDictList, setApprovalStatusDictList] = useState<any[]>([]);
+  const [urgencyLevelDictList, setUrgencyLevelDictList] = useState<any[]>([]);
   
   // 节点详情弹框相关状态
   const [detailVisible, setDetailVisible] = useState(false);
@@ -246,8 +247,27 @@ export default function MyTask() {
     }
   };
 
+  // 获取紧急程度字典
+  const getUrgencyLevelDictList = async () => {
+    try {
+      const { dictDataApi } = await import('../api/DictData');
+      const response = await dictDataApi.getDictDataPage({
+        pageNo: 1,
+        pageSize: -1,
+        dictType: 'urgency_level',
+      });
+      const data = (response as any)?.data || response;
+      const dictList = data?.list || [];
+      setUrgencyLevelDictList(dictList);
+      console.log('MyTask: 获取紧急程度字典成功', dictList);
+    } catch (error: any) {
+      console.error('获取紧急程度字典失败:', error);
+    }
+  };
+
   useEffect(() => {
     getApprovalStatusDictList();
+    getUrgencyLevelDictList();
   }, []);
   
   /** 查询列表 */
@@ -937,7 +957,8 @@ export default function MyTask() {
         workName: record.name || data?.workName || data?.name,
         orderNo: record.orderNo || data?.orderNo,
         workerUserName: record.workerUserName || data?.workerUserName,
-        initiatorName: record.initiatorName || data?.initiatorName || data?.initiator || record.initiator || '',
+        // 优先使用包含完整信息的字段(可能包含电话号码)
+        initiatorName: data?.initiatorName || record.initiatorName || data?.initiator || record.initiator || '',
         workTime: record.workTime || data?.workTime,
         // 确保 type 字段存在,使用第一层 data.type
         type: data?.type || data?.nodeType || '',
@@ -1434,6 +1455,46 @@ export default function MyTask() {
     };
   };
 
+  // 获取紧急程度样式
+  const getUrgencyLevelStyle = (urgencyText: string): React.CSSProperties => {
+    if (!urgencyText || urgencyText === '-') {
+      return {
+        backgroundColor: '#e5e5e5',
+        color: '#333333',
+      };
+    }
+    
+    const urgencyTextLower = urgencyText.toLowerCase();
+    
+    // 正常:蓝色 #1677ff
+    if (urgencyTextLower.includes('正常') || urgencyTextLower.includes('normal') || urgencyTextLower.includes('普通')) {
+      return {
+        backgroundColor: '#1677ff',
+        color: '#ffffff',
+      };
+    }
+    // 紧急:橙色 #fa8c16
+    if (urgencyTextLower.includes('紧急') || urgencyTextLower.includes('urgent')) {
+      return {
+        backgroundColor: '#fa8c16',
+        color: '#ffffff',
+      };
+    }
+    // 非常紧急:红色 #ff4d4f
+    if (urgencyTextLower.includes('非常紧急') || urgencyTextLower.includes('very urgent') || urgencyTextLower.includes('特急')) {
+      return {
+        backgroundColor: '#ff4d4f',
+        color: '#ffffff',
+      };
+    }
+    
+    // 如果没有匹配到,默认灰色
+    return {
+      backgroundColor: '#e5e5e5',
+      color: '#333333',
+    };
+  };
+
   // 表格列配置
   const columns: ColumnsType<MyTaskVO> = [
     {
@@ -1543,6 +1604,30 @@ export default function MyTask() {
         );
       },
     },
+    {
+      title: '紧急程度',
+      dataIndex: 'urgencyLevel',
+      width: 120,
+      align: 'center',
+      render: (urgencyLevel: string | number | undefined, record: MyTaskVO) => {
+        const urgencyValue = urgencyLevel || record.urgencyLevel;
+        const urgencyItem = urgencyLevelDictList.find(item => String(item.value) === String(urgencyValue));
+        const urgencyText = urgencyItem ? (urgencyItem.label || '') : (urgencyValue ? String(urgencyValue) : '-');
+        
+        if (!urgencyValue || urgencyText === '-') {
+          return <span>-</span>;
+        }
+        
+        return (
+          <span 
+            className="inline-flex px-3 py-1 rounded-lg text-xs"
+            style={getUrgencyLevelStyle(urgencyText)}
+          >
+            {urgencyText}
+          </span>
+        );
+      },
+    },
     {
       title: '操作',
       width: 120,

+ 84 - 0
src/components/TaskManagement.tsx

@@ -200,6 +200,7 @@ export default function TaskManagement() {
   });
   const [searchKey, setSearchKey] = useState('');
   const [approvalStatusDictList, setApprovalStatusDictList] = useState<any[]>([]);
+  const [urgencyLevelDictList, setUrgencyLevelDictList] = useState<any[]>([]);
   
   // 节点详情弹框相关状态
   const [detailVisible, setDetailVisible] = useState(false);
@@ -246,8 +247,27 @@ export default function TaskManagement() {
     }
   };
 
+  // 获取紧急程度字典
+  const getUrgencyLevelDictList = async () => {
+    try {
+      const { dictDataApi } = await import('../api/DictData');
+      const response = await dictDataApi.getDictDataPage({
+        pageNo: 1,
+        pageSize: -1,
+        dictType: 'urgency_level',
+      });
+      const data = (response as any)?.data || response;
+      const dictList = data?.list || [];
+      setUrgencyLevelDictList(dictList);
+      console.log('TaskManagement: 获取紧急程度字典成功', dictList);
+    } catch (error: any) {
+      console.error('获取紧急程度字典失败:', error);
+    }
+  };
+
   useEffect(() => {
     getApprovalStatusDictList();
+    getUrgencyLevelDictList();
   }, []);
   
   /** 查询列表 */
@@ -1434,6 +1454,46 @@ export default function TaskManagement() {
     };
   };
 
+  // 获取紧急程度样式
+  const getUrgencyLevelStyle = (urgencyText: string): React.CSSProperties => {
+    if (!urgencyText || urgencyText === '-') {
+      return {
+        backgroundColor: '#e5e5e5',
+        color: '#333333',
+      };
+    }
+    
+    const urgencyTextLower = urgencyText.toLowerCase();
+    
+    // 正常:蓝色 #1677ff
+    if (urgencyTextLower.includes('正常') || urgencyTextLower.includes('normal') || urgencyTextLower.includes('普通')) {
+      return {
+        backgroundColor: '#1677ff',
+        color: '#ffffff',
+      };
+    }
+    // 紧急:橙色 #fa8c16
+    if (urgencyTextLower.includes('紧急') || urgencyTextLower.includes('urgent')) {
+      return {
+        backgroundColor: '#fa8c16',
+        color: '#ffffff',
+      };
+    }
+    // 非常紧急:红色 #ff4d4f
+    if (urgencyTextLower.includes('非常紧急') || urgencyTextLower.includes('very urgent') || urgencyTextLower.includes('特急')) {
+      return {
+        backgroundColor: '#ff4d4f',
+        color: '#ffffff',
+      };
+    }
+    
+    // 如果没有匹配到,默认灰色
+    return {
+      backgroundColor: '#e5e5e5',
+      color: '#333333',
+    };
+  };
+
   // 表格列配置
   const columns: ColumnsType<MyTaskVO> = [
     {
@@ -1543,6 +1603,30 @@ export default function TaskManagement() {
         );
       },
     },
+    {
+      title: '紧急程度',
+      dataIndex: 'urgencyLevel',
+      width: 120,
+      align: 'center',
+      render: (urgencyLevel: string | number | undefined, record: MyTaskVO) => {
+        const urgencyValue = urgencyLevel || record.urgencyLevel;
+        const urgencyItem = urgencyLevelDictList.find(item => String(item.value) === String(urgencyValue));
+        const urgencyText = urgencyItem ? (urgencyItem.label || '') : (urgencyValue ? String(urgencyValue) : '-');
+        
+        if (!urgencyValue || urgencyText === '-') {
+          return <span>-</span>;
+        }
+        
+        return (
+          <span 
+            className="inline-flex px-3 py-1 rounded-lg text-xs"
+            style={getUrgencyLevelStyle(urgencyText)}
+          >
+            {urgencyText}
+          </span>
+        );
+      },
+    },
     {
       title: '操作',
       width: 120,

+ 136 - 71
src/components/WorkJobDetail.tsx

@@ -21,6 +21,7 @@ import { CheckCircleOutlined, ClockCircleOutlined, SyncOutlined } from '@ant-des
 import { workJobApi, WorkJobVO, WorkflowWorkNodeDO } from '../api/WorkJob';
 import { formatDateWithFormat } from '../utils/formatTime';
 import { dictDataApi, DictDataVO } from '../api/DictData';
+import { userApi } from '../api/user';
 
 interface WorkflowStep {
   id: string;
@@ -38,7 +39,7 @@ interface WorkflowStep {
 interface FlowRecord {
   id: string;
   taskNode: string; // 任务节点
-  executor: string; // 执行
+  executor: string; // 任务负责
   startTime?: string; // 开始时间
   endTime?: string; // 结束时间
   taskStatus: 'completed' | 'in_progress' | 'pending'; // 任务状态
@@ -109,43 +110,6 @@ const getStatusIcon = (status: 'completed' | 'in_progress' | 'pending') => {
   }
 };
 
-// 获取执行人信息
-const getExecutorInfo = (workNode: WorkflowWorkNodeDO, type: string): string => {
-  if (!workNode) return '待处理';
-  
-  let executorName = '';
-  if (workNode.nodeUserList && Array.isArray(workNode.nodeUserList)) {
-    const workerUser = workNode.nodeUserList.find((user: any) => user.type === 'worker' || !user.type);
-    if (workerUser && workerUser.userName) {
-      executorName = workerUser.userName;
-    }
-  }
-  
-  if (!executorName) {
-    if (workNode.workerUserName) {
-      executorName = workNode.workerUserName;
-    } else if (workNode.initiatorName) {
-      executorName = workNode.initiatorName;
-    } else if (workNode.workerUserId) {
-      executorName = String(workNode.workerUserId);
-    } else if (workNode.initiator) {
-      executorName = workNode.initiator;
-    }
-  }
-  
-  if (!executorName) return '待处理';
-  
-  if (type === 'createJob') {
-    return `发起人: ${executorName}`;
-  } else if (type === 'review' || type === 'confirm') {
-    return `审核人: ${executorName}`;
-  } else if (type === 'isolation' || type === 'releaseIsolation' || type === 'returnLock') {
-    return `操作人: ${executorName}`;
-  } else {
-    return `执行人: ${executorName}`;
-  }
-};
-
 // 获取节点状态
 const getNodeStatus = (workNode: WorkflowWorkNodeDO, nodeMap: Map<string, WorkflowWorkNodeDO>): 'completed' | 'in_progress' | 'pending' => {
   if (!workNode) return 'pending';
@@ -1130,6 +1094,9 @@ export default function WorkJobDetail() {
   
   // 展开的分支组(按 parentUuid)
   const [expandedBranchGroups, setExpandedBranchGroups] = useState<Set<string>>(new Set());
+  
+  // 用户ID到用户名的映射
+  const [userNameMap, setUserNameMap] = useState<Map<number | string, string>>(new Map());
 
   // 获取作业状态字典数据
   const getJobStatusDictList = async () => {
@@ -1156,6 +1123,55 @@ export default function WorkJobDetail() {
     }
   }, [jobId]);
 
+  // 批量获取用户信息
+  const loadUserNames = async (userIds: (number | string)[]) => {
+    if (!userIds || userIds.length === 0) return new Map<number | string, string>();
+    
+    const userMap = new Map<number | string, string>();
+    const uniqueUserIds = Array.from(new Set(userIds.filter(id => id && !isNaN(Number(id)))));
+    
+    if (uniqueUserIds.length === 0) return userMap;
+    
+    try {
+      // 逐个查询用户信息(更准确)
+      const userPromises = uniqueUserIds.map(async (userId) => {
+        try {
+          const user = await userApi.getUser(Number(userId));
+          const userData = (user as any)?.data || user;
+          if (userData && userData.nickname) {
+            // 同时存储数字和字符串类型的键,确保能匹配到
+            return { 
+              id: userId, 
+              idNum: Number(userId),
+              idStr: String(userId),
+              nickname: userData.nickname 
+            };
+          }
+        } catch (error: any) {
+          console.error(`获取用户 ${userId} 信息失败:`, error);
+        }
+        return null;
+      });
+      
+      const userResults = await Promise.all(userPromises);
+      userResults.forEach((result) => {
+        if (result) {
+          // 同时存储多种键类型,确保能匹配到
+          userMap.set(result.id, result.nickname);
+          userMap.set(result.idNum, result.nickname);
+          userMap.set(result.idStr, result.nickname);
+        }
+      });
+      
+      console.log('用户映射结果:', Array.from(userMap.entries()));
+      console.log('查询的用户ID列表:', uniqueUserIds);
+    } catch (error: any) {
+      console.error('获取用户信息失败:', error);
+    }
+    
+    return userMap;
+  };
+
   const loadJobDetail = async () => {
     if (!jobId) return;
     try {
@@ -1166,6 +1182,20 @@ export default function WorkJobDetail() {
       setJobDetail(data);
       console.log('作业详情数据:', data);
       
+      // 收集所有的 workerUserId
+      const userIds: (number | string)[] = [];
+      if (data?.workflowWorkNodeDOList && Array.isArray(data.workflowWorkNodeDOList)) {
+        data.workflowWorkNodeDOList.forEach((node: any) => {
+          if (node.workerUserId) {
+            userIds.push(node.workerUserId);
+          }
+        });
+      }
+      
+      // 批量获取用户信息
+      const userMap = await loadUserNames(userIds);
+      setUserNameMap(userMap);
+      
       // 构建流程树
       if (data?.workflowWorkNodeDOList && Array.isArray(data.workflowWorkNodeDOList) && data.workflowWorkNodeDOList.length > 0) {
         console.log('准备构建流程树,节点数量:', data.workflowWorkNodeDOList.length);
@@ -1425,6 +1455,49 @@ export default function WorkJobDetail() {
 
   const workflowSteps = buildWorkflowSteps();
 
+  // 获取任务负责人信息(组件内部函数,可以访问 userNameMap)
+  const getExecutorInfo = (workNode: WorkflowWorkNodeDO, type: string): string => {
+    if (!workNode) return '待处理';
+    
+    let executorName = '';
+    if (workNode.nodeUserList && Array.isArray(workNode.nodeUserList)) {
+      const workerUser = workNode.nodeUserList.find((user: any) => user.type === 'worker' || !user.type);
+      if (workerUser && workerUser.userName) {
+        executorName = workerUser.userName;
+      }
+    }
+    
+    if (!executorName) {
+      if (workNode.workerUserName) {
+        executorName = workNode.workerUserName;
+      } else if (workNode.initiatorName) {
+        executorName = workNode.initiatorName;
+      } else if (workNode.workerUserId) {
+        // 从映射中获取用户名,如果没有则使用ID
+        // 尝试多种键类型匹配
+        const userId = workNode.workerUserId;
+        const userName = userNameMap.get(userId) || 
+                        userNameMap.get(String(userId)) || 
+                        userNameMap.get(Number(userId));
+        executorName = userName || String(userId);
+      } else if (workNode.initiator) {
+        executorName = workNode.initiator;
+      }
+    }
+    
+    if (!executorName) return '待处理';
+    
+    if (type === 'createJob') {
+      return `发起人: ${executorName}`;
+    } else if (type === 'review' || type === 'confirm') {
+      return `审核人: ${executorName}`;
+    } else if (type === 'isolation' || type === 'releaseIsolation' || type === 'returnLock') {
+      return `操作人: ${executorName}`;
+    } else {
+      return `任务负责人: ${executorName}`;
+    }
+  };
+
   // 构建流转记录数据
   const buildFlowRecords = (): FlowRecord[] => {
     if (!jobDetail?.workflowWorkNodeDOList || !Array.isArray(jobDetail.workflowWorkNodeDOList)) {
@@ -1453,8 +1526,19 @@ export default function WorkJobDetail() {
       // 格式化时间
       const startTime = node.createTime ? formatDateWithFormat(node.createTime) : undefined;
       
-      // 获取执行人(如果有)
-      const executor = node.workerUserId || node.initiatorName || '';
+      // 获取任务负责人(如果有)
+      let executor = '';
+      if (node.workerUserId) {
+        // 从映射中获取用户名,如果没有则使用ID
+        // 尝试多种键类型匹配
+        const userId = node.workerUserId;
+        const userName = userNameMap.get(userId) || 
+                        userNameMap.get(String(userId)) || 
+                        userNameMap.get(Number(userId));
+        executor = userName || String(userId);
+      } else if (node.initiatorName) {
+        executor = node.initiatorName;
+      }
 
       // 获取描述信息
       let description = node.approvalOpinion || '';
@@ -1551,7 +1635,7 @@ export default function WorkJobDetail() {
             <div className="w-5 h-5 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0">
               <User className="w-3.5 h-3.5 text-blue-600" />
             </div>
-                <span>{jobDetail?.initiatorName || jobDetail?.initiator || '-'}</span>
+                <span>作业发起人:{jobDetail?.initiatorName || jobDetail?.initiator || '-'}</span>
             <span className="text-gray-300">|</span>
                        <span>
                          {jobDetail?.initiationTime
@@ -1599,12 +1683,12 @@ export default function WorkJobDetail() {
             </div>
           </div>
 
-          {/* 右侧:执行记录 */}
+          {/* 右侧:执行进度 */}
           <div className="bg-white rounded-xl shadow-sm border border-gray-200 flex-1 flex flex-col min-h-0 flex-shrink-0" style={{ marginRight: '20px',maxHeight:'750px' }}>
             <div className="px-6 py-4 border-b border-gray-200 flex items-center justify-between">
               <h2 className="text-lg font-semibold text-blue-600 flex items-center gap-2">
                 <Clock className="w-5 h-5" />
-                执行记录
+                执行进度
               </h2>
             </div>
             <div className="flex-1 overflow-y-auto p-4">
@@ -1614,18 +1698,6 @@ export default function WorkJobDetail() {
                   const isInProgress = record.taskStatus === 'in_progress';
                   const isPending = record.taskStatus === 'pending';
 
-                  // 根据状态获取描述信息
-                  let description = record.executionDescription || '';
-                  if (!description) {
-                    if (isCompleted) {
-                      description = '任务已完成';
-                    } else if (isInProgress) {
-                      description = '任务正在进行中';
-                    } else {
-                      description = '等待开始';
-                    }
-                  }
-
                   return (
                     <div
                       key={record.id}
@@ -1642,22 +1714,15 @@ export default function WorkJobDetail() {
                             {record.taskNode}
                           </div>
 
-                          {/* 执行人信息 */}
-                          <div className="text-sm text-gray-600 mb-2">
-                            {record.executor ? (
-                              <>
-                                {record.taskNode === '作业申请' ? '发起人' : 
-                                 record.taskNode === '审核审批' ? '审核人' : 
-                                 record.taskNode === '上锁操作' || record.taskNode === '共锁操作' ? '操作人' : 
-                                 '执行人'}: {record.executor}
-                              </>
-                            ) : '待处理'}
-                          </div>
-
-                          {/* 描述信息 */}
-                          <div className="text-sm text-gray-500">
-                            {description}
-                          </div>
+                          {/* 任务负责人信息 */}
+                          {record.executor && (
+                            <div className="text-sm text-gray-600 mb-2">
+                              {record.taskNode === '作业申请' ? '发起人' : 
+                               record.taskNode === '审核审批' ? '审核人' : 
+                               record.taskNode === '上锁操作' || record.taskNode === '共锁操作' ? '操作人' : 
+                               '任务负责人'}: {record.executor}
+                            </div>
+                          )}
 
                           {/* 时间信息 */}
                           {record.startTime && (