import React, { useState, useEffect, useMemo } from 'react';
import { CheckCircle, Eye, ShoppingCart, HelpCircle, PlayCircle, Clock, AlertCircle, Rocket } from 'lucide-react';
import { LineChart, Line, AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts';
import { Card, Button, Table, Tag, message, Modal, Form as AntdForm, Input, Select, DatePicker, InputNumber, Switch, Radio, Checkbox, Cascader, Upload, Alert, Space, Image } from 'antd';
import { UploadOutlined, LockOutlined, CheckCircleOutlined, BarcodeOutlined, SendOutlined, KeyOutlined } from '@ant-design/icons';
import { executorHomeApi, ExecutorNodeCountVO, ExecutorNodeVO, ExecutorDayCompletedVO } from '../api/executorHome';
import { myTaskApi, MyTaskNodeDetailVO, UpdateNodeApprovalParam } from '../api/mytask';
import { fileApi } from '../api/file';
import { formatDateWithFormat, dateFormatter } from '../utils/formatTime';
import { toast } from 'sonner';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import dayjs, { Dayjs } from 'dayjs';
import { setConfAndFields2, FormCreateData } from '../utils/formCreate';
import FormUploadField from './FormUploadField';
import {
  isWorkflowCoLockType,
  isWorkflowLockSchemeType,
  isWorkflowUnlockCoLockType,
  isWorkflowUnlockSchemeType,
} from '../utils/workflowNodeTypes';
import { dictDataApi, DictDataVO } from '../api/DictData';
// @ts-ignore
import urgecy1Icon from '../assets/urgecy1.png';
// @ts-ignore
import urgecy2Icon from '../assets/urgecy2.png';
// @ts-ignore
import urgecy3Icon from '../assets/urgecy3.png';

// 辅助函数：安全地将值转换为 dayjs 对象
const safeToDayjs = (value: any): dayjs.Dayjs | null => {
  if (!value && value !== 0) {
    return null;
  }
  
  // 如果是数字（时间戳）
  if (typeof value === 'number') {
    let timestamp = value;
    if (timestamp > 0 && timestamp < 10000000000) {
      timestamp = timestamp * 1000;
    }
    const dayjsValue = dayjs(timestamp);
    if (dayjsValue.isValid()) {
      return dayjsValue;
    } else {
      return null;
    }
  }
  
  // 如果是字符串
  if (typeof value === 'string' && value.trim() !== '') {
    const numValue = Number(value);
    if (!isNaN(numValue) && numValue > 0 && numValue.toString() === value.trim()) {
      let timestamp = numValue;
      if (timestamp < 10000000000) {
        timestamp = timestamp * 1000;
      }
      const dayjsValue = dayjs(timestamp);
      if (dayjsValue.isValid()) {
        return dayjsValue;
      } else {
        return null;
      }
    } else {
      const dayjsValue = dayjs(value);
      return dayjsValue.isValid() ? dayjsValue : null;
    }
  }
  
  // 如果已经是 dayjs 对象
  if (value && typeof value === 'object' && typeof value.isValid === 'function') {
    try {
      return value.isValid() ? value : null;
    } catch (e) {
      // isValid 调用失败
    }
  }
  
  // 如果是对象，检查是否有 $d 属性
  if (value && typeof value === 'object') {
    try {
      if (value.$d) {
        const dayjsValue = dayjs(value.$d);
        return dayjsValue.isValid() ? dayjsValue : null;
      }
      if (value.valueOf && typeof value.valueOf === 'function') {
        const timestamp = value.valueOf();
        if (typeof timestamp === 'number') {
          const dayjsValue = dayjs(timestamp);
          return dayjsValue.isValid() ? dayjsValue : null;
        }
      }
    } catch (e) {
      return null;
    }
  }
  
  return null;
};

// 辅助函数：验证 dayjs 对象是否有效
const isValidDayjs = (value: any): boolean => {
  if (!value) return false;
  if (typeof value !== 'object') return false;
  if (typeof value.isValid !== 'function') return false;
  try {
    return value.isValid();
  } catch (e) {
    return false;
  }
};

// 辅助函数：将表单值中的日期字符串转换为 dayjs 对象
const convertDateValues = (formValues: any, fields: any[]): any => {
  const fieldTypeMap: { [key: string]: string } = {};
  
  // 建立字段名到类型的映射
  fields.forEach((field: any) => {
    try {
      const fieldObj = typeof field === 'string' ? JSON.parse(field) : field;
      const fieldName = fieldObj.name || fieldObj.field;
      if (fieldName) {
        fieldTypeMap[fieldName] = fieldObj.type;
      }
    } catch (e) {
      // 解析失败，跳过
    }
  });
  
  // 转换日期值
  const convertedValues: any = {};
  Object.keys(formValues).forEach((fieldName) => {
    const fieldType = fieldTypeMap[fieldName];
    const value = formValues[fieldName];
    
    if (fieldType === 'date' || fieldType === 'datetime' || fieldType === 'timepicker') {
      convertedValues[fieldName] = safeToDayjs(value) || undefined;
    } else if (fieldType === 'daterange') {
      if (Array.isArray(value) && value.length === 2) {
        const [start, end] = value;
        const startDayjs = safeToDayjs(start);
        const endDayjs = safeToDayjs(end);
        
        if (startDayjs && endDayjs) {
          convertedValues[fieldName] = [startDayjs, endDayjs];
        } else {
          convertedValues[fieldName] = undefined;
        }
      } else {
        convertedValues[fieldName] = undefined;
      }
    } else {
      convertedValues[fieldName] = value;
    }
  });
  
  return convertedValues;
};

export default function ExecutorDashboard() {
  const { t } = useTranslation();
  const navigate = useNavigate();
  const [loading, setLoading] = useState(true);
  const [nodeList, setNodeList] = useState<ExecutorNodeVO[]>([]);
  const [nodeCount, setNodeCount] = useState<ExecutorNodeCountVO>({
    unreleasedCount: 0,
    runningCount: 0,
    completedCount: 0,
  });
  const [trendData, setTrendData] = useState<ExecutorDayCompletedVO[]>([]);
  
  // 字典数据状态
  const [workTypeDictList, setWorkTypeDictList] = useState<DictDataVO[]>([]);
  const [urgencyLevelDictList, setUrgencyLevelDictList] = useState<DictDataVO[]>([]);
  
  // 任务详情弹框相关状态
  const [taskDetailVisible, setTaskDetailVisible] = useState(false);
  const [taskDetailLoading, setTaskDetailLoading] = useState(false);
  const [taskDetailData, setTaskDetailData] = useState<MyTaskNodeDetailVO | null>(null);
  const [formData, setFormData] = useState<FormCreateData>({
    rule: [],
    option: {}
  });
  const [formLoading, setFormLoading] = useState(false);
  const [originalFields, setOriginalFields] = useState<string[]>([]);
  const [originalConf, setOriginalConf] = useState<string>('');
  const [taskDetailForm] = AntdForm.useForm();
  const [approvalComment, setApprovalComment] = useState('');
  const [approvalLoading, setApprovalLoading] = useState(false);
  const [submitLoading, setSubmitLoading] = useState(false);
  const [isolationDeviceNumber, setIsolationDeviceNumber] = useState('');
  const [isolationFileList, setIsolationFileList] = useState<any[]>([]);
  const [isolationSubmitLoading, setIsolationSubmitLoading] = useState(false);
  
  // 获取字典数据
  const fetchDictData = async () => {
    try {
      // 并行获取作业类型和紧急程度字典
      const [workTypeRes, urgencyRes] = await Promise.all([
        dictDataApi.getDictDataPage({
          pageNo: 1,
          pageSize: -1,
          dictType: 'work_type',
        }),
        dictDataApi.getDictDataPage({
          pageNo: 1,
          pageSize: -1,
          dictType: 'urgency_level',
        }),
      ]);
      
      // 处理作业类型字典数据
      const workTypeData = (workTypeRes as any)?.data || workTypeRes;
      setWorkTypeDictList(workTypeData?.list || []);
      
      // 处理紧急程度字典数据
      const urgencyData = (urgencyRes as any)?.data || urgencyRes;
      setUrgencyLevelDictList(urgencyData?.list || []);
    } catch (error: any) {
      console.error('获取字典数据失败', error);
      setWorkTypeDictList([]);
      setUrgencyLevelDictList([]);
    }
  };
  
  // 获取所有数据
  const fetchAllData = async () => {
    setLoading(true);
    try {
      // 并行调用三个接口
      const [countData, completedList, nodeListData] = await Promise.all([
        executorHomeApi.getExecutorNodeCount(),
        executorHomeApi.getMyCompletedNodeList(),
        executorHomeApi.getMyNodeList({ pageNo: 1, pageSize: 10 }),
      ]);
      
      // 设置统计数据
      setNodeCount(countData || { unreleasedCount: 0, runningCount: 0, completedCount: 0 });
      
      // 设置趋势数据
      const formattedTrendData = (completedList || []).map(item => ({
        date: item.day ? (item.day.includes('日') ? item.day : `${item.day}日`) : '',
        completedCount: item.completedCount || 0,
      }));
      setTrendData(formattedTrendData);
      
      // 设置节点列表
      setNodeList(nodeListData || []);
    } catch (error: any) {
      console.error('获取数据失败', error);
      toast.error(error.message || t('cockpit.getDataFailed'));
      setNodeCount({ unreleasedCount: 0, runningCount: 0, completedCount: 0 });
      setTrendData([]);
      setNodeList([]);
    } finally {
      setLoading(false);
    }
  };
  
  useEffect(() => {
    fetchDictData();
    fetchAllData();
  }, []);
  
  // 将 ExecutorNodeVO 转换为表格可用的格式
  const transformedNodeList = useMemo(() => {
    return nodeList.map((node) => ({
      ...node,
      // 映射字段以兼容表格显示
      id: (typeof node.id === 'number' ? node.id : undefined) || (typeof node.nodeId === 'number' ? node.nodeId : undefined),
      nodeId: node.nodeId || node.id || node.uuid,
      orderNo: node.orderNo || (node.workId ? String(node.workId) : String(node.id || '')),
      name: node.name || '未知任务',
      currentNodeName: node.currentNodeName || node.nodeName || '',
      currentNodeId: node.currentNodeId || node.nodeId,
      approvalStatus: node.approvalStatus,
      taskStatus: node.approvalStatus,
      status: node.approvalStatus,
      workTime: node.workTime || node.startTime,
      startTime: node.startTime || (node.workTime ? String(node.workTime) : undefined), // 使用 workTime 作为开始时间（转换为字符串）
      workerUserName: node.workerUserName || node.initiatorName || '',
      urgencyLevel: node.urgencyLevel !== undefined && node.urgencyLevel !== null ? node.urgencyLevel : '', // 从接口数据中获取（保留0值）
      workType: node.workType !== undefined && node.workType !== null ? node.workType : '', // 从接口数据中获取（保留0值）
    }));
  }, [nodeList]);
  
  // 解析任务状态类型：pending | inProgress | completed
  const getTaskStatusKind = (status: string | number | undefined): 'pending' | 'inProgress' | 'completed' => {
    if (status === undefined || status === null) return 'pending';
    const statusNum = typeof status === 'number' ? status : parseInt(String(status), 10);
    if (!isNaN(statusNum)) {
      if (statusNum === 1) return 'pending';
      if (statusNum === 2) return 'inProgress';
      if (statusNum === 3) return 'completed';
    }
    const statusStr = String(status).toLowerCase();
    if (statusStr === 'running' || statusStr === '进行中' || statusStr === 'in_progress' || statusStr === '执行中' || statusStr === '2') return 'inProgress';
    if (statusStr === 'completed' || statusStr === '已完成' || statusStr === 'approved' || statusStr === '已通过' || statusStr === '3') return 'completed';
    return 'pending';
  };

  // 获取任务状态文本（根据 approvalStatus 数字值判断）
  const getTaskStatusText = (status: string | number | undefined): string => {
    const kind = getTaskStatusKind(status);
    if (kind === 'inProgress') return t('cockpit.inProgress');
    if (kind === 'completed') return t('cockpit.completed');
    return t('cockpit.pending');
  };
  
  // 获取任务状态样式
  const getTaskStatusStyle = (status: string | number | undefined) => {
    const kind = getTaskStatusKind(status);
    if (kind === 'inProgress') return { backgroundColor: '#1677ff', color: '#ffffff' };
    if (kind === 'completed') return { backgroundColor: '#0acb57', color: '#ffffff' };
    return { backgroundColor: '#e5e5e5', color: '#333333' };
  };
  
  // 获取紧急程度图标和样式（根据字典 value 判断：0=一般，1=紧急，2=非常紧急）
  const getUrgencyLevelIconAndStyle = (urgencyValue: string | number | undefined): { icon: React.ReactNode; style: React.CSSProperties } => {
    if (urgencyValue === null || urgencyValue === undefined || urgencyValue === '') {
      return {
        icon: null,
        style: {
          backgroundColor: '#e5e5e5',
          color: '#333333',
        },
      };
    }
    
    const value = Number(urgencyValue);
    
    // 0 = 一般：使用 urgecy1.png 图标 + 黑色文字
    if (value === 0) {
      return {
        icon: (
          <img 
            src={urgecy1Icon} 
            alt={t('cockpit.priorityNormal')} 
            className="w-5 h-5 flex-shrink-0 mr-1.5"
            style={{ objectFit: 'contain' }}
          />
        ),
        style: {
          backgroundColor: 'transparent',
          color: '#000000',
        },
      };
    }
    
    // 1 = 紧急：使用 urgecy2.png 图标 + 橙色加粗文字
    if (value === 1) {
      return {
        icon: (
          <img 
            src={urgecy2Icon} 
            alt={t('cockpit.priorityUrgent')} 
            className="w-5 h-5 flex-shrink-0 mr-1.5"
            style={{ objectFit: 'contain' }}
          />
        ),
        style: {
          backgroundColor: 'transparent',
          color: '#fa8c16',
          fontWeight: 'bold',
        },
      };
    }
    
    // 2 = 非常紧急：使用 urgecy3.png 图标 + 红色加粗文字
    if (value === 2) {
      return {
        icon: (
          <img 
            src={urgecy3Icon} 
            alt={t('cockpit.priorityVeryUrgent')} 
            className="w-5 h-5 flex-shrink-0 mr-1.5"
            style={{ objectFit: 'contain' }}
          />
        ),
        style: {
          backgroundColor: 'transparent',
          color: '#ff4d4f',
          fontWeight: 'bold',
        },
      };
    }
    
    // 如果没有匹配到，默认灰色
    return {
      icon: null,
      style: {
        backgroundColor: '#e5e5e5',
        color: '#333333',
      },
    };
  };
  
  // 根据字典值获取作业类型文本
  const getWorkTypeText = (workType: string | number | undefined): string => {
    if (!workType && workType !== 0) {
      return '-';
    }
    const workTypeItem = workTypeDictList.find(item => String(item.value) === String(workType));
    return workTypeItem ? (workTypeItem.label || String(workType)) : String(workType);
  };
  
  // 根据字典值获取优先级文本
  const getPriorityText = (urgencyLevel: string | number | undefined): string => {
    if (!urgencyLevel && urgencyLevel !== 0) {
      return '-';
    }
    const urgencyItem = urgencyLevelDictList.find(item => String(item.value) === String(urgencyLevel));
    return urgencyItem ? (urgencyItem.label || String(urgencyLevel)) : String(urgencyLevel);
  };
  
  // 默认表单配置
  const defaultFormConfig = {
    name: '',
    labelPosition: 'right',
    formSize: 'middle',
    labelSuffix: '',
    labelWidth: 100,
    hideRequiredMark: false,
    showValidationError: true,
    inlineValidation: false,
    showSubmitButton: false,
    showResetButton: false,
  };

  // 渲染字段预览（支持嵌套结构）
  const renderFieldPreview = (field: any, parentSpanStyle?: React.CSSProperties): React.ReactNode => {
    const formConfig = formData.option?.formConfig || defaultFormConfig;
    const layoutColumns = formConfig.layoutColumns || 1;
    const spanStyle = parentSpanStyle || (layoutColumns > 1 ? { gridColumn: `span ${Math.min(layoutColumns, field.span || 1)}` } : undefined);

    // 处理容器类型（card 和 grid）
    if (field.type === 'card') {
      const children = field.children || [];
      const cardTitle = field.label || field.cardTitle || t('cockpit.cardContainer');
      return (
        <div key={field.id} style={spanStyle} className="mb-4">
          <Card title={cardTitle} className="w-full">
            <div className="space-y-4">
              {children.map((child: any) => renderFieldPreview(child))}
            </div>
          </Card>
        </div>
      );
    }

    if (field.type === 'grid') {
      const gridColumns = field.gridColumns || 2;
      const children = field.children || [];
      return (
        <div key={field.id} style={spanStyle} className="mb-4">
          <div
            style={{
              display: 'grid',
              gridTemplateColumns: `repeat(${gridColumns}, minmax(0, 1fr))`,
              gap: '16px',
            }}
          >
            {children.map((child: any) => {
              const childSpanStyle = gridColumns > 1 
                ? { gridColumn: `span ${Math.min(gridColumns, child.span || 1)}` } 
                : undefined;
              return (
                <div key={child.id} style={childSpanStyle}>
                  {renderFieldPreview(child)}
                </div>
              );
            })}
          </div>
        </div>
      );
    }

    // 处理 alert 类型
    if (field.type === 'alert') {
      const themeClass =
        field.alertTheme === 'dark'
          ? 'bg-gray-800 text-white border-gray-700'
          : '';
      return (
        <div key={field.id} className="mb-4" style={spanStyle}>
          <Alert
            message={field.alertTitle || field.label}
            description={field.alertDescription}
            type={field.alertType || 'info'}
            showIcon={field.alertShowIcon !== false}
            closable={field.alertClosable}
            closeText={field.alertCloseText}
            className={`${field.alertCentered ? 'text-center' : ''} ${themeClass}`}
            banner
            style={field.style}
          />
          {field.hint && <div className="text-xs text-gray-400 mt-1">{field.hint}</div>}
        </div>
      );
    }

    // 与表单设计器一致：每字段 labelCol/wrapperCol
    const getItemLayout = (f: any) => {
      const isTop = formConfig.labelPosition === 'top';
      const w = f.labelWidth ?? formConfig.labelWidth ?? 100;
      const effective = (typeof w === 'number' && w > 0) ? w : 100;
      return {
        labelCol: isTop ? undefined : { flex: `${effective}px`, style: { minWidth: `${effective}px`, textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left' } },
        wrapperCol: isTop ? undefined : { flex: 'auto', style: { minWidth: 0 } },
      };
    };
    const itemLayout = getItemLayout(field);

    // 处理普通字段
    switch (field.type) {
      case 'textarea':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
            >
              <Input.TextArea 
                placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'} 
                rows={4}
                allowClear={field.showClear}
                maxLength={field.maxLength}
                readOnly={field.readOnly}
                disabled={field.disabled}
                size={field.size || 'middle'}
              />
            </AntdForm.Item>
          </div>
        );
      case 'password':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
            >
              <Input.Password 
                placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'}
                allowClear={field.showClear}
                maxLength={field.maxLength}
                readOnly={field.readOnly}
                disabled={field.disabled}
                size={field.size || 'middle'}
              />
            </AntdForm.Item>
          </div>
        );
      case 'number':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
            >
              <InputNumber 
                style={{ width: '100%' }} 
                placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'}
                max={field.maxLength}
                readOnly={field.readOnly}
                disabled={field.disabled}
                size={field.size || 'middle'}
              />
            </AntdForm.Item>
          </div>
        );
      case 'select':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
            >
              <Select
                placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择'}
                allowClear={field.showClear}
                disabled={field.disabled}
                size={field.size || 'middle'}
              >
                {(field.options || []).map((opt: any, idx: number) => (
                  <Select.Option key={idx} value={opt.value}>{opt.label}</Select.Option>
                ))}
              </Select>
            </AntdForm.Item>
          </div>
        );
      case 'date':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
              getValueFromEvent={(value) => {
                if (!value) return undefined;
                if (value && typeof value === 'object' && 'valueOf' in value && typeof value.valueOf === 'function' && 'isValid' in value && typeof value.isValid === 'function') {
                  if (value.isValid()) {
                    return value.valueOf();
                  }
                  return undefined;
                }
                return value;
              }}
              normalize={(value) => {
                if (!value) return undefined;
                if (typeof value === 'number') {
                  const dayjsValue = dayjs(value);
                  return dayjsValue.isValid() ? dayjsValue : undefined;
                }
                if (typeof value === 'string') {
                  const numValue = Number(value);
                  if (!isNaN(numValue) && numValue > 0) {
                    const dayjsValue = dayjs(numValue);
                    return dayjsValue.isValid() ? dayjsValue : undefined;
                  }
                  const dayjsValue = dayjs(value);
                  return dayjsValue.isValid() ? dayjsValue : undefined;
                }
                if (value && typeof value === 'object' && 'isValid' in value && typeof value.isValid === 'function') {
                  return value.isValid() ? value : undefined;
                }
                return undefined;
              }}
            >
              <DatePicker 
                style={{ width: '100%' }} 
                placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择日期'}
                allowClear={field.showClear}
                disabled={field.disabled}
                size={field.size || 'middle'}
              />
            </AntdForm.Item>
          </div>
        );
      case 'daterange':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期范围' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
              getValueFromEvent={(value) => {
                if (!value || !Array.isArray(value) || value.length !== 2) return undefined;
                const [start, end] = value;
                if (start && typeof start === 'object' && 'valueOf' in start && typeof start.valueOf === 'function' && 'isValid' in start && typeof start.isValid === 'function' &&
                    end && typeof end === 'object' && 'valueOf' in end && typeof end.valueOf === 'function' && 'isValid' in end && typeof end.isValid === 'function') {
                  if (start.isValid() && end.isValid()) {
                    return [start.valueOf(), end.valueOf()];
                  }
                  return undefined;
                }
                return value;
              }}
              normalize={(value) => {
                if (!value) return undefined;
                if (Array.isArray(value) && value.length === 2) {
                  const [start, end] = value;
                  let startDayjs: any = null;
                  let endDayjs: any = null;
                  
                  if (typeof start === 'number') {
                    startDayjs = dayjs(start);
                    startDayjs = startDayjs.isValid() ? startDayjs : null;
                  } else if (typeof start === 'string') {
                    const numValue = Number(start);
                    if (!isNaN(numValue) && numValue > 0) {
                      startDayjs = dayjs(numValue);
                      startDayjs = startDayjs.isValid() ? startDayjs : null;
                    } else {
                      startDayjs = dayjs(start);
                      startDayjs = startDayjs.isValid() ? startDayjs : null;
                    }
                  } else if (start && typeof start === 'object' && 'isValid' in start && typeof start.isValid === 'function') {
                    startDayjs = start.isValid() ? start : null;
                  }
                  
                  if (typeof end === 'number') {
                    endDayjs = dayjs(end);
                    endDayjs = endDayjs.isValid() ? endDayjs : null;
                  } else if (typeof end === 'string') {
                    const numValue = Number(end);
                    if (!isNaN(numValue) && numValue > 0) {
                      endDayjs = dayjs(numValue);
                      endDayjs = endDayjs.isValid() ? endDayjs : null;
                    } else {
                      endDayjs = dayjs(end);
                      endDayjs = endDayjs.isValid() ? endDayjs : null;
                    }
                  } else if (end && typeof end === 'object' && 'isValid' in end && typeof end.isValid === 'function') {
                    endDayjs = end.isValid() ? end : null;
                  }
                  
                  if (startDayjs && endDayjs) {
                    return [startDayjs, endDayjs];
                  }
                }
                return undefined;
              }}
            >
              <DatePicker.RangePicker 
                style={{ width: '100%' }} 
                placeholder={Array.isArray(field.placeholder) ? field.placeholder as [string, string] : ['开始日期', '结束日期']}
                allowClear={field.showClear}
                disabled={field.disabled}
                size={field.size || 'middle'}
              />
            </AntdForm.Item>
          </div>
        );
      case 'datetime':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期时间' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
              getValueFromEvent={(value) => {
                if (!value) return undefined;
                if (value && typeof value === 'object' && 'valueOf' in value) {
                  return value.valueOf();
                }
                return value;
              }}
              normalize={(value) => {
                if (!value) return undefined;
                if (typeof value === 'number') {
                  const dayjsValue = dayjs(value);
                  return dayjsValue.isValid() ? dayjsValue : undefined;
                }
                if (typeof value === 'string') {
                  const numValue = Number(value);
                  if (!isNaN(numValue) && numValue > 0) {
                    const dayjsValue = dayjs(numValue);
                    return dayjsValue.isValid() ? dayjsValue : undefined;
                  }
                  const dayjsValue = dayjs(value);
                  return dayjsValue.isValid() ? dayjsValue : undefined;
                }
                if (value && typeof value === 'object' && 'isValid' in value && typeof value.isValid === 'function') {
                  return value.isValid() ? value : undefined;
                }
                return undefined;
              }}
            >
              <DatePicker 
                style={{ width: '100%' }} 
                placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择日期时间'}
                allowClear={field.showClear}
                showTime={{ format: 'HH:mm:ss' }}
                format="YYYY-MM-DD HH:mm:ss"
                disabled={field.disabled}
                size={field.size || 'middle'}
              />
            </AntdForm.Item>
          </div>
        );
      case 'switch':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
              help={field.hint}
              valuePropName="checked"
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
            >
              <Switch disabled={field.disabled} />
            </AntdForm.Item>
          </div>
        );
      case 'radio':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
            >
              <Radio.Group disabled={field.disabled}>
                {(field.options || []).map((opt: any, idx: number) => (
                  <Radio key={idx} value={opt.value}>{opt.label}</Radio>
                ))}
              </Radio.Group>
            </AntdForm.Item>
          </div>
        );
      case 'checkbox':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
            >
              <Checkbox.Group disabled={field.disabled}>
                {(field.options || []).map((opt: any, idx: number) => (
                  <Checkbox key={idx} value={opt.value}>{opt.label}</Checkbox>
                ))}
              </Checkbox.Group>
            </AntdForm.Item>
          </div>
        );
      case 'cascader':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
            >
              <Cascader
                placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择'}
                options={field.cascaderOptions || []}
                className="w-full"
                allowClear={field.showClear}
                disabled={field.disabled}
                size={field.size || 'middle'}
              />
            </AntdForm.Item>
          </div>
        );
      case 'upload':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请上传' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
            >
              <FormUploadField
                uploadType={field.uploadType}
                maxCount={field.maxCount}
                accept={field.accept}
                disabled={field.disabled}
              />
            </AntdForm.Item>
          </div>
        );
      case 'time':
      case 'timepicker':
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择时间' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
            >
              <DatePicker 
                style={{ width: '100%' }} 
                placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择时间'}
                allowClear={field.showClear}
                picker="time"
                format="HH:mm:ss"
                disabled={field.disabled}
                size={field.size || 'middle'}
              />
            </AntdForm.Item>
          </div>
        );
      default:
        // 检查 inputType 是否为时间类型
        const inputType = field.inputType || field.type;
        if (inputType === 'date' || inputType === 'datetime' || inputType === 'time' || inputType === 'timepicker') {
          if (inputType === 'datetime') {
            return (
              <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
                <AntdForm.Item
                  label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
                  name={field.name || field.field}
                  required={field.required && !formConfig.hideRequiredMark}
                  rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期时间' }] : []}
                  help={field.hint}
                  labelCol={itemLayout.labelCol}
                  wrapperCol={itemLayout.wrapperCol}
                >
                  <DatePicker 
                    style={{ width: '100%' }} 
                    placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择日期时间'}
                    allowClear={field.showClear}
                    showTime={{ format: 'HH:mm:ss' }}
                    format="YYYY-MM-DD HH:mm:ss"
                    disabled={field.disabled}
                    size={field.size || 'middle'}
                  />
                </AntdForm.Item>
              </div>
            );
          } else if (inputType === 'time' || inputType === 'timepicker') {
            return (
              <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
                <AntdForm.Item
                  label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
                  name={field.name || field.field}
                  required={field.required && !formConfig.hideRequiredMark}
                  rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择时间' }] : []}
                  help={field.hint}
                  labelCol={itemLayout.labelCol}
                  wrapperCol={itemLayout.wrapperCol}
                >
                  <DatePicker 
                    style={{ width: '100%' }} 
                    placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择时间'}
                    allowClear={field.showClear}
                    picker="time"
                    format="HH:mm:ss"
                    disabled={field.disabled}
                    size={field.size || 'middle'}
                  />
                </AntdForm.Item>
              </div>
            );
          } else {
            return (
              <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
                <AntdForm.Item
                  label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
                  name={field.name || field.field}
                  required={field.required && !formConfig.hideRequiredMark}
                  rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期' }] : []}
                  help={field.hint}
                  labelCol={itemLayout.labelCol}
                  wrapperCol={itemLayout.wrapperCol}
                >
                  <DatePicker 
                    style={{ width: '100%' }} 
                    placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择日期'}
                    allowClear={field.showClear}
                    disabled={field.disabled}
                    size={field.size || 'middle'}
                  />
                </AntdForm.Item>
              </div>
            );
          }
        }
        
        // 其他类型使用 Input
        return (
          <div key={field.id} style={{ ...spanStyle, backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '12px', marginBottom: '12px', border: '1px solid #e0e0e0' }}>
            <AntdForm.Item
              label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
              name={field.name || field.field}
              required={field.required && !formConfig.hideRequiredMark}
              rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
              help={field.hint}
              labelCol={itemLayout.labelCol}
              wrapperCol={itemLayout.wrapperCol}
            >
              <Input 
                type={field.inputType || 'text'}
                placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'}
                allowClear={field.showClear}
                maxLength={field.maxLength}
                readOnly={field.readOnly}
                disabled={field.disabled}
                size={field.size || 'middle'}
              />
            </AntdForm.Item>
          </div>
        );
    }
  };

  // 查看任务详情（完整复刻管理员驾驶舱的逻辑）
  const handleViewTaskDetail = async (node: ExecutorNodeVO) => {
    console.log('ExecutorDashboard: handleViewTaskDetail 被调用', node);
    
    const nodeId = node.id || node.uuid;
    if (!nodeId) {
      console.warn('ExecutorDashboard: 节点ID不存在', node);
      message.warning(t('cockpit.nodeIdNotExist'));
      return;
    }
    
    setTaskDetailLoading(true);
    setTaskDetailVisible(true);
    console.log('ExecutorDashboard: 弹框状态已设置为 true (加载中)');
    
    try {
      // 确保 nodeId 是 number 类型
      const numericNodeId = typeof nodeId === 'number' ? nodeId : (typeof nodeId === 'string' ? parseInt(nodeId, 10) : Number(nodeId));
      if (isNaN(numericNodeId)) {
        console.warn('ExecutorDashboard: 节点ID无效', nodeId);
        message.warning(t('cockpit.nodeIdInvalid'));
        setTaskDetailLoading(false);
        return;
      }
      
      console.log('ExecutorDashboard: 开始获取节点详情', { nodeId: numericNodeId });
      const response = await myTaskApi.getMyWorkNodeDetail(numericNodeId);
      console.log('ExecutorDashboard: 节点详情响应', response);
      
      let data: any = response;
    
      // 直接从第一层 data.formId 获取 formId
      let extractedFormId: number | undefined = undefined;
      if (data?.formId !== undefined && data?.formId !== null) {
        const formIdValue = data.formId;
        if (typeof formIdValue === 'string') {
          const parsed = parseInt(formIdValue, 10);
          if (!isNaN(parsed)) {
            extractedFormId = parsed;
            console.log('ExecutorDashboard: ✅ 从 data.formId (字符串) 提取到 formId', extractedFormId);
          }
        } else if (typeof formIdValue === 'number') {
          extractedFormId = formIdValue;
          console.log('ExecutorDashboard: ✅ 从 data.formId (数字) 提取到 formId', extractedFormId);
        }
      }
      
      if (extractedFormId === undefined) {
        console.warn('ExecutorDashboard: ⚠️ 未能提取到 formId', {
          'data.formId': data?.formId,
          'data': data
        });
      }
      
      // 合并列表数据中的作业信息
      const detailDataWithWorkInfo: MyTaskNodeDetailVO = {
        ...(data || {}),
        workName: node.nodeName || data?.workName || data?.name,
        orderNo: node.workId ? String(node.workId) : String(node.id || ''),
        workerUserName: node.workerUserName || data?.workerUserName,
        initiatorName: node.initiatorName || data?.initiatorName || data?.initiator || '',
        workTime: node.startTime || data?.workTime,
        type: data?.type || data?.nodeType || '',
        nodeType: data?.nodeType || data?.type || '',
        formId: extractedFormId,
      };
      
      console.log('ExecutorDashboard: 合并后的详情数据', detailDataWithWorkInfo);
      
      // 先设置数据，确保弹框有内容显示
      setTaskDetailData(detailDataWithWorkInfo);
      setTaskDetailVisible(true);
      setTaskDetailLoading(false);
      
      // 根据节点类型决定是否需要获取表单
      const nodeType = detailDataWithWorkInfo.type || detailDataWithWorkInfo.nodeType || '';
      const isIsolation =
        isWorkflowLockSchemeType(nodeType) || isWorkflowCoLockType(nodeType);
      const isReleaseIsolation =
        isWorkflowUnlockSchemeType(nodeType) || isWorkflowUnlockCoLockType(nodeType);
      const isReturnLock = nodeType === 'returnLock';
      const isolationType = String(detailDataWithWorkInfo?.isolationType ?? '').trim();
      const isBlindOrDismantle = isolationType === '0' || isolationType === '2'; // 0=盲板 2=拆除
      const isApproved = detailDataWithWorkInfo.approvalStatus === 'approved' || detailDataWithWorkInfo.approvalStatus === 3;
      const formId = detailDataWithWorkInfo.formId;
      const hasFormId = formId !== undefined && formId !== null && (
        typeof formId === 'number' || 
        (typeof formId === 'string' && formId !== '' && String(formId).trim() !== '')
      );
      const hasFormData = detailDataWithWorkInfo.formData && (
        (typeof detailDataWithWorkInfo.formData === 'string' && detailDataWithWorkInfo.formData.trim() !== '') ||
        (typeof detailDataWithWorkInfo.formData === 'object' && Object.keys(detailDataWithWorkInfo.formData).length > 0)
      );
      
      // 当前节点无表单时清空表单 state，避免完成/结束节点误展示上一节点的自定义表单
      if (!hasFormId && !(isApproved && hasFormData)) {
        setFormData({ rule: [], option: {} });
        setOriginalFields([]);
        setOriginalConf('');
      }
      
      // 打开盲板/拆除详情时先清空设备编号和附件，后续若有 formData 再回填
      if (isIsolation || isReleaseIsolation) {
        const isolationType = String(detailDataWithWorkInfo.isolationType ?? '').trim();
        if (isolationType === '0' || isolationType === '2') {
          setIsolationDeviceNumber('');
          setIsolationFileList([]);
        }
      }
      
      // 如果任务状态为"已通过"且有 formData，则从 formData 中解析表单结构
      if (isApproved && hasFormData) {
        console.log('ExecutorDashboard: ✅ 任务已通过，从 formData 中解析表单结构');
        setFormLoading(true);
        
        try {
          let parsedFormData: any;
          if (typeof detailDataWithWorkInfo.formData === 'string') {
            parsedFormData = JSON.parse(detailDataWithWorkInfo.formData);
          } else {
            parsedFormData = detailDataWithWorkInfo.formData;
          }
          
          const conf = parsedFormData.conf;
          const fields = parsedFormData.fields;
          
          if (conf && fields) {
            const confString = typeof conf === 'string' ? conf : JSON.stringify(conf);
            const fieldsArray = Array.isArray(fields) ? fields : [];
            const fieldsStringArray = fieldsArray.map((field: any) => {
              return typeof field === 'string' ? field : JSON.stringify(field);
            });
            
            setOriginalConf(confString);
            setOriginalFields(fieldsStringArray);
            
            // 解析字段值用于回显
            const formValues: any = {};
            const fieldTypeMap: { [key: string]: string } = {};
            
            fieldsStringArray.forEach((fieldString: string) => {
              try {
                const fieldObj = typeof fieldString === 'string' ? JSON.parse(fieldString) : fieldString;
                const fieldName = fieldObj.name || fieldObj.field;
                if (fieldName) {
                  fieldTypeMap[fieldName] = fieldObj.type;
                }
              } catch (e) {
                console.error('ExecutorDashboard: 解析字段 JSON 失败', e, fieldString);
              }
            });
            
            fieldsStringArray.forEach((fieldString: string) => {
              try {
                const fieldObj = typeof fieldString === 'string' ? JSON.parse(fieldString) : fieldString;
                const fieldName = fieldObj.name || fieldObj.field;
                if (fieldName && fieldObj.value !== undefined && fieldObj.value !== null) {
                  const fieldType = fieldTypeMap[fieldName];
                  let value = fieldObj.value;
                  
                  if (fieldType === 'date' || fieldType === 'datetime') {
                    if (typeof value === 'string' && value.trim() !== '') {
                      const dayjsValue = dayjs(value);
                      formValues[fieldName] = dayjsValue.isValid() ? dayjsValue : undefined;
                    } else {
                      formValues[fieldName] = undefined;
                    }
                  } else if (fieldType === 'daterange') {
                    if (Array.isArray(value) && value.length === 2) {
                      const [start, end] = value;
                      const startDayjs = typeof start === 'string' && start ? dayjs(start) : null;
                      const endDayjs = typeof end === 'string' && end ? dayjs(end) : null;
                      if (startDayjs && startDayjs.isValid() && endDayjs && endDayjs.isValid()) {
                        formValues[fieldName] = [startDayjs, endDayjs];
                      } else {
                        formValues[fieldName] = undefined;
                      }
                    } else {
                      formValues[fieldName] = undefined;
                    }
                  } else {
                    formValues[fieldName] = value;
                  }
                }
              } catch (e) {
                console.error('ExecutorDashboard: 解析字段 JSON 失败', e, fieldString);
              }
            });
            
            setConfAndFields2(setFormData, conf, fields);
            const convertedFormValues = convertDateValues(formValues, fieldsStringArray);
            
            setTimeout(() => {
              taskDetailForm.setFieldsValue(convertedFormValues);
              console.log('ExecutorDashboard: 表单数据已回填（从 formData）', convertedFormValues);
            }, 100);
            // 有 conf/fields 时也回显 deviceNumber、attachments；attachments 可能是 JSON 字符串
            const normAttachments = (att: any): any[] => {
              if (att == null) return []; if (Array.isArray(att)) return att;
              if (typeof att === 'string' && att.trim()) { try { const p = JSON.parse(att); return Array.isArray(p) ? p : []; } catch { return []; } } return [];
            };
            const listInConf = normAttachments(parsedFormData.attachments).length ? normAttachments(parsedFormData.attachments) : normAttachments((detailDataWithWorkInfo as any).attachments);
            const deviceNumInConf = parsedFormData.deviceNumber ?? (detailDataWithWorkInfo as any).deviceNumber;
            const hasDeviceInConf = deviceNumInConf !== undefined && deviceNumInConf !== null;
            if (hasDeviceInConf || listInConf.length > 0) {
              setIsolationDeviceNumber(deviceNumInConf ?? '');
              setIsolationFileList(
                listInConf.map((item: any, idx: number) => ({
                  uid: `echo-${idx}-${item.url || item.name || idx}`,
                  name: item.name || `文件${idx + 1}`,
                  url: item.url || item.response,
                  status: 'done',
                  response: item.url || item.response,
                }))
              );
            }
          } else if (
            (() => { const d = parsedFormData.deviceNumber; const a = parsedFormData.attachments; if (d !== undefined && d !== null) return true; if (a == null) return false; if (Array.isArray(a) && a.length > 0) return true; if (typeof a === 'string' && a.trim()) { try { const p = JSON.parse(a); return Array.isArray(p) && p.length > 0; } catch { return false; } } return false; })()
          ) {
            const listElse = (() => { const a = parsedFormData.attachments; if (a == null) return []; if (Array.isArray(a)) return a; if (typeof a === 'string' && a.trim()) { try { const p = JSON.parse(a); return Array.isArray(p) ? p : []; } catch { return []; } } return []; })();
            setIsolationDeviceNumber(parsedFormData.deviceNumber ?? '');
            setIsolationFileList(
              listElse.map((item: any, idx: number) => ({
                uid: `echo-${idx}-${item.url || item.name || idx}`,
                name: item.name || `文件${idx + 1}`,
                url: item.url || item.response,
                status: 'done',
                response: item.url || item.response,
              }))
            );
          } else {
            console.warn('ExecutorDashboard: formData 中缺少 conf 或 fields', { conf: !!conf, fields: !!fields });
            message.warning(t('cockpit.formDataIncomplete'));
          }
        } catch (e) {
          console.error('ExecutorDashboard: 解析 formData 失败', e);
          message.error(t('cockpit.parseFormDataFailed') + ': ' + (e instanceof Error ? e.message : String(e)));
        } finally {
          setFormLoading(false);
        }
      }
      // 有 formId 时从接口获取表单：① 审核等非隔离节点 ② 盲板/拆除节点（隔离或解除隔离且隔离方式为盲板或拆除）
      else if (hasFormId && (
        (!isIsolation && !isReleaseIsolation && !isReturnLock) ||
        ((isIsolation || isReleaseIsolation) && isBlindOrDismantle)
      )) {
        console.log('ExecutorDashboard: ✅ 满足条件，开始获取表单', { formId, nodeType, isBlindOrDismantle });
        setFormData({ rule: [], option: {} });
        setOriginalFields([]);
        setOriginalConf('');
        setFormLoading(true);
        
        (async () => {
          try {
            const numericFormId = typeof formId === 'string' ? parseInt(formId, 10) : formId;
            if (isNaN(numericFormId)) {
              console.error('ExecutorDashboard: formId 不是有效数字', formId);
              message.error(t('cockpit.formIdInvalid'));
              setFormLoading(false);
              return;
            }
            
            console.log('ExecutorDashboard: 🚀 开始调用表单接口', { formId: numericFormId, nodeType });
            const FormApi = await import('../api/bpm/form');
            const formDetailResponse = await FormApi.getForm(numericFormId);
            console.log('ExecutorDashboard: ✅ 表单接口调用成功', formDetailResponse);
            
            let formDetail: any = formDetailResponse;
            if (formDetailResponse && typeof formDetailResponse === 'object' && 'data' in formDetailResponse) {
              formDetail = (formDetailResponse as any).data || formDetailResponse;
            }
            
            const conf = formDetail?.conf || formDetail?.formConfig;
            const fields = formDetail?.fields || formDetail?.formFields;
            
            if (conf && fields) {
              const confString = typeof conf === 'string' ? conf : JSON.stringify(conf);
              const fieldsArray = Array.isArray(fields) ? fields : [];
              const fieldsStringArray = fieldsArray.map((field: any) => {
                return typeof field === 'string' ? field : JSON.stringify(field);
              });
              
              setOriginalConf(confString);
              setOriginalFields(fieldsStringArray);
              
              setConfAndFields2(setFormData, conf, fields);
              
              // 仅任务已完成（approved）时回显表单数据；进行中一律不回显并清空表单
              const shouldEchoFormData = detailDataWithWorkInfo.formData && isApproved;
              if (shouldEchoFormData) {
                try {
                  let formValues = typeof detailDataWithWorkInfo.formData === 'string' 
                    ? JSON.parse(detailDataWithWorkInfo.formData) 
                    : detailDataWithWorkInfo.formData;
                  
                  formValues = convertDateValues(formValues, fieldsArray);
                  
                  const cleanedFormValues: any = {};
                  Object.keys(formValues).forEach(key => {
                    const value = formValues[key];
                    const field = fieldsArray.find((f: any) => {
                      const fieldObj = typeof f === 'string' ? JSON.parse(f) : f;
                      return (fieldObj.name || fieldObj.field) === key;
                    });
                    
                    if (field) {
                      const fieldObj = typeof field === 'string' ? JSON.parse(field) : field;
                      const fieldType = fieldObj.type;
                      
                      if (fieldType === 'date' || fieldType === 'datetime' || fieldType === 'timepicker') {
                        if (isValidDayjs(value)) {
                          cleanedFormValues[key] = value;
                        } else if (value !== null && value !== undefined) {
                          const dayjsValue = safeToDayjs(value);
                          cleanedFormValues[key] = dayjsValue || undefined;
                        } else {
                          cleanedFormValues[key] = undefined;
                        }
                      } else if (fieldType === 'daterange') {
                        if (Array.isArray(value) && value.length === 2) {
                          const [start, end] = value;
                          let startDayjs: dayjs.Dayjs | null = null;
                          if (isValidDayjs(start)) {
                            startDayjs = start;
                          } else {
                            startDayjs = safeToDayjs(start);
                          }
                          let endDayjs: dayjs.Dayjs | null = null;
                          if (isValidDayjs(end)) {
                            endDayjs = end;
                          } else {
                            endDayjs = safeToDayjs(end);
                          }
                          cleanedFormValues[key] = (startDayjs && endDayjs) ? [startDayjs, endDayjs] : undefined;
                        } else {
                          cleanedFormValues[key] = undefined;
                        }
                      } else {
                        cleanedFormValues[key] = value;
                      }
                    } else {
                      cleanedFormValues[key] = value;
                    }
                  });
                  
                  setTimeout(() => {
                    try {
                      taskDetailForm.setFieldsValue(cleanedFormValues);
                      console.log('ExecutorDashboard: 表单数据已回填', cleanedFormValues);
                    } catch (e) {
                      console.error('ExecutorDashboard: 设置表单值失败', e);
                    }
                  }, 100);
                } catch (e) {
                  console.error('ExecutorDashboard: 解析表单数据失败', e);
                }
              } else if (!isApproved) {
                // 任务进行中：清空自定义表单，避免带出历史或隔离方案等填写内容
                setTimeout(() => { try { taskDetailForm.resetFields(); } catch (_) { /* ignore */ } }, 100);
              }
              // 隔离/解除隔离完成查看详情：从 formData 或节点详情顶层回显（部分解除隔离节点仅顶层有数据）
              if (isApproved && (isIsolation || isReleaseIsolation)) {
                try {
                  const normAtt = (att: any): any[] => { if (att == null) return []; if (Array.isArray(att)) return att; if (typeof att === 'string' && att.trim()) { try { const p = JSON.parse(att); return Array.isArray(p) ? p : []; } catch { return []; } } return []; };
                  let deviceNum: any; let listF: any[];
                  if (detailDataWithWorkInfo.formData) {
                    const parsed = typeof detailDataWithWorkInfo.formData === 'string' ? JSON.parse(detailDataWithWorkInfo.formData) : detailDataWithWorkInfo.formData;
                    listF = normAtt(parsed.attachments).length ? normAtt(parsed.attachments) : normAtt((detailDataWithWorkInfo as any).attachments);
                    deviceNum = parsed.deviceNumber ?? (detailDataWithWorkInfo as any).deviceNumber;
                  } else {
                    deviceNum = (detailDataWithWorkInfo as any).deviceNumber;
                    listF = normAtt((detailDataWithWorkInfo as any).attachments);
                  }
                  if ((deviceNum !== undefined && deviceNum !== null) || listF.length > 0) {
                    setIsolationDeviceNumber(deviceNum ?? '');
                    setIsolationFileList(listF.map((item: any, idx: number) => ({ uid: `echo-${idx}-${item.url || item.name || idx}`, name: item.name || `文件${idx + 1}`, url: item.url || item.response, status: 'done', response: item.url || item.response })));
                  }
                } catch (_) { /* ignore */ }
              }
            } else {
              console.warn('ExecutorDashboard: 表单详情缺少配置或字段', { conf: !!conf, fields: !!fields });
              message.warning(t('cockpit.formConfigIncomplete'));
            }
          } catch (e) {
            console.error('ExecutorDashboard: 获取表单详情失败', e);
            message.error(t('cockpit.getFormDetailFailed') + ': ' + (e instanceof Error ? e.message : String(e)));
          } finally {
            setFormLoading(false);
          }
        })();
      } else {
        setFormLoading(false);
        if (isApproved && (isIsolation || isReleaseIsolation)) {
          try {
            const normAtt = (att: any): any[] => { if (att == null) return []; if (Array.isArray(att)) return att; if (typeof att === 'string' && att.trim()) { try { const p = JSON.parse(att); return Array.isArray(p) ? p : []; } catch { return []; } } return []; };
            const deviceNum = (detailDataWithWorkInfo as any).deviceNumber;
            const listF = normAtt((detailDataWithWorkInfo as any).attachments);
            if ((deviceNum !== undefined && deviceNum !== null) || listF.length > 0) {
              setIsolationDeviceNumber(deviceNum ?? '');
              setIsolationFileList(listF.map((item: any, idx: number) => ({ uid: `echo-${idx}-${item.url || item.name || idx}`, name: item.name || `文件${idx + 1}`, url: item.url || item.response, status: 'done', response: item.url || item.response })));
            }
          } catch (_) { /* ignore */ }
        }
      }
      
      // 回显审核意见
      if (detailDataWithWorkInfo.approvalOpinion && detailDataWithWorkInfo.approvalOpinion !== 'pending') {
        setApprovalComment(detailDataWithWorkInfo.approvalOpinion);
      } else {
        setApprovalComment('');
      }
      
      console.log('ExecutorDashboard: 弹框已打开', { detailVisible: true, detailData: detailDataWithWorkInfo });
    } catch (error: any) {
      console.error('ExecutorDashboard: 获取节点详情失败', error);
      toast.error(error.message || t('cockpit.getNodeDetailFailed'));
      if (!taskDetailData) {
        setTaskDetailData({
          id: nodeId,
          nodeId: nodeId,
          workId: node.workId,
          workName: node.nodeName,
          orderNo: node.workId ? String(node.workId) : String(node.id || ''),
          workerUserName: node.workerUserName || node.initiatorName || '',
          workTime: node.startTime,
          type: '',
        } as MyTaskNodeDetailVO);
      }
      setTaskDetailVisible(true);
    } finally {
      setTaskDetailLoading(false);
    }
  };

  // 处理查看任务（使用新的 handleViewTaskDetail）
  const handleViewTask = (node: ExecutorNodeVO) => {
    handleViewTaskDetail(node);
  };
  
  // 表格列定义
  const columns = [
    {
      title: t('cockpit.jobNo'),
      dataIndex: 'orderNo',
      key: 'orderNo',
      width: 120,
      render: (_: any, record: ExecutorNodeVO) => {
        return record.orderNo || '-';
      },
    },
    {
      title: t('cockpit.jobName'),
      dataIndex: 'name',
      key: 'name',
      width: 200,
      ellipsis: true,
      render: (text: string) => {
        return text || '-';
      },
    },
    {
      title: t('cockpit.taskName'),
      dataIndex: 'currentNodeName',
      key: 'currentNodeName',
      width: 200,
      ellipsis: true,
      render: (text: string, record: ExecutorNodeVO) => {
        const urgencyValue = record.urgencyLevel;
        const priorityText = getPriorityText(urgencyValue);
        
        // 根据优先级值设置颜色样式
        const getPriorityStyle = (value: string | number | undefined): React.CSSProperties => {
          if (value === null || value === undefined || value === '') {
            return { color: '#6b7280' }; // 灰色
          }
          const numValue = Number(value);
          if (numValue === 1) {
            return { color: '#fa8c16' }; // 紧急：橙色
          }
          if (numValue === 2) {
            return { color: '#ff4d4f' }; // 非常紧急：红色
          }
          return { color: '#6b7280' }; // 一般：灰色
        };
        
        const nodeName = text || record.currentNodeName || record.nodeName || record.description || t('cockpit.unknownTask');
        
        return (
          <div>
            <div>{nodeName}</div>
            {urgencyValue !== undefined && urgencyValue !== null && urgencyValue !== '' && (
              <div className="text-xs mt-1" style={getPriorityStyle(urgencyValue)}>
                {t('cockpit.urgencyLevel')}：{priorityText}
              </div>
            )}
          </div>
        );
      },
    },
    {
      title: t('cockpit.jobType'),
      dataIndex: 'workType',
      key: 'workType',
      width: 120,
      render: (workType: string | number | undefined, record: ExecutorNodeVO) => {
        const workTypeValue = workType || record.workType;
        const workTypeText = getWorkTypeText(workTypeValue);
        return <span>{workTypeText}</span>;
      },
    },
    {
      title: t('cockpit.startTime'),
      dataIndex: 'workTime',
      key: 'workTime',
      width: 180,
      render: (text: any, record: ExecutorNodeVO) => {
        const timeValue = text || record.workTime || record.startTime;
        if (!timeValue) return '-';
        try {
          // 如果是数字（时间戳），需要处理
          if (typeof timeValue === 'number') {
            // 如果是秒级时间戳，转换为毫秒
            let timestamp = timeValue;
            if (timestamp < 10000000000) {
              timestamp = timestamp * 1000;
            }
            return formatDateWithFormat(timestamp, 'YYYY-MM-DD HH:mm:ss');
          }
          return formatDateWithFormat(timeValue, 'YYYY-MM-DD HH:mm:ss');
        } catch (e) {
          return String(timeValue);
        }
      },
    },
    {
      title: t('cockpit.status'),
      key: 'status',
      width: 100,
      render: (_: any, record: ExecutorNodeVO) => {
        const status = record.approvalStatus;
        const statusText = getTaskStatusText(status);
        const style = getTaskStatusStyle(status);
        return (
          <Tag style={style}>
            {statusText}
          </Tag>
        );
      },
    },
    {
      title: t('cockpit.action'),
      key: 'action',
      width: 120,
      render: (_: any, record: ExecutorNodeVO) => {
        const statusText = getTaskStatusText(record.approvalStatus);
        const statusTextLower = statusText.toLowerCase();
        const isInProgress = statusTextLower.includes('进行中') || statusTextLower.includes('待审核') || statusTextLower.includes('pending') || statusTextLower.includes('执行中') || statusTextLower.includes('in progress');
        const isCompleted = statusTextLower.includes('已完成') || statusTextLower.includes('已通过') || statusTextLower.includes('approved') || statusTextLower.includes('完成') || statusTextLower.includes('执行完成') || statusTextLower.includes('completed');
        const buttonText = isInProgress ? t('form.handleNow') : (isCompleted ? t('form.viewDetail') : t('form.viewDetail'));
        return (
          <Space size="small">
            <Button
              type="link"
              size="small"
              icon={<Eye className="w-4 h-4" style={{ color: '#000000' }} />}
              onClick={(e) => {
                e.stopPropagation();
                e.preventDefault();
                handleViewTask(record);
              }}
              style={{ color: '#000000' }}
              className="transition-colors hover:text-[#1677ff] hover:underline"
              onMouseEnter={(e) => {
                e.currentTarget.style.color = '#1677ff';
                e.currentTarget.querySelector('svg')?.setAttribute('style', 'color: #1677ff');
              }}
              onMouseLeave={(e) => {
                e.currentTarget.style.color = '#000000';
                e.currentTarget.querySelector('svg')?.setAttribute('style', 'color: #000000');
              }}
            >
              {buttonText}
            </Button>
          </Space>
        );
      },
    },
  ];
  
  return (
    <div className="space-y-8">
      {/* 任务状态摘要 */}
      <div className="grid grid-cols-3 gap-4 mb-8">
        <Card className="border border-gray-200 shadow-sm">
          <div className="flex items-center justify-between">
            <div>
              <div className="text-sm text-gray-500 mb-1">{t('cockpit.pendingTask')}</div>
              <div className="text-2xl font-bold text-gray-700">{nodeCount.unreleasedCount || 0}</div>
            </div>
            <div className="w-12 h-12 rounded-lg bg-gray-100 flex items-center justify-center">
              <Clock className="w-6 h-6 text-gray-600" />
            </div>
          </div>
        </Card>
        
        <Card className="border border-blue-200 shadow-sm bg-blue-50">
          <div className="flex items-center justify-between">
            <div>
              <div className="text-sm text-gray-500 mb-1">{t('cockpit.inProgressTask')}</div>
              <div className="text-2xl font-bold text-blue-600">{nodeCount.runningCount || 0}</div>
            </div>
            <div className="w-12 h-12 rounded-lg bg-blue-100 flex items-center justify-center">
              <PlayCircle className="w-6 h-6 text-blue-600" />
            </div>
          </div>
        </Card>
        
        <Card className="border border-green-200 shadow-sm bg-green-50">
          <div className="flex items-center justify-between">
            <div>
              <div className="text-sm text-gray-500 mb-1">{t('cockpit.completedTask')}</div>
              <div className="text-2xl font-bold text-green-600">{nodeCount.completedCount || 0}</div>
            </div>
            <div className="w-12 h-12 rounded-lg bg-green-100 flex items-center justify-center">
              <CheckCircle className="w-6 h-6 text-green-600" />
            </div>
          </div>
        </Card>
      </div>
      
      {/* 我的作业任务 */}
      <Card className="border border-gray-200 shadow-sm mb-8" style={{marginBottom: '20px'}}>
        <div className="flex items-center justify-between mb-4">
          <div className="flex items-center gap-2">
            <AlertCircle className="w-5 h-5 text-orange-500" />
            <h3 className="text-lg font-semibold text-gray-900">{t('cockpit.myJobTasks')}</h3>
          </div>
          <div className="flex items-center gap-4">
            <span className="text-sm text-gray-500">{t('cockpit.processJobTasksPrompt')}</span>
            <Button 
              type="link" 
              size="small" 
              onClick={() => {
                // 通过 sessionStorage 传递参数，让 Dashboard 自动切换到隔离作业下的我的任务菜单
                sessionStorage.setItem('navigateToMenu', JSON.stringify({
                  menu: 'isolationWork',
                  subMenu: 'myTask'
                }));
                
                // 如果当前已经在 dashboard 页面，触发自定义事件来切换菜单
                if (window.location.pathname === '/dashboard') {
                  // 触发自定义事件，通知 Dashboard 切换菜单
                  window.dispatchEvent(new CustomEvent('switchToMenu', {
                    detail: { menu: 'isolationWork', subMenu: 'myTask' }
                  }));
                } else {
                  // 如果不在 dashboard 页面，导航过去
                  navigate('/dashboard');
                }
              }}
            >
              {t('cockpit.viewAll')}
            </Button>
          </div>
        </div>
        <Table
          columns={columns}
          dataSource={transformedNodeList}
          rowKey={(record) => `${record.id || record.uuid || Math.random()}`}
          loading={loading}
          pagination={false}
          size="middle"
          scroll={{ y: 400 }}
        />
      </Card>
      
      {/* 任务完成趋势 */}
      <Card className="border border-gray-200 shadow-sm mb-8" style={{marginBottom: '20px'}}>
        <h3 className="text-lg font-semibold text-gray-900 mb-6">
          {t('cockpit.taskCompleteTrend')}
        </h3>
        <div className="h-80">
          <ResponsiveContainer width="100%" height="100%">
            <AreaChart
              data={trendData}
              margin={{ top: 10, right: 30, left: 20, bottom: 20 }}
            >
              <defs>
                <linearGradient id="colorCompletedCount" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="5%" stopColor="#1677ff" stopOpacity={0.3}/>
                  <stop offset="95%" stopColor="#1677ff" stopOpacity={0}/>
                </linearGradient>
              </defs>
              <CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
              <XAxis 
                dataKey="date" 
                stroke="#6b7280"
                tick={{ fontSize: 12, fill: '#6b7280' }}
                axisLine={{ stroke: '#e5e7eb' }}
              />
              <YAxis 
                stroke="#6b7280"
                tick={{ fontSize: 12, fill: '#6b7280' }}
                axisLine={{ stroke: '#e5e7eb' }}
                domain={[0, 'dataMax + 1']}
              />
              <Tooltip 
                contentStyle={{ 
                  backgroundColor: '#fff', 
                  border: '1px solid #e5e7eb',
                  borderRadius: '8px',
                  padding: '8px 12px'
                }}
              />
              <Legend />
              <Area 
                type="monotone" 
                dataKey="completedCount" 
                stroke="#1677ff" 
                strokeWidth={2}
                fill="url(#colorCompletedCount)"
                name={t('cockpit.dailyTaskCompletedCount')}
                dot={{ fill: '#1677ff', r: 4 }}
                activeDot={{ r: 6 }}
              />
            </AreaChart>
          </ResponsiveContainer>
        </div>
      </Card>
      
      {/* 任务详情弹框 */}
      <Modal
        title={null}
        open={taskDetailVisible}
        onCancel={() => {
          setTaskDetailVisible(false);
          setTaskDetailData(null);
          setFormData({ rule: [], option: {} });
          setFormLoading(false);
          setOriginalFields([]);
          setOriginalConf('');
          taskDetailForm.resetFields();
          setApprovalComment('');
          setIsolationDeviceNumber('');
          setIsolationFileList([]);
        }}
        footer={null}
        width={1000}
        destroyOnClose
        maskClosable={false}
        styles={{
          body: {
            minHeight: '600px',
            maxHeight: '700px',
            height: '700px',
            padding: 0,
            display: 'flex',
            flexDirection: 'column',
            overflow: 'hidden'
          }
        }}
      >
        {taskDetailLoading ? (
          <div className="py-8 text-center text-gray-500">{t('cockpit.loading')}</div>
        ) : taskDetailData ? (
          <div style={{ 
            display: 'flex',
            flexDirection: 'column',
            height: '100%',
            overflow: 'hidden'
          }}>
            {/* 标题区域 */}
            <div className="mb-4" style={{ padding: '20px 24px 0' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
                <div style={{ 
                  width: '3px', 
                  height: '24px', 
                  backgroundColor: '#025fff',
                  borderRadius: '2px',
                  flexShrink: 0
                }}></div>
                <h2 className="text-xl font-semibold mb-2" style={{ color: '#025fff', marginBottom: 0 }}>
                  {taskDetailData.workName || taskDetailData.name || t('cockpit.taskDetail')}
                </h2>
                <span 
                  className="inline-flex px-3 py-1 rounded-full text-xs font-medium"
                  style={getTaskStatusStyle(taskDetailData.approvalStatus || taskDetailData.taskStatus || taskDetailData.status)}
                >
                  {getTaskStatusText(taskDetailData.approvalStatus || taskDetailData.taskStatus || taskDetailData.status)}
                </span>
              </div>
              <div className="text-sm flex gap-4" style={{ color: '#898f9a', marginTop: '12px' }}>
                <span>{t('cockpit.orderNo')}：{taskDetailData.orderNo || '-'}</span>
                <span>{t('cockpit.jobInitiatorLabel')}：{taskDetailData.initiatorName || '-'}</span>
                <span>{t('cockpit.taskOwnerLabel')}：{taskDetailData.workerUserName || '-'}</span>
                <span>{t('cockpit.startTime')}：{taskDetailData.workTime ? dateFormatter(taskDetailData.workTime) : '-'}</span>
              </div>
            </div>

            {/* 内容区域 - 可滚动 */}
            <div className="mt-6" style={{ 
              padding: '0 24px',
              flex: 1,
              overflowY: 'auto',
              minHeight: 0
            }}>
              {(() => {
                const isApproved = taskDetailData?.approvalStatus === 'approved' || taskDetailData?.approvalStatus === 3;
                const nodeType = String(taskDetailData?.type || taskDetailData?.nodeType || '').trim();
                const isReview = nodeType === 'review';
                const isIsolation =
                  isWorkflowLockSchemeType(nodeType) || isWorkflowCoLockType(nodeType);
                const isReleaseIsolation =
                  isWorkflowUnlockSchemeType(nodeType) || isWorkflowUnlockCoLockType(nodeType);
                const isReturnLock = nodeType === 'returnLock';
                const hasFormIdForCurrentNode = taskDetailData?.formId !== undefined && taskDetailData?.formId !== null && (
                  typeof taskDetailData.formId === 'number' || (typeof taskDetailData.formId === 'string' && String(taskDetailData.formId).trim() !== '')
                );

                // 隔离/方案节点、解除隔离节点和还锁节点
                if (isIsolation || isReleaseIsolation || isReturnLock) {
                  const isolationType = String(taskDetailData?.isolationType ?? '').trim();
                  const isLockoutTagout = isolationType === '1';
                  const isBlindPlate = isolationType === '0';
                  const isDismantle = isolationType === '2';
                  const showLockCabinet = isReturnLock || (isLockoutTagout && (isIsolation || isReleaseIsolation));
                  const showDeviceForm = (isIsolation || isReleaseIsolation) && (isBlindPlate || isDismantle);

                  if (showDeviceForm) {
                    const deviceLabel = isReleaseIsolation
                      ? (isBlindPlate ? t('form.releaseBlindPlateDeviceNo') : t('form.restoreDeviceNo'))
                      : (isBlindPlate ? t('form.blindPlateDeviceNo') : t('form.dismantleDeviceNo'));
                    const formIdVal = taskDetailData?.formId;
                    const hasFormIdForBlindDismantle = formIdVal !== undefined && formIdVal !== null && (
                      typeof formIdVal === 'number' || (typeof formIdVal === 'string' && String(formIdVal).trim() !== '')
                    );
                    return (
                      <div key="isolation-device-form" style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
                        <div style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: '24px', background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)' }}>
                          <div style={{ width: '100%' }}>
                              <div style={{ marginBottom: 26 }}>
                                <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 14, fontWeight: 600, color: '#1f2937', marginBottom: 12 }}>
                                  <span style={{ width: 28, height: 28, borderRadius: 8, background: '#e6f4ff', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
                                    <BarcodeOutlined style={{ fontSize: 14, color: '#1677ff' }} />
                                  </span>
                                  {deviceLabel}
                                </label>
                                <Input
                                  value={isolationDeviceNumber}
                                  onChange={(e) => !isApproved && setIsolationDeviceNumber(e.target.value)}
                                  placeholder={`请输入${deviceLabel}`}
                                  maxLength={100}
                                  size="large"
                                  disabled={isApproved}
                                  prefix={<BarcodeOutlined style={{ color: '#91caff', marginRight: 8 }} />}
                                  style={{ borderRadius: 10, borderColor: '#d9e8ff', fontSize: 15 }}
                                />
                              </div>
                              <div>
                                <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 14, fontWeight: 600, color: '#1f2937', marginBottom: 12 }}>
                                  <span style={{ width: 28, height: 28, borderRadius: 8, background: '#e6f4ff', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
                                    <UploadOutlined style={{ fontSize: 14, color: '#1677ff' }} />
                                  </span>
                                  附件上传
                                  {!isApproved && <span style={{ marginLeft: 8, fontSize: 12, fontWeight: 400, color: '#69b1ff', background: '#e6f4ff', padding: '2px 8px', borderRadius: 6 }}>支持拖拽</span>}
                                </label>
                                {isApproved && isolationFileList.length > 0 ? (
                                  <div style={{ borderRadius: 12, padding: '32px 20px', background: 'linear-gradient(180deg, #f5faff 0%, #e8f4ff 50%, #e0efff 100%)', border: '2px solid #91caff', minHeight: 180, display: 'flex', flexWrap: 'wrap', gap: 16, alignItems: 'center', justifyContent: 'center', alignContent: 'center' }}>
                                    <Image.PreviewGroup>
                                      {isolationFileList.filter((f: any) => /\.(jpg|jpeg|png|gif|webp|bmp)(\?|$)/i.test(String((f.url || f.response) || '')) || /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(String(f.name || ''))).map((file: any) => (
                                        <Image key={file.uid} width={160} height={160} src={file.url || file.response} style={{ objectFit: 'cover', borderRadius: 10, cursor: 'pointer', flexShrink: 0 }} alt={file.name} />
                                      ))}
                                    </Image.PreviewGroup>
                                    {isolationFileList.filter((f: any) => !/\.(jpg|jpeg|png|gif|webp|bmp)(\?|$)/i.test(String((f.url || f.response) || '')) && !/\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(String(f.name || ''))).map((file: any) => (
                                      <a key={file.uid} href={file.url || file.response} target="_blank" rel="noopener noreferrer" style={{ display: 'block', padding: '12px 16px', background: '#fff', borderRadius: 10, color: '#1677ff', border: '1px solid #91caff', maxWidth: 240, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{file.name}</a>
                                    ))}
                                  </div>
                                ) : isApproved ? (
                                  <div style={{ padding: 24, textAlign: 'center', color: '#8c8c8c', background: '#fafafa', borderRadius: 12 }}>暂无附件</div>
                                ) : (
                                  <Upload.Dragger
                                    fileList={isolationFileList}
                                    onChange={({ fileList }) => setIsolationFileList(fileList.slice(-5))}
                                    multiple
                                    showUploadList={{ showRemoveIcon: true }}
                                    customRequest={async ({ file, onSuccess, onError }) => {
                                      try {
                                        const url = await fileApi.upload(file as File);
                                        onSuccess?.(url);
                                      } catch (e: any) {
                                        onError?.(e);
                                        message.error(e?.message || '文件上传失败');
                                      }
                                    }}
                                    style={{ borderRadius: 12, padding: '32px 20px', background: 'linear-gradient(180deg, #f5faff 0%, #e8f4ff 50%, #e0efff 100%)', border: '2px dashed #91caff' }}
                                  >
                                    <p className="ant-upload-drag-icon" style={{ marginBottom: 12 }}>
                                      <span style={{ width: 64, height: 64, borderRadius: 16, background: 'linear-gradient(135deg, rgba(22,119,255,0.15) 0%, rgba(64,150,255,0.1) 100%)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
                                        <UploadOutlined style={{ fontSize: 32, color: '#1677ff' }} />
                                      </span>
                                    </p>
                                    <p className="ant-upload-text" style={{ margin: 0, color: '#0958d9', fontSize: 15, fontWeight: 500 }}>点击或拖拽文件到此区域上传</p>
                                    <p className="ant-upload-hint" style={{ margin: '8px 0 0', color: '#69b1ff', fontSize: 13 }}>最多 5 个文件，支持多选</p>
                                  </Upload.Dragger>
                                )}
                              </div>
                              {hasFormIdForBlindDismantle && (
                                <div style={{ marginTop: 24, paddingTop: 24, borderTop: '1px solid rgba(22, 119, 255, 0.12)' }}>
                                  {formLoading ? (
                                    <div className="py-6 text-center text-gray-500">{t('cockpit.formLoading')}</div>
                                  ) : formData.rule && formData.rule.length > 0 ? (
                                    (() => {
                                      const formConfig = formData.option?.formConfig || defaultFormConfig;
                                      const layoutColumns = formConfig.layoutColumns || 1;
                                      const gridStyle = layoutColumns > 1 ? {
                                        display: 'grid',
                                        gridTemplateColumns: `repeat(${layoutColumns}, minmax(0, 1fr))`,
                                        gap: '12px',
                                        rowGap: '16px',
                                      } : undefined;
                                      return (
                                        <AntdForm
                                          form={taskDetailForm}
                                          layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                                          size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                                          requiredMark={formConfig.hideRequiredMark ? false : undefined}
                                          labelCol={
                                            formConfig.labelPosition === 'top' || !formConfig.labelWidth
                                              ? undefined
                                              : {
                                                  flex: `${formConfig.labelWidth}px`,
                                                  style: {
                                                    minWidth: `${formConfig.labelWidth}px`,
                                                    textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
                                                  },
                                                }
                                          }
                                          wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                                        >
                                          <div style={gridStyle} className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}>
                                            <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; } .form-detail-grid .ant-form-item-control { min-width: 0; }`}</style>
                                            {(formData.rule || []).map((field: any) => {
                                              const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;
                                              return renderFieldPreview(fieldWithDisabled);
                                            })}
                                          </div>
                                        </AntdForm>
                                      );
                                    })()
                                  ) : null}
                                </div>
                              )}
                          </div>
                        </div>
                        <div className="flex justify-end gap-3" style={{ padding: '20px 24px', borderTop: '1px solid rgba(22, 119, 255, 0.1)', flexShrink: 0, background: 'linear-gradient(0deg, #f0f7ff 0%, #fafcff 60%, #fff 100%)' }}>
                          {!isApproved ? (
                            <Button
                              type="primary"
                              loading={isolationSubmitLoading}
                              onClick={async () => {
                                const nodeId = taskDetailData.nodeId ?? taskDetailData.id;
                                if (nodeId == null) {
                                  message.warning(t('cockpit.nodeIdNotExist'));
                                  return;
                                }
                                const uploadedFiles = isolationFileList.filter((f: any) => f.status === 'done' && (f.response != null));
                                const uploadingCount = isolationFileList.filter((f: any) => f.status === 'uploading').length;
                                if (uploadingCount > 0) {
                                  message.warning('请等待文件上传完成');
                                  return;
                                }
                                if (isolationFileList.length > 0 && uploadedFiles.length === 0) {
                                  message.warning('请等待文件上传完成或移除未上传成功的文件');
                                  return;
                                }
                                if (hasFormIdForBlindDismantle && formData.rule && formData.rule.length > 0) {
                                  try {
                                    await taskDetailForm.validateFields();
                                  } catch (err: any) {
                                    if (err?.errorFields?.[0]?.errors?.[0]) {
                                      message.error(err.errorFields[0].errors[0]);
                                    } else {
                                      message.error('请完善表单内容');
                                    }
                                    return;
                                  }
                                }
                                setIsolationSubmitLoading(true);
                                try {
                                  const attachmentUrls = uploadedFiles.map((f: any) => {
                                    const url = typeof f.response === 'string' ? f.response : (f.response?.url ?? '');
                                    return { name: f.name, url };
                                  });
                                  let formDataString: string | undefined = undefined;
                                  if (hasFormIdForBlindDismantle && formData.rule && formData.rule.length > 0 && originalFields.length > 0) {
                                    try {
                                      const values = taskDetailForm.getFieldsValue();
                                      const fieldsWithValues = originalFields.map((fieldString: string) => {
                                        try {
                                          const fieldObj = JSON.parse(fieldString);
                                          const fieldName = fieldObj.name || fieldObj.field;
                                          const fieldValue = values[fieldName];
                                          fieldObj.value = fieldValue !== undefined && fieldValue !== null ? fieldValue : '';
                                          return JSON.stringify(fieldObj);
                                        } catch {
                                          return fieldString;
                                        }
                                      });
                                      const submitData = { conf: formData.option, fields: fieldsWithValues };
                                      formDataString = JSON.stringify(submitData);
                                    } catch (e) {
                                      console.error('ExecutorDashboard: 盲板/拆除 表单数据序列化失败', e);
                                    }
                                  }
                                  await myTaskApi.updateNodeApproval({
                                    nodeId: typeof nodeId === 'number' ? nodeId : Number(nodeId),
                                    approvalStatus: 'approved',
                                    deviceNumber: isolationDeviceNumber,
                                    attachments: JSON.stringify(attachmentUrls),
                                    ...(formDataString != null ? { formData: formDataString } : {}),
                                  });
                                  message.success(t('common.submit') + t('common.success'));
                                  setTaskDetailVisible(false);
                                  setTaskDetailData(null);
                                  setIsolationDeviceNumber('');
                                  setIsolationFileList([]);
                                  fetchAllData();
                                } catch (error: any) {
                                  message.error(error?.message || '提交失败');
                                } finally {
                                  setIsolationSubmitLoading(false);
                                }
                              }}
                              icon={<SendOutlined />}
                              style={{ minWidth: 120, height: 44, borderRadius: 10, fontSize: 15, fontWeight: 500, boxShadow: '0 4px 14px rgba(22, 119, 255, 0.35)' }}
                            >
                              {t('common.submit')}
                            </Button>
                          ) : (
                            <Button onClick={() => { setTaskDetailVisible(false); setTaskDetailData(null); setIsolationDeviceNumber(''); setIsolationFileList([]); }} style={{ minWidth: 120, height: 44, borderRadius: 10, fontSize: 15, fontWeight: 500 }}>
                              {t('common.cancel')}
                            </Button>
                          )}
                        </div>
                      </div>
                    );
                  }

                  return (
                    <div style={{ flex: 1, minHeight: 0, overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '24px', background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)' }}>
                      <div style={{ width: '100%', textAlign: 'center', padding: '24px 0' }}>
                        <div style={{ marginBottom: 28 }}>
                          <span style={{ width: 88, height: 88, borderRadius: 20, background: 'linear-gradient(135deg, #1677ff 0%, #4096ff 50%, #69b1ff 100%)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 8px 24px rgba(22, 119, 255, 0.35)' }}>
                            <LockOutlined style={{ fontSize: 42, color: '#fff' }} />
                          </span>
                        </div>
                        <div style={{ fontSize: 18, fontWeight: 600, color: '#1f2937', lineHeight: 1.6, marginBottom: 8 }}>{t('form.lockCabinetTip')}</div>
                        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 13, color: '#69b1ff' }}>
                          <KeyOutlined />
                          <span>完成取锁、取钥匙后，任务将自动推进</span>
                        </div>
                      </div>
                    </div>
                  );
                }

                // 审核类型节点 (review) - 表单直接放在外层，取消内置白框
                if (isReview) {
                  return (
                    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
                      <div style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: '24px', background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)' }}>
                        <div style={{ width: '100%' }}>
                            {formLoading ? (
                              <div className="py-8 text-center text-gray-500">{t('cockpit.formLoading')}</div>
                            ) : hasFormIdForCurrentNode && formData.rule && formData.rule.length > 0 ? (
                              <div className="space-y-4">
                                {(() => {
                                  const formConfig = formData.option?.formConfig || defaultFormConfig;
                                  const layoutColumns = formConfig.layoutColumns || 1;
                                  const gridStyle = layoutColumns > 1 ? { display: 'grid', gridTemplateColumns: `repeat(${layoutColumns}, minmax(0, 1fr))`, gap: '12px', rowGap: '16px' } : undefined;
                                  return (
                                    <AntdForm form={taskDetailForm} layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'} size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize} requiredMark={formConfig.hideRequiredMark ? false : undefined} labelCol={formConfig.labelPosition === 'top' || !formConfig.labelWidth ? undefined : { flex: `${formConfig.labelWidth}px`, style: { minWidth: `${formConfig.labelWidth}px`, textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left' } }} wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}>
                                      <div style={gridStyle} className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}>
                                        <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; } .form-detail-grid .ant-form-item-control { min-width: 0; }`}</style>
                                        {(formData.rule || []).map((field: any) => {
                                          const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;
                                          return renderFieldPreview(fieldWithDisabled);
                                        })}
                                      </div>
                                    </AntdForm>
                                  );
                                })()}
                              </div>
                            ) : (
                              <div style={{ textAlign: 'center', padding: '32px 24px' }}>
                                <span style={{ width: 72, height: 72, borderRadius: 18, background: 'linear-gradient(135deg, #1677ff 0%, #4096ff 50%, #69b1ff 100%)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 8px 24px rgba(22, 119, 255, 0.35)', marginBottom: 20 }}>
                                  <CheckCircleOutlined style={{ fontSize: 36, color: '#fff' }} />
                                </span>
                                <div style={{ fontSize: 18, fontWeight: 600, color: '#1f2937', lineHeight: 1.6 }}>无需填写表单，直接点击底部按钮提交即可</div>
                              </div>
                            )}
                            <div className="flex items-start" style={{ gap: 16, marginTop: 24, paddingTop: 24, borderTop: '1px solid rgba(22, 119, 255, 0.12)' }}>
                              <label className="text-sm font-medium text-gray-700 whitespace-nowrap pt-2" style={{ width: defaultFormConfig.labelWidth ? `${defaultFormConfig.labelWidth - 20}px` : '80px', textAlign: defaultFormConfig.labelPosition === 'left' ? 'left' : defaultFormConfig.labelPosition === 'right' ? 'right' : 'left', flexShrink: 0 }}>{t('form.reviewComment')}</label>
                              <div className="flex-1">
                                <Input.TextArea rows={4} value={approvalComment} onChange={(e) => setApprovalComment(e.target.value)} placeholder={t('form.reviewCommentPlaceholder')} maxLength={500} showCount disabled={isApproved} readOnly={isApproved} style={{ borderRadius: 10, borderColor: '#d9e8ff' }} />
                              </div>
                            </div>
                        </div>
                      </div>
                      <div className="flex justify-end gap-3" style={{ padding: '20px 24px', borderTop: '1px solid rgba(22, 119, 255, 0.1)', flexShrink: 0, background: 'linear-gradient(0deg, #f0f7ff 0%, #fafcff 60%, #fff 100%)' }}>
                        <Button
                          danger
                          loading={approvalLoading}
                          disabled={isApproved}
                          onClick={async () => {
                            const nodeId = taskDetailData.nodeId ?? taskDetailData.id;
                            if (nodeId == null) {
                              message.warning(t('cockpit.nodeIdNotExist'));
                              return;
                            }
                            const numNodeId = typeof nodeId === 'number' ? nodeId : Number(nodeId);
                            if (isNaN(numNodeId)) {
                              message.warning(t('cockpit.nodeIdInvalid'));
                              return;
                            }
                            if (formData.rule && formData.rule.length > 0) {
                              try {
                                await taskDetailForm.validateFields();
                              } catch (err: any) {
                                if (err?.errorFields?.length) {
                                  message.error(err.errorFields[0]?.errors?.[0] || '请完善表单内容');
                                } else {
                                  message.error('请完善表单内容');
                                }
                                return;
                              }
                            }
                            setApprovalLoading(true);
                            try {
                              let formDataString: string | undefined;
                              if (formData.rule?.length && originalFields.length > 0) {
                                const values = taskDetailForm.getFieldsValue();
                                const fieldsWithValues = originalFields.map((fieldString: string) => {
                                  try {
                                    const fieldObj = JSON.parse(fieldString);
                                    const fieldName = fieldObj.name || fieldObj.field;
                                    const fieldValue = values[fieldName];
                                    fieldObj.value = fieldValue !== undefined && fieldValue !== null ? fieldValue : '';
                                    return JSON.stringify(fieldObj);
                                  } catch (e) {
                                    return fieldString;
                                  }
                                });
                                formDataString = JSON.stringify({
                                  id: taskDetailData.formId ?? taskDetailData.id,
                                  name: taskDetailData.nodeName || taskDetailData.workName || '未知',
                                  conf: originalConf,
                                  fields: fieldsWithValues
                                });
                              }
                              const params: UpdateNodeApprovalParam = {
                                nodeId: numNodeId,
                                approvalStatus: 'rejected',
                                approvalOpinion: approvalComment || undefined,
                                formData: formDataString,
                              };
                              await myTaskApi.updateNodeApproval(params);
                              message.success(t('form.reviewRejectSuccess'));
                              setTaskDetailVisible(false);
                              setTaskDetailData(null);
                              setFormData({ rule: [], option: {} });
                              setFormLoading(false);
                              setOriginalFields([]);
                              setOriginalConf('');
                              taskDetailForm.resetFields();
                              setApprovalComment('');
                              fetchAllData();
                            } catch (error: any) {
                              message.error(error?.message || t('form.reviewRejectFailed'));
                            } finally {
                              setApprovalLoading(false);
                            }
                          }}
                        >
                          {t('form.reviewReject')}
                        </Button>
                        <Button
                          type="primary"
                          loading={approvalLoading}
                          disabled={isApproved}
                          onClick={async () => {
                            const nodeId = taskDetailData.nodeId ?? taskDetailData.id;
                            if (nodeId == null) {
                              message.warning(t('cockpit.nodeIdNotExist'));
                              return;
                            }
                            const numNodeId = typeof nodeId === 'number' ? nodeId : Number(nodeId);
                            if (isNaN(numNodeId)) {
                              message.warning(t('cockpit.nodeIdInvalid'));
                              return;
                            }
                            if (formData.rule && formData.rule.length > 0) {
                              try {
                                await taskDetailForm.validateFields();
                              } catch (err: any) {
                                if (err?.errorFields?.length) {
                                  message.error(err.errorFields[0]?.errors?.[0] || '请完善表单内容');
                                } else {
                                  message.error('请完善表单内容');
                                }
                                return;
                              }
                            }
                            setApprovalLoading(true);
                            try {
                              let formDataString: string | undefined;
                              if (formData.rule?.length && originalFields.length > 0) {
                                const values = taskDetailForm.getFieldsValue();
                                const fieldsWithValues = originalFields.map((fieldString: string) => {
                                  try {
                                    const fieldObj = JSON.parse(fieldString);
                                    const fieldName = fieldObj.name || fieldObj.field;
                                    const fieldValue = values[fieldName];
                                    fieldObj.value = fieldValue !== undefined && fieldValue !== null ? fieldValue : '';
                                    return JSON.stringify(fieldObj);
                                  } catch (e) {
                                    return fieldString;
                                  }
                                });
                                formDataString = JSON.stringify({
                                  id: taskDetailData.formId ?? taskDetailData.id,
                                  name: taskDetailData.nodeName || taskDetailData.workName || '未知',
                                  conf: originalConf,
                                  fields: fieldsWithValues
                                });
                              }
                              const params: UpdateNodeApprovalParam = {
                                nodeId: numNodeId,
                                approvalStatus: 'approved',
                                approvalOpinion: approvalComment || undefined,
                                formData: formDataString,
                              };
                              await myTaskApi.updateNodeApproval(params);
                              message.success(t('form.reviewApproveSuccess'));
                              setTaskDetailVisible(false);
                              setTaskDetailData(null);
                              setFormData({ rule: [], option: {} });
                              setFormLoading(false);
                              setOriginalFields([]);
                              setOriginalConf('');
                              taskDetailForm.resetFields();
                              setApprovalComment('');
                              fetchAllData();
                            } catch (error: any) {
                              message.error(error?.message || t('form.reviewApproveFailed'));
                            } finally {
                              setApprovalLoading(false);
                            }
                          }}
                        >
                          {t('form.reviewApprove')}
                        </Button>
                      </div>
                    </div>
                  );
                }

                // 其他节点类型（录入信息等）- 与审核节点统一样式：渐变背景、无内置白框
                return (
                  <div style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
                    <div style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: '24px', background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)' }}>
                      <div style={{ width: '100%' }}>
                      {/* 自定义表单：仅当前节点有 formId 时渲染 */}
                      {formLoading ? (
                        <div className="py-8 text-center text-gray-500">{t('cockpit.formLoading')}</div>
                      ) : hasFormIdForCurrentNode && formData.rule && formData.rule.length > 0 ? (
                        <div className="space-y-4">
                          {(() => {
                            const formConfig = formData.option?.formConfig || defaultFormConfig;
                            const layoutColumns = formConfig.layoutColumns || 1;
                            const gridStyle = layoutColumns > 1 ? {
                              display: 'grid',
                              gridTemplateColumns: `repeat(${layoutColumns}, minmax(0, 1fr))`,
                              gap: '12px',
                              rowGap: '16px',
                            } : undefined;
                            
                            return (
                              <AntdForm
                                form={taskDetailForm}
                                layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                                size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                                requiredMark={formConfig.hideRequiredMark ? false : undefined}
                                labelCol={
                                  formConfig.labelPosition === 'top' || !formConfig.labelWidth
                                    ? undefined
                                    : {
                                        flex: `${formConfig.labelWidth}px`,
                                        style: {
                                          minWidth: `${formConfig.labelWidth}px`,
                                          textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
                                        },
                                      }
                                }
                                wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                              >
                                <div 
                                  style={gridStyle} 
                                  className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}
                                >
                                  <style>{`
                                    .form-detail-grid .ant-form-item { margin-bottom: 12px; }
                                    .form-detail-grid .ant-form-item-control { min-width: 0; }
                                  `}</style>
                                  {(formData.rule || []).map((field: any) => {
                                    const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;
                                    return renderFieldPreview(fieldWithDisabled);
                                  })}
                                </div>
                              </AntdForm>
                            );
                          })()}
                        </div>
                      ) : (
                        <div
                          style={{
                            flex: 1,
                            minHeight: 0,
                            overflow: 'hidden',
                            display: 'flex',
                            alignItems: 'center',
                            justifyContent: 'center',
                            padding: '24px',
                            background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)',
                          }}
                        >
                          <div style={{ width: '100%', textAlign: 'center', padding: '24px 0' }}>
                            <div style={{ marginBottom: 24 }}>
                              <span
                                style={{
                                  width: 88,
                                  height: 88,
                                  borderRadius: 20,
                                  background: 'linear-gradient(135deg, #52c41a 0%, #73d13d 50%, #95de64 100%)',
                                  display: 'inline-flex',
                                  alignItems: 'center',
                                  justifyContent: 'center',
                                  boxShadow: '0 8px 24px rgba(82, 196, 26, 0.35)',
                                }}
                              >
                                <CheckCircleOutlined style={{ fontSize: 42, color: '#fff' }} />
                              </span>
                            </div>
                            <div style={{ fontSize: 18, fontWeight: 600, color: '#1f2937', lineHeight: 1.6 }}>
                              无需填写表单，直接点击底部按钮提交即可
                            </div>
                            <div style={{ marginTop: 12, fontSize: 13, color: '#69b1ff' }}>
                              确认无误后点击「完成」结束本节点
                            </div>
                          </div>
                        </div>
                      )}
                      </div>
                    </div>
                    {/* 底部按钮 - 取消 + 提交/完成 */}
                    <div
                      className="flex justify-end gap-3"
                      style={{
                        padding: '20px 24px',
                        borderTop: '1px solid rgba(22, 119, 255, 0.1)',
                        flexShrink: 0,
                        background: 'linear-gradient(0deg, #f0f7ff 0%, #fafcff 60%, #fff 100%)',
                      }}
                    >
                      <Button
                        onClick={() => {
                          setTaskDetailVisible(false);
                          setTaskDetailData(null);
                          setFormData({ rule: [], option: {} });
                          setOriginalFields([]);
                          setOriginalConf('');
                          taskDetailForm.resetFields();
                        }}
                        style={{ minWidth: 120, height: 44, borderRadius: 10, fontSize: 15, fontWeight: 500 }}
                      >
                        {t('common.cancel')}
                      </Button>
                      <Button
                        type="primary"
                        loading={submitLoading}
                        disabled={isApproved}
                        onClick={async () => {
                          const nodeId = taskDetailData.nodeId ?? taskDetailData.id;
                          if (nodeId == null) {
                            message.warning(t('cockpit.nodeIdNotExist'));
                            return;
                          }
                          const numNodeId = typeof nodeId === 'number' ? nodeId : Number(nodeId);
                          if (isNaN(numNodeId)) {
                            message.warning(t('cockpit.nodeIdInvalid'));
                            return;
                          }
                          setSubmitLoading(true);
                          try {
                            const values = formData.rule?.length ? await taskDetailForm.validateFields() : {};
                            const fieldsWithValues = originalFields.map((fieldString: string) => {
                              try {
                                const fieldObj = JSON.parse(fieldString);
                                const fieldName = fieldObj.name || fieldObj.field;
                                const fieldValue = values[fieldName];
                                fieldObj.value = fieldValue !== undefined && fieldValue !== null ? fieldValue : '';
                                return JSON.stringify(fieldObj);
                              } catch (e) {
                                return fieldString;
                              }
                            });
                            const submitData = {
                              id: taskDetailData.formId ?? taskDetailData.id,
                              name: taskDetailData.nodeName || taskDetailData.workName || '未知',
                              conf: originalConf,
                              fields: fieldsWithValues
                            };
                            const formDataString = JSON.stringify(submitData);
                            const params: UpdateNodeApprovalParam = {
                              nodeId: numNodeId,
                              approvalStatus: 'approved',
                              approvalOpinion: undefined,
                              formData: formDataString
                            };
                            await myTaskApi.updateNodeApproval(params);
                            const nodeType = String(taskDetailData?.type || taskDetailData?.nodeType || '').trim();
                            const isComplete = nodeType === 'complete';
                            message.success(isComplete ? t('form.completeSuccess') : t('common.submit') + t('common.success'));
                            setTaskDetailVisible(false);
                            setTaskDetailData(null);
                            setFormData({ rule: [], option: {} });
                            setFormLoading(false);
                            setOriginalFields([]);
                            setOriginalConf('');
                            taskDetailForm.resetFields();
                            fetchAllData();
                          } catch (error: any) {
                            if (error?.errorFields) {
                              message.error('请填写完整的表单内容');
                            } else {
                              message.error(error?.message || '提交失败');
                            }
                          } finally {
                            setSubmitLoading(false);
                          }
                        }}
                        style={{ minWidth: 120, height: 44, borderRadius: 10, fontSize: 15, fontWeight: 500, boxShadow: '0 4px 14px rgba(22, 119, 255, 0.35)' }}
                      >
                        {(() => {
                          const nodeType = String(taskDetailData?.type || taskDetailData?.nodeType || '').trim();
                          return nodeType === 'complete' ? t('form.complete') : t('common.submit');
                        })()}
                      </Button>
                    </div>
                  </div>
                );
              })()}
            </div>
          </div>
        ) : null}
      </Modal>
    </div>
  );
}
