'use client';

import { useState, useEffect, useCallback } from 'react';
import dynamic from 'next/dynamic';
import { useRouter, useSearchParams } from 'next/navigation';
import { useAuthGuard } from '@/hooks/useAuthGuard';
import { useAuth } from '@/lib/auth';
import { useTranslation } from '@/hooks/useTranslation';
import { FormRenderer } from '@features/forms/components/FormRenderer';
import { ApprovalTimeline } from '@/components/ApprovalTimeline';
import { UserSelector, type UserInfo } from '@/components/UserSelector';
import { mapApprovalHistoryToNodeStatuses } from '@/features/approval/utils/status-mapper';
import { PageState } from '@/components/common/feedback/PageState';
import type { HistoryItem, InstanceStatus } from '@/types/approval';
import { getDesignData, getFormDefinitionByKey, getFormInstance } from '@/services/api/form-management';
import { 
  getMyPendingTasks, 
  getMyInitiatedProcesses,
  getMyProcessedTasks,
  getMyCCTasks,
  approveTask,
  rejectTask,
  withdrawApproval,
  forwardTask,
  getApprovalHistory,
  getAdminInstances,
  type AdminInstanceItem,
  adminTerminateProcess,
  adminApproveTask,
  adminRejectTask,
  adminReassignTask,
  adminResumeWithApprovers,
  type ApprovalTaskItem,
  type ProcessInstanceItem
} from '@/services/api/approval';
import { AdminAnalyticsPanel } from '@/features/approval/components/AdminAnalyticsPanel';
import { ApprovalActions } from '@/features/approval/components/ApprovalActions';
import { 
  getFormDefinitions,
  type FormDefinition
} from '@/services/api/form-management';
import { 
  Clock, 
  FileText, 
  CheckCircle,
  Check,
  Mail, 
  ChevronDown,
  Search,
  Filter,
  AlertCircle,
  AlertTriangle,
  User,
  Calendar,
  Loader2,
  Plus,
  Car,
  DollarSign,
  ShoppingCart,
  Plane,
  Users,
  X,
  XCircle,
  RotateCcw,
  ArrowRightCircle,
  Send,
  UserPlus,
  UserCog,
  ShieldAlert,
  Workflow
} from 'lucide-react';
import { toast } from '@/lib/toast';
import { formatDate } from '@/utils/format';

// 动态导入流程预览组件
const LarkProcessPreview = dynamic(
  () => import('@/features/approval/designer/LarkProcessPreview').then(mod => ({ default: mod.LarkProcessPreview })),
  { ssr: false }
);

// ============================================
// 类型定义
// ============================================

type TabType = 'submit' | 'pending' | 'initiated' | 'processed' | 'cc' | 'admin';
type AdminViewType = 'processing' | 'analytics';

interface ApprovalItem {
  id: string;
  title: string;
  businessType: string;
  formKey?: string;
  submitter: {
    id: string;
    name: string;
    avatar?: string;
  };
  submitTime: string;
  status: string;
  currentNode?: string;
  priority?: number;
  // 原始数据
  raw: ApprovalTaskItem | ProcessInstanceItem | AdminInstanceItem;
}

interface ApprovalHistoryNode {
  nodeId: string;
  nodeName: string;
  nodeType: string;
  status: string;
  startTime: string;
  endTime?: string;
  tasks: Array<{
    id: string;
    assignee?: {
      id: string;
      name: string;
      displayName?: string;
      avatar?: string;
    };
    status: string;
    autoApproved: boolean;
    autoApproveReason?: string;
    actions: Array<{
      id: string;
      action: string;
      operator: {
        id: string;
        name: string;
        displayName?: string;
      };
      comment?: string;
      actionTime: string;
    }>;
  }>;
}

interface ApprovalDetail {
  id: string;
  title: string;
  businessType: string;
  formKey?: string;
  formData?: Record<string, any>;
  formSchema?: any;
  formUiSchema?: any;
  submitter: {
    id: string;
    name: string;
    avatar?: string;
  };
  submitTime: string;
  status: string;
  currentNode?: string;
  workflowId?: string;
  canApprove: boolean;
  canReject: boolean;
  history?: ApprovalHistoryNode[];  // 审批历史
  processVersion?: {  // 流程模型
    id: string;
    version: number;
    model: {
      nodes: any[];
      edges: any[];
    };
  };
  calculatedProcess?: {  // ⭐ 新增：动态计算后的流程（包含实际审批人）
    model: {
      nodes: any[];
      edges: any[];
    };
    initiator?: {
      id: string;
      name: string;
      avatar?: string;
    };
  };
  endReason?: string;  // ⭐ 新增：流程终止原因（撤回/拒绝/终止）
}

// ============================================
// 主组件
// ============================================

export default function ApprovalCenterPage() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const { isReady } = useAuthGuard();
  const { hasPermission, hasRole } = useAuth();
  const { t, locale } = useTranslation();
  
  // 只有 Administrator 角色才能看到管理员入口
  const isAdmin = hasRole('Administrator');

  // 从URL参数读取默认标签（如果有）
  const tabFromUrl = searchParams.get('tab') as TabType | null;
  const adminViewFromUrl = searchParams.get('view') as AdminViewType | null;
  const validTabs: TabType[] = ['submit', 'pending', 'initiated', 'processed', 'cc', 'admin'];
  const defaultTab = (tabFromUrl && validTabs.includes(tabFromUrl) && (tabFromUrl !== 'admin' || isAdmin))
    ? tabFromUrl
    : 'submit';
  const defaultAdminView: AdminViewType = adminViewFromUrl === 'analytics' ? 'analytics' : 'processing';

  // ========== 状态管理 ==========
  const [activeTab, setActiveTab] = useState<TabType>(defaultTab);
  const [adminView, setAdminView] = useState<AdminViewType>(defaultAdminView);
  const [selectedFormKey, setSelectedFormKey] = useState<string>('all');
  const [searchTerm, setSearchTerm] = useState('');

  // 列表数据
  const [items, setItems] = useState<ApprovalItem[]>([]);
  const [selectedItem, setSelectedItem] = useState<ApprovalItem | null>(null);
  const [loading, setLoading] = useState(true);
  
  // 详情数据
  const [detail, setDetail] = useState<ApprovalDetail | null>(null);
  const [detailLoading, setDetailLoading] = useState(false);
  
  // 审批操作
  const [approving, setApproving] = useState(false);
  const [rejecting, setRejecting] = useState(false);
  const [comment, setComment] = useState('');

  // 撤回操作
  const [withdrawing, setWithdrawing] = useState(false);
  const [withdrawDialogOpen, setWithdrawDialogOpen] = useState(false);
  const [withdrawItem, setWithdrawItem] = useState<ApprovalItem | null>(null);
  const [withdrawReason, setWithdrawReason] = useState('');

  // 转交操作
  const [forwarding, setForwarding] = useState(false);
  const [forwardDialogOpen, setForwardDialogOpen] = useState(false);
  const [forwardComment, setForwardComment] = useState('');
  const [forwardTargetUser, setForwardTargetUser] = useState<UserInfo | null>(null);
  const [userSelectorOpen, setUserSelectorOpen] = useState(false);

  // 管理员操作
  const [adminActionType, setAdminActionType] = useState<'terminate' | 'approve' | 'reject' | 'reassign' | 'resume' | null>(null);
  const [adminReason, setAdminReason] = useState('');
  const [adminComment, setAdminComment] = useState('');
  // ERR-20260501-004 配套：恢复挂起流程时填入的审批人 UUID 列表（逗号或换行分隔）
  const [adminApproverIdsRaw, setAdminApproverIdsRaw] = useState('');
  const [adminProcessing, setAdminProcessing] = useState(false);
  const [adminTargetUser, setAdminTargetUser] = useState<UserInfo | null>(null);
  const [adminUserSelectorOpen, setAdminUserSelectorOpen] = useState(false);

  // 提交请求页面数据
  const [allForms, setAllForms] = useState<FormDefinition[]>([]);
  const [recentForms, setRecentForms] = useState<FormDefinition[]>([]);

  useEffect(() => {
    if (!isReady) return;
    if (!isAdmin && activeTab === 'admin') {
      setActiveTab('submit');
      setAdminView('processing');
      const params = new URLSearchParams(searchParams.toString());
      params.set('tab', 'submit');
      params.delete('view');
      router.replace(`/approval-center?${params.toString()}`);
    }
  }, [activeTab, isAdmin, isReady, router, searchParams]);

  useEffect(() => {
    if (!isReady) return;
    const urlTab = searchParams.get('tab') as TabType | null;
    if (!urlTab || !validTabs.includes(urlTab)) return;
    if (urlTab === 'admin') {
      if (!isAdmin) return;
      if (activeTab !== 'admin') {
        setActiveTab('admin');
      }
      const urlView = searchParams.get('view') as AdminViewType | null;
      const nextView: AdminViewType = urlView === 'analytics' ? 'analytics' : 'processing';
      if (adminView !== nextView) {
        setAdminView(nextView);
      }
      return;
    }
    if (activeTab !== urlTab) {
      setActiveTab(urlTab);
    }
  }, [activeTab, adminView, isAdmin, isReady, searchParams]);

  // ========== 辅助函数 ==========
  
  // 判断流程是否已结束
  const isProcessEnded = (status: string) => {
    return ['APPROVED', 'REJECTED', 'WITHDRAWN', 'TERMINATED', 'FAILED'].includes(status);
  };
  const [formsLoading, setFormsLoading] = useState(false);
  const [selectedCategory, setSelectedCategory] = useState<string>('');

  // Tab 数量统计
  const [tabCounts, setTabCounts] = useState({
    pending: 0,
    initiated: 0,
    processed: 0,
    cc: 0,
    admin: 0,
  });

  // ========== 数据加载 ==========
  useEffect(() => {
    if (!isReady) return;
    if (activeTab === 'submit') {
      loadForms(); // 加载表单列表
    } else if (activeTab === 'admin' && adminView === 'analytics') {
      setItems([]);
      setSelectedItem(null);
      setDetail(null);
      setLoading(false);
    } else {
      loadItems(); // 加载审批数据
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isReady, activeTab, adminView]);

  // 初始化时加载所有 tab 的数量
  useEffect(() => {
    if (!isReady) return;
    loadAllTabCounts();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isReady]);

  // 处理 URL 参数中的 instanceId（从管理员页面跳转过来）
  useEffect(() => {
    if (!isReady) return;
    const instanceId = searchParams.get('instanceId');
    if (instanceId && items.length > 0) {
      // 查找对应的审批项
      const targetItem = items.find(item => item.id === instanceId);
      if (targetItem) {
        setSelectedItem(targetItem);
        // 自动加载详情
        loadDetail(targetItem);
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isReady, searchParams, items]);

  const loadAllTabCounts = async () => {
    try {
      // 并行加载所有 tab 的数量
      const requests = [
        getMyPendingTasks({ limit: 1 }).catch(() => ({ total: 0, items: [] })),
        getMyInitiatedProcesses({ limit: 1 }).catch(() => ({ total: 0, items: [] })),
        getMyProcessedTasks({ limit: 1 }).catch(() => ({ total: 0, items: [] })),
        getMyCCTasks({ limit: 1 }).catch(() => ({ total: 0, items: [] })),
      ];

      // 只有管理员才加载admin tab计数
      if (isAdmin) {
        requests.push(
          getAdminInstances({ status: 'RUNNING', approvalRequired: true, limit: 1 }).catch(() => ({ total: 0, items: [] }))
        );
      }

      const results = await Promise.all(requests);
      const [pendingRes, initiatedRes, processedRes, ccRes, adminRes] = results;

      setTabCounts({
        pending: pendingRes.total || 0,
        initiated: initiatedRes.total || 0,
        processed: processedRes.total || 0,
        cc: ccRes.total || 0,
        admin: adminRes?.total || 0,
      });
    } catch (error) {
      console.error('[ApprovalCenter] Load tab counts error:', error);
    }
  };

  const loadForms = async () => {
    try {
      setFormsLoading(true);
      
      // 加载所有表单（按创建时间倒序，最新的在前面）
      const allRes = await getFormDefinitions({ 
        forUse: true, 
        status: 'PUBLISHED',
        limit: 100 
      });
      
      // 取前 5 个作为最近表单
      const recentRes = allRes.items.slice(0, 5);
      
      console.log('[ApprovalCenter] Loaded forms:', {
        total: allRes.items.length,
        recent: recentRes.length,
      });
      
      setRecentForms(recentRes);
      setAllForms(allRes.items);
      
      // 默认选中第一个分类
      if (allRes.items.length > 0) {
        const categories = getCategoryGroups(allRes.items);
        if (categories.length > 0) {
          setSelectedCategory(categories[0].name);
        }
      }
    } catch (error) {
      console.error('[ApprovalCenter] Load forms error:', error);
      toast.error(t.common.error);
    } finally {
      setFormsLoading(false);
    }
  };

  const loadItems = async () => {
    try {
      setLoading(true);
      setSelectedItem(null);
      setDetail(null);
      
      let response: any;
      
      switch (activeTab) {
        case 'pending':
          response = await getMyPendingTasks({ limit: 100 });
          setItems(mapPendingToItems(response.items));
          setTabCounts(prev => ({ ...prev, pending: response.total || response.items.length }));
          break;
        case 'initiated':
          response = await getMyInitiatedProcesses({ limit: 100 });
          setItems(mapInitiatedToItems(response.items));
          setTabCounts(prev => ({ ...prev, initiated: response.total || response.items.length }));
          break;
        case 'processed':
          response = await getMyProcessedTasks({ limit: 100 });
          setItems(mapProcessedToItems(response.items));
          setTabCounts(prev => ({ ...prev, processed: response.total || response.items.length }));
          break;
        case 'cc':
          response = await getMyCCTasks({ limit: 100 });
          setItems(mapCCToItems(response.items));
          setTabCounts(prev => ({ ...prev, cc: response.total || response.items.length }));
          break;
        case 'admin':
          if (adminView !== 'processing') {
            setItems([]);
            break;
          }
          // 管理员：查看所有运行中 + 挂起的审批流程（SUSPENDED 来自 ERR-20260501-004：审批人解析失败时挂起等管理员介入）
          {
            const [runningRes, suspendedRes] = await Promise.all([
              getAdminInstances({ status: 'RUNNING', approvalRequired: true, limit: 100 }),
              getAdminInstances({ status: 'SUSPENDED', approvalRequired: true, limit: 100 }),
            ]);
            const merged = [...suspendedRes.items, ...runningRes.items];
            setItems(mapAdminToItems(merged));
            setTabCounts(prev => ({
              ...prev,
              admin: (runningRes.total ?? runningRes.items.length) + (suspendedRes.total ?? suspendedRes.items.length),
            }));
          }
          break;
      }
    } catch (error) {
      console.error('[ApprovalCenter] Load items error:', error);
      toast.error(t.common.error);
    } finally {
      setLoading(false);
    }
  };

  // 加载详情
  const loadDetail = useCallback(async (item: ApprovalItem) => {
    try {
      setDetailLoading(true);
      setDetail(null);
      
      const raw = item.raw as any;
      
      console.log('='.repeat(80));
      console.log('[ApprovalCenter] 📋 开始加载审批详情');
      console.log('='.repeat(80));
      console.log('[ApprovalCenter] 1️⃣ 选中的审批项:', {
        id: item.id,
        title: item.title,
        businessType: item.businessType,
        formKey: item.formKey,
        status: item.status,
        currentNode: item.currentNode,
      });
      console.log('[ApprovalCenter] 2️⃣ 原始数据 (raw):', raw);
      
      // 获取表单设计数据
      let formSchema = null;
      let formUiSchema = null;
      let formData = null;
      let processVersion = null;  // ⭐ 新增：流程模型
      
      if (item.formKey) {
        try {
          console.log('[ApprovalCenter] 3️⃣ 查询表单定义，formKey =', item.formKey);
          
          const formDef = await getFormDefinitionByKey(item.formKey);
          console.log('[ApprovalCenter] 4️⃣ 获取到表单定义:', formDef);
          
          const designData = await getDesignData(formDef.id);
          console.log('[ApprovalCenter] 5️⃣ 获取到设计数据:', {
            formDefinition: designData.formDefinition,
            formVersion: {
              id: designData.formVersion?.id,
              version: designData.formVersion?.version,
              hasSchema: !!designData.formVersion?.schema,
              hasUiSchema: !!designData.formVersion?.uiSchema,
              schema: designData.formVersion?.schema,
              uiSchema: designData.formVersion?.uiSchema,
            },
            processVersion: {
              id: designData.processVersion?.id,
              version: designData.processVersion?.version,
            },
          });
          
          formSchema = designData.formVersion?.schema;
          formUiSchema = designData.formVersion?.uiSchema;
          processVersion = designData.processVersion;  // ⭐ 存储流程版本
          
          console.log('[ApprovalCenter] 6️⃣ 提取的 Schema:', {
            hasSchema: !!formSchema,
            hasUiSchema: !!formUiSchema,
            hasProcessVersion: !!processVersion,
          });
        } catch (error) {
          console.error('[ApprovalCenter] ❌ 加载表单设计失败:', error);
          // 如果无法获取表单设计，继续显示其他信息
        }
      } else {
        console.warn('[ApprovalCenter] ⚠️ formKey 为空，跳过加载表单设计');
      }
      
      // 获取表单数据
      // 根据架构设计，表单数据存储在 FormInstance.data 中，而不是 workflow variables
      // 需要通过 businessId (FormInstance.id) 获取
      if (item.businessType === 'FORM_INSTANCE' && item.businessType !== item.formKey) {
        // businessId 是表单实例的 ID
        const businessId = raw.businessId || raw.businessInstanceId || (raw.instance as any)?.businessId;
        if (businessId) {
          try {
            console.log('[ApprovalCenter] 7️⃣ 通过 businessId 获取表单实例数据:', businessId);
            const formInstanceData = await getFormInstance(businessId);
            console.log('[ApprovalCenter] 8️⃣ 获取到表单实例:', formInstanceData);
            formData = formInstanceData.data;
            console.log('[ApprovalCenter] 9️⃣ 提取的表单数据:', formData);
          } catch (error) {
            console.error('[ApprovalCenter] ❌ 获取表单实例失败:', error);
          }
        } else {
          console.warn('[ApprovalCenter] ⚠️ businessId 为空');
        }
      }
      
      // 降级方案：尝试从 workflow variables 读取（可能为空）
      if (!formData && raw.variables?.formData) {
        formData = raw.variables.formData;
        console.log('[ApprovalCenter] 🔄 从 workflow 变量中获取到表单数据 (降级):', formData);
      }
      
      if (!formData) {
        console.warn('[ApprovalCenter] ⚠️ 未能获取到表单数据');
        console.log('[ApprovalCenter] raw =', raw);
      }
      
      // 加载审批历史
      let approvalHistory: ApprovalHistoryNode[] | undefined;
      let latestStatus = item.status; // 默认使用列表项状态
      let endReason: string | undefined; // ⭐ 新增：流程终止原因（撤回/拒绝/终止）
      const instanceId = raw.instanceId || raw.workflowId;
      if (instanceId) {
        try {
          console.log('[ApprovalCenter] 🔟 加载审批历史, instanceId =', instanceId);
          const historyResponse = await getApprovalHistory(instanceId);
          approvalHistory = historyResponse.items;
          endReason = historyResponse.endReason; // ⭐ 获取终止原因
          console.log('[ApprovalCenter] ✅ 审批历史加载完成:', approvalHistory);
          
          // ⭐ 从审批历史响应中获取最新的流程状态和终止原因
          if (historyResponse.status) {
            latestStatus = historyResponse.status;
            console.log('[ApprovalCenter] 📊 从审批历史获取到最新状态:', latestStatus);
          }
          if (endReason) {
            console.log('[ApprovalCenter] 📝 获取到流程终止原因:', endReason);
          }
          
          // ⭐ 只在应该显示流程状态的 Tab 中同步更新列表项
          // "待我审批" Tab 应该显示任务状态，不应该被流程状态覆盖
          // "我提交的"/"我审批的" 等 Tab 应该显示流程状态，需要同步更新
          const shouldUpdateListStatus = activeTab !== 'pending';
          
          if (shouldUpdateListStatus) {
            setItems(prevItems => 
              prevItems.map(prevItem => 
                prevItem.id === item.id 
                  ? { ...prevItem, status: latestStatus }
                  : prevItem
              )
            );
            console.log('[ApprovalCenter] ✅ 已同步更新列表项状态');
          } else {
            console.log('[ApprovalCenter] ℹ️ 待我审批Tab不更新列表状态（保持任务状态）');
          }
        } catch (error) {
          console.error('[ApprovalCenter] ❌ 加载审批历史失败:', error);
          // 审批历史加载失败不影响其他内容显示
        }
      }
      
      // ⭐ 动态计算审批人
      let calculatedProcess = null;
      if (processVersion && formData) {
        try {
          console.log('[ApprovalCenter] 🔄 开始动态计算审批人');
          const formDef = await getFormDefinitionByKey(item.formKey!);
          
          // ⭐ 重要：需要传递表单提交人的ID，而不是当前登录用户的ID
          // 因为审批人是基于提交人计算的（如"提交人的上级"）
          // raw.initiator 在审批流程中就是表单的提交人
          const submitterId = raw.initiator?.id || raw.submitter?.id;
          console.log('[ApprovalCenter] 📌 表单提交人:', {
            'submitterId': submitterId,
            'raw.initiator': raw.initiator,
            'raw.submitter': raw.submitter,
          });
          
          // 调用预览API计算实际审批人
          const previewResponse = await import('@/services/api/form-management').then(mod => 
            mod.previewProcessWithApprovers(formDef.id, {
              formData,
              departmentId: raw.departmentId || null,
              initiatorId: submitterId,  // ⭐ 传递表单提交人的ID
            })
          );
          
          calculatedProcess = previewResponse;
          console.log('[ApprovalCenter] ✅ 审批人计算完成:', calculatedProcess);
        } catch (error) {
          console.error('[ApprovalCenter] ❌ 计算审批人失败:', error);
          // 计算失败不影响显示，将使用原始流程模型
        }
      }
      
      const detailData: ApprovalDetail = {
        id: item.id,
        title: item.title,
        businessType: item.businessType,
        formKey: item.formKey,
        formData,
        formSchema,
        formUiSchema,
        submitter: item.submitter,
        submitTime: item.submitTime,
        status: latestStatus,  // ⭐ 使用最新状态
        currentNode: item.currentNode,
        workflowId: instanceId,  // ⭐ 使用 instanceId（审批实例ID）
        canApprove: activeTab === 'pending',
        canReject: activeTab === 'pending',
        history: approvalHistory,  // ⭐ 审批历史
        processVersion,  // ⭐ 流程模型
        calculatedProcess,  // ⭐ 新增：动态计算后的流程
        endReason,  // ⭐ 新增：流程终止原因（撤回/拒绝/终止）
      };
      
      console.log('[ApprovalCenter] 🔟 最终组装的详情数据:', detailData);
      console.log('='.repeat(80));
      console.log('[ApprovalCenter] ✅ 审批详情加载完成');
      console.log('='.repeat(80));
      
      setDetail(detailData);
    } catch (error) {
      console.error('[ApprovalCenter] ❌ 加载详情出错:', error);
      toast.error(t.common.error);
    } finally {
      setDetailLoading(false);
    }
  }, [activeTab, t.common.error]);

  // 选中项变化时加载详情
  useEffect(() => {
    if (selectedItem) {
      loadDetail(selectedItem);
    }
  }, [selectedItem, loadDetail]);

  // ========== 审批操作 ==========
  const handleApprove = async () => {
    console.log('[ApprovalCenter] 🟢 handleApprove 开始执行');
    console.log('[ApprovalCenter] detail:', detail);
    console.log('[ApprovalCenter] detail.workflowId:', detail?.workflowId);
    
    if (!detail || !detail.workflowId) {
      console.error('[ApprovalCenter] ❌ detail 或 workflowId 缺失');
      toast.error(locale === 'zh' ? '审批实例ID缺失，无法执行审批' : 'Instance ID missing');
      return;
    }
    
    const raw = selectedItem?.raw as any;
    const taskId = raw?.taskId || raw?.id;
    
    console.log('[ApprovalCenter] taskId:', taskId);
    console.log('[ApprovalCenter] raw:', raw);
    
    if (!taskId) {
      toast.error(locale === 'zh' ? '任务ID缺失' : 'Task ID missing');
      return;
    }
    
    try {
      setApproving(true);
      console.log('[ApprovalCenter] 📤 调用审批API:', {
        instanceId: detail.workflowId,
        taskId,
        comment: comment.trim() || undefined,
      });
      
      // ⭐ 方案2：API 返回最新状态
      const result = await approveTask(detail.workflowId, {
        taskId,
        comment: comment.trim() || undefined,
      });
      
      console.log('[ApprovalCenter] ✅ 审批成功，返回结果:', result);
      toast.success(t.approvals.approveSuccess || '审批通过');
      
      // ⭐ 审批成功后，总是关闭详情并刷新列表（因为当前任务已被处理）
      setSelectedItem(null);
      setDetail(null);
      
      // ⭐ 立即刷新列表和计数（不阻塞用户）
      loadItems();
      loadAllTabCounts();
      
      // ⭐ 延迟只刷新计数（不刷新列表，避免闪烁）
      setTimeout(() => {
        loadAllTabCounts();
        console.log('[ApprovalCenter] 🔄 审批后延迟刷新计数完成（500ms）');
      }, 500);
      
      console.log('[ApprovalCenter] ✅ 已关闭详情并触发列表刷新');
      
    } catch (error: any) {
      console.error('[ApprovalCenter] ❌ Approve error:', error);
      toast.error(error.message || t.approvals.approveFailed);
    } finally {
      setApproving(false);
      setComment('');
    }
  };

  const handleReject = async () => {
    console.log('[ApprovalCenter] 🔴 handleReject 开始执行');
    console.log('[ApprovalCenter] detail:', detail);
    console.log('[ApprovalCenter] detail.workflowId:', detail?.workflowId);
    
    if (!detail || !detail.workflowId) {
      console.error('[ApprovalCenter] ❌ detail 或 workflowId 缺失');
      toast.error(locale === 'zh' ? '审批实例ID缺失，无法执行审批' : 'Instance ID missing');
      return;
    }
    
    if (!comment.trim()) {
      toast.error(t.approvals.rejectReasonRequired || '请填写拒绝理由');
      return;
    }
    
    const raw = selectedItem?.raw as any;
    const taskId = raw?.taskId || raw?.id;
    
    console.log('[ApprovalCenter] taskId:', taskId);
    console.log('[ApprovalCenter] raw:', raw);
    
    if (!taskId) {
      toast.error(locale === 'zh' ? '任务ID缺失' : 'Task ID missing');
      return;
    }
    
    try {
      setRejecting(true);
      console.log('[ApprovalCenter] 📤 调用拒绝API:', {
        instanceId: detail.workflowId,
        taskId,
        comment: comment.trim(),
      });
      
      await rejectTask(detail.workflowId, {
        taskId,
        comment: comment.trim(),
      });
      
      console.log('[ApprovalCenter] ✅ 拒绝成功');
      toast.success(t.approvals.rejectSuccess || '已拒绝');
      
      // ⭐ 拒绝成功后，总是关闭详情并刷新列表（因为当前任务已被处理）
      setSelectedItem(null);
      setDetail(null);
      
      // ⭐ 立即异步刷新列表和计数（不阻塞用户）
      loadItems();
      loadAllTabCounts();
      
      // ⭐ 延迟只刷新计数（不刷新列表，避免闪烁）
      setTimeout(() => {
        loadAllTabCounts();
        console.log('[ApprovalCenter] 🔄 拒绝后延迟刷新计数完成（500ms）');
      }, 500);
      
      console.log('[ApprovalCenter] ✅ 已关闭详情并触发列表刷新');
    } catch (error: any) {
      console.error('[ApprovalCenter] ❌ Reject error:', error);
      toast.error(error.message || t.approvals.rejectFailed);
    } finally {
      setRejecting(false);
      setComment('');
    }
  };

  // ========== 撤回操作 ==========
  const handleWithdrawClick = (item: ApprovalItem, e: React.MouseEvent) => {
    e.stopPropagation(); // 防止触发列表项点击
    setWithdrawItem(item);
    setWithdrawDialogOpen(true);
  };

  const handleWithdrawConfirm = async () => {
    if (!withdrawItem) return;

    const raw = withdrawItem.raw as any;
    const instanceId = raw.instanceId || raw.id;

    if (!instanceId) {
      toast.error(locale === 'zh' ? '审批实例ID缺失' : 'Instance ID missing');
      return;
    }

    try {
      setWithdrawing(true);
      console.log('[ApprovalCenter] 🔄 撤回申请:', {
        instanceId,
        reason: withdrawReason,
      });

      const result = await withdrawApproval(instanceId, {
        reason: withdrawReason.trim() || undefined,
      });

      console.log('[ApprovalCenter] ✅ 撤回成功，返回结果:', result);
      toast.success(locale === 'zh' ? '已撤回申请' : 'Withdrawn successfully');

      // ⭐ 1. 使用API返回的状态立即更新列表项（避免重新加载列表）
      const newStatus = result.status || 'WITHDRAWN';
      setItems(prevItems => prevItems.map(item => 
        item.id === withdrawItem.id 
          ? { ...item, status: newStatus }
          : item
      ));
      console.log('[ApprovalCenter] ✅ 列表项状态已更新为:', newStatus);
      
      // 2. 如果当前选中项是撤回项，清除详情面板
      if (selectedItem?.id === withdrawItem.id) {
        setSelectedItem(null);
        setDetail(null);
      }

      // 3. 立即刷新计数（不刷新列表，避免闪烁）
      loadAllTabCounts();
      
      // 4. 延迟再刷新一次计数（确保Temporal完成）
      setTimeout(() => {
        loadAllTabCounts();
        console.log('[ApprovalCenter] 🔄 撤回后延迟刷新计数完成（500ms）');
      }, 500);

      // 5. 关闭对话框
      setWithdrawDialogOpen(false);
      setWithdrawItem(null);
      setWithdrawReason('');
    } catch (error: any) {
      console.error('[ApprovalCenter] ❌ Withdraw error:', error);
      toast.error(error.message || (locale === 'zh' ? '撤回失败' : 'Withdraw failed'));
    } finally {
      setWithdrawing(false);
    }
  };

  const handleWithdrawCancel = () => {
    setWithdrawDialogOpen(false);
    setWithdrawItem(null);
    setWithdrawReason('');
  };

  // ========== 转交操作 ==========
  const handleForwardClick = () => {
    setForwardDialogOpen(true);
  };

  // ⭐ 步骤1：用户选择目标用户（只保存，不提交）
  const handleUserSelected = (selectedUsers: UserInfo[]) => {
    if (selectedUsers.length === 0) {
      toast.error(locale === 'zh' ? '请选择转交目标' : 'Please select a target user');
      return;
    }

    const targetUser = selectedUsers[0]; // 单选模式，取第一个
    setForwardTargetUser(targetUser);
    setUserSelectorOpen(false); // 关闭用户选择器，回到转交对话框
  };

  // ⭐ 步骤2：确认转交（执行API调用）
  const handleForwardSubmit = async () => {
    if (!forwardTargetUser) {
      toast.error(locale === 'zh' ? '请选择转交目标' : 'Please select a target user');
      return;
    }

    if (!detail || !detail.workflowId) {
      toast.error(locale === 'zh' ? '审批实例ID缺失' : 'Instance ID missing');
      return;
    }

    const raw = selectedItem?.raw as any;
    const taskId = raw?.taskId || raw?.id;

    if (!taskId) {
      toast.error(locale === 'zh' ? '任务ID缺失' : 'Task ID missing');
      return;
    }

    try {
      setForwarding(true);
      console.log('[ApprovalCenter] 📤 转交审批:', {
        instanceId: detail.workflowId,
        taskId,
        toUserId: forwardTargetUser.id,
        comment: forwardComment,
      });

      await forwardTask(detail.workflowId, {
        taskId,
        toUserId: forwardTargetUser.id,
        comment: forwardComment.trim() || undefined,
      });

      console.log('[ApprovalCenter] ✅ 转交成功');
      toast.success(
        locale === 'zh' 
          ? `已转交给 ${forwardTargetUser.displayName}` 
          : `Forwarded to ${forwardTargetUser.displayName}`
      );

      // 1. 立即从列表中移除当前项
      if (selectedItem) {
        setItems(prevItems => prevItems.filter(item => item.id !== selectedItem.id));
        setSelectedItem(null);
        setDetail(null);
        // 更新计数：待审批-1
        setTabCounts(prev => ({
          ...prev,
          pending: Math.max(0, prev.pending - 1),
        }));
      }

      // 2. 关闭对话框并清空状态
      setForwardDialogOpen(false);
      setUserSelectorOpen(false);
      setForwardComment('');
      setForwardTargetUser(null);

      // 3. 延迟刷新列表
      setTimeout(async () => {
        console.log('[ApprovalCenter] 🔄 延迟刷新列表...');
        await loadItems();
      }, 800);
    } catch (error: any) {
      console.error('[ApprovalCenter] ❌ Forward error:', error);
      toast.error(error.message || (locale === 'zh' ? '转交失败' : 'Forward failed'));
    } finally {
      setForwarding(false);
    }
  };

  const handleForwardCancel = () => {
    setForwardDialogOpen(false);
    setUserSelectorOpen(false);
    setForwardComment('');
    setForwardTargetUser(null);
  };

  // ========== 管理员操作 ==========
  const handleAdminAction = async () => {
    if (!selectedItem || !adminActionType) return;

    if (!adminReason.trim()) {
      toast.error('请填写操作原因');
      return;
    }

    if (adminActionType === 'reassign' && !adminTargetUser) {
      toast.error('请选择目标审批人');
      return;
    }

    const raw = selectedItem.raw as any;
    const instanceId = raw.id || raw.instanceId;
    let taskId = raw.taskId;

    // 如果raw中没有taskId，尝试从detail的审批历史中获取当前pending的taskId
    if (!taskId && detail?.history) {
      for (const node of detail.history) {
        for (const task of node.tasks || []) {
          if (task.status === 'PENDING' || task.status === 'ASSIGNED') {
            taskId = task.id;
            console.log('[Admin] Found taskId from history:', taskId);
            break;
          }
        }
        if (taskId) break;
      }
    }

    console.log('[Admin] Operation:', {
      actionType: adminActionType,
      instanceId,
      taskId,
      hasDetail: !!detail,
    });

    try {
      setAdminProcessing(true);

      switch (adminActionType) {
        case 'terminate':
          await adminTerminateProcess(instanceId, { reason: adminReason });
          toast.success('已强制结束流程');
          break;

        case 'approve':
          if (!taskId) {
            toast.error('该流程当前没有待处理的审批任务，无法代审批');
            console.warn('[Admin] No taskId available for approve action');
            return;
          }
          await adminApproveTask(instanceId, {
            taskId,
            reason: adminReason,
            comment: adminComment || undefined
          });
          toast.success('已代审批通过');
          break;

        case 'reject':
          if (!taskId) {
            toast.error('该流程当前没有待处理的审批任务，无法代驳回');
            console.warn('[Admin] No taskId available for reject action');
            return;
          }
          await adminRejectTask(instanceId, {
            taskId,
            reason: adminReason,
            comment: adminComment || undefined
          });
          toast.success('已代审批驳回');
          break;

        case 'reassign':
          if (!taskId || !adminTargetUser) {
            toast.error(!taskId ? '该流程当前没有待处理的审批任务，无法重新分配' : '缺少目标审批人');
            console.warn('[Admin] No taskId or targetUser for reassign action');
            return;
          }
          await adminReassignTask(instanceId, {
            taskId,
            targetUserId: adminTargetUser.id,
            reason: adminReason
          });
          toast.success(`已重新分配给 ${adminTargetUser.displayName}`);
          break;

        case 'resume': {
          // ERR-20260501-004：恢复挂起的流程（审批人解析失败导致 SUSPENDED）
          // 输入 textarea 用逗号 / 换行分隔的 UUID 列表
          const approverIds = adminApproverIdsRaw
            .split(/[,\n]/)
            .map((s) => s.trim())
            .filter(Boolean);
          if (approverIds.length === 0) {
            toast.error('请至少填入一个审批人 UUID');
            return;
          }
          const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
          if (approverIds.some((id) => !uuidRegex.test(id))) {
            toast.error('审批人列表中含无效的 UUID');
            return;
          }
          await adminResumeWithApprovers(instanceId, { approverIds, reason: adminReason });
          toast.success(`已恢复挂起流程，指派 ${approverIds.length} 位审批人`);
          break;
        }
      }

      // 重置状态
      setAdminActionType(null);
      setAdminReason('');
      setAdminComment('');
      setAdminTargetUser(null);
      setAdminApproverIdsRaw('');

      // ⭐ 1. 先清空选中项（避免显示过时数据）
      setSelectedItem(null);
      setDetail(null);

      // ⭐ 2. 立即刷新一次
      await Promise.all([loadItems(), loadAllTabCounts()]);
      
      toast.success('操作成功，列表已刷新');
      
      // ⭐ 3. 延迟再刷新一次（保持与其他操作一致，800ms）
      setTimeout(async () => {
        console.log('[ApprovalCenter] 🔄 延迟刷新列表（管理员操作后）...');
        await loadItems();
        await loadAllTabCounts();
      }, 800);
      
      
    } catch (error: any) {
      toast.error('操作失败: ' + error.message);
    } finally {
      setAdminProcessing(false);
    }
  };

  const handleAdminCancel = () => {
    setAdminActionType(null);
    setAdminReason('');
    setAdminComment('');
    setAdminTargetUser(null);
    setAdminApproverIdsRaw('');
  };

  // ========== 筛选和搜索 ==========
  const filteredItems = items.filter(item => {
    const matchesSearch = !searchTerm || 
      item.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
      item.submitter.name.toLowerCase().includes(searchTerm.toLowerCase());
    
    const matchesForm = selectedFormKey === 'all' || item.formKey === selectedFormKey;
    
    return matchesSearch && matchesForm;
  });

  // 获取表单列表（用于筛选）
  const formKeys = Array.from(new Set(items.map(item => item.formKey).filter(Boolean))) as string[];

  // ========== 提交请求页面的数据处理 ==========
  
  // 图标映射
  const iconMap: Record<string, React.ReactNode> = {
    car: <Car className="w-5 h-5" />,
    dollar: <DollarSign className="w-5 h-5" />,
    shopping: <ShoppingCart className="w-5 h-5" />,
    clock: <Clock className="w-5 h-5" />,
    plane: <Plane className="w-5 h-5" />,
    calendar: <Calendar className="w-5 h-5" />,
    users: <Users className="w-5 h-5" />,
    file: <FileText className="w-5 h-5" />,
  };

  // 图标颜色映射
  const iconColorMap: Record<string, string> = {
    car: 'bg-orange-500',
    dollar: 'bg-blue-500',
    shopping: 'bg-blue-600',
    clock: 'bg-blue-500',
    plane: 'bg-green-500',
    calendar: 'bg-pink-500',
    users: 'bg-purple-500',
    file: 'bg-gray-500',
  };

  // 获取表单图标
  const getFormIcon = (form: FormDefinition) => {
    const iconKey = form.icon || 'file';
    return iconMap[iconKey] || iconMap.file;
  };

  // 获取表单图标颜色
  const getFormIconColor = (form: FormDefinition) => {
    const iconKey = form.icon || 'file';
    return iconColorMap[iconKey] || iconColorMap.file;
  };

  // 按分类分组
  interface CategoryGroup {
    name: string;
    forms: FormDefinition[];
  }

  const getCategoryGroups = (forms: FormDefinition[]): CategoryGroup[] => {
    const groupMap = new Map<string, FormDefinition[]>();
    
    forms.forEach(form => {
      const category = form.category || (locale === 'zh' ? '未分类' : 'Uncategorized');
      if (!groupMap.has(category)) {
        groupMap.set(category, []);
      }
      groupMap.get(category)!.push(form);
    });
    
    return Array.from(groupMap.entries()).map(([name, forms]) => ({
      name,
      forms,
    }));
  };

  // 搜索过滤表单
  const filteredForms = allForms.filter(form => {
    if (!searchTerm) return true;
    const term = searchTerm.toLowerCase();
    return (
      form.name.toLowerCase().includes(term) ||
      form.key.toLowerCase().includes(term) ||
      form.description?.toLowerCase().includes(term)
    );
  });

  // 推荐表单
  const recommendedForms = recentForms.slice(0, 6);

  // 获取分类列表
  const categoryGroups = getCategoryGroups(filteredForms);

  // 处理表单点击
  const handleFormClick = (form: FormDefinition) => {
    router.push(`/approval-center/submit/${form.key}`);
  };

  const updateTab = (tab: TabType) => {
    setActiveTab(tab);
    const params = new URLSearchParams(searchParams.toString());
    params.set('tab', tab);
    if (tab !== 'admin') {
      params.delete('view');
    }
    router.replace(`/approval-center?${params.toString()}`);
  };

  const updateAdminView = (view: AdminViewType) => {
    setAdminView(view);
    const params = new URLSearchParams(searchParams.toString());
    params.set('tab', 'admin');
    params.set('view', view);
    router.replace(`/approval-center?${params.toString()}`);
  };

  // ========== 渲染函数 ==========
  const renderTabs = () => {
    const tabs = [
      { key: 'submit' as TabType, label: locale === 'zh' ? '提交请求' : 'Submit Request', icon: Plus, color: 'text-[#3370ff]', count: undefined },
      { key: 'pending' as TabType, label: t.approvals.pendingMyApproval || '待我审批', icon: Clock, color: 'text-[#3370ff]', count: tabCounts.pending },
      { key: 'initiated' as TabType, label: t.approvals.myInitiated || '我提交的', icon: FileText, color: 'text-[#00b42a]', count: tabCounts.initiated },
      { key: 'processed' as TabType, label: t.approvals.myProcessed || '我审批的', icon: CheckCircle, color: 'text-[#722ed1]', count: tabCounts.processed },
      { key: 'cc' as TabType, label: t.approvals.ccToMe || '抄送我的', icon: Mail, color: 'text-[#ff7d00]', count: tabCounts.cc },
    ];

    // 只有管理员才显示管理员处理tab
    if (isAdmin) {
      tabs.push({
        key: 'admin' as TabType,
        label: t.approvals.adminProcessing || '管理员处理',
        icon: ShieldAlert,
        color: 'text-red-600',
        count: tabCounts.admin,
      });
    }

    return (
      <div className="flex items-center justify-between px-6 h-14 bg-white border-b" style={{ borderColor: '#e5e6eb' }}>
        <div className="flex items-center gap-2">
          {tabs.map((tab, index) => {
          const Icon = tab.icon;
          const isActive = activeTab === tab.key;
          
          return (
            <div key={tab.key} className="flex items-center gap-2">
              {index === 1 && (
                <div className="h-6 w-px bg-gray-200"></div>
              )}
              <button
                onClick={() => updateTab(tab.key)}
                className={`
                  px-4 h-9 rounded-lg flex items-center gap-2 text-sm font-medium transition-all
                  ${isActive 
                    ? 'bg-[#eef2ff] text-[#3370ff]' 
                    : 'text-gray-600 hover:bg-gray-50'
                  }
                `}
              >
                <Icon className={`w-4 h-4 ${isActive ? tab.color : ''}`} />
                <span>{tab.label}</span>
                {/* 数量徽章 */}
                {tab.count !== undefined && tab.count > 0 && (
                  <span className={`
                    inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 rounded-full text-xs font-semibold
                    ${tab.key === 'pending' 
                      ? (isActive ? 'bg-[#3370ff] text-white' : 'bg-red-500 text-white')  // 待我审批：选中时蓝色，未选中时红色
                      : (isActive ? 'bg-[#3370ff] text-white' : 'bg-gray-400 text-white')  // 其他：选中时蓝色，未选中时灰色
                    }
                  `}>
                    {tab.count > 99 ? '99+' : tab.count}
                  </span>
                )}
              </button>
            </div>
          );
        })}
        </div>
        {activeTab === 'admin' && isAdmin && (
          <div className="flex items-center gap-2">
            <button
              onClick={() => updateAdminView('processing')}
              className={`px-3 h-8 rounded-md text-sm transition-all ${
                adminView === 'processing' ? 'bg-[#3370ff] text-white' : 'text-[#4e5969] hover:bg-gray-50'
              }`}
            >
              {t.approvals.adminProcessing}
            </button>
            <button
              onClick={() => updateAdminView('analytics')}
              className={`px-3 h-8 rounded-md text-sm transition-all ${
                adminView === 'analytics' ? 'bg-[#3370ff] text-white' : 'text-[#4e5969] hover:bg-gray-50'
              }`}
            >
              {t.approvals.adminAnalytics.tabLabel}
            </button>
          </div>
        )}
      </div>
    );
  };

  const renderFilters = () => (
    <div className="px-6 py-4 bg-white border-b flex items-center gap-3" style={{ borderColor: '#e5e6eb' }}>
      {/* 搜索框 */}
      <div className="flex-1 relative">
        <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
        <input
          type="text"
          placeholder={locale === 'zh' ? '搜索标题、提交人...' : 'Search title, submitter...'}
          value={searchTerm}
          onChange={(e) => setSearchTerm(e.target.value)}
          className="w-full pl-10 pr-4 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
        />
      </div>

      {/* 表单筛选 */}
      {formKeys.length > 0 && (
        <div className="relative">
          <Filter className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 pointer-events-none z-10" />
          <select
            value={selectedFormKey}
            onChange={(e) => setSelectedFormKey(e.target.value)}
            className="pl-10 pr-10 py-2 border border-gray-200 rounded-lg text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 appearance-none cursor-pointer min-w-[180px]"
          >
            <option value="all">{locale === 'zh' ? '全部表单' : 'All Forms'}</option>
            {formKeys.map(key => (
              <option key={key} value={key}>{key}</option>
            ))}
          </select>
          <ChevronDown className="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 pointer-events-none" />
        </div>
      )}
    </div>
  );

  const renderItemList = () => {
    if (loading) {
      return (
        <div className="flex flex-col h-full">
          {/* 搜索框占位 */}
          <div className="p-4 border-b bg-white" style={{ borderColor: '#e5e6eb' }}>
            <div className="h-10"></div>
          </div>
          <div className="flex-1 flex items-center justify-center">
            <div className="flex flex-col items-center gap-3">
              <div className="animate-spin rounded-full h-8 w-8 border-2 border-gray-200 border-t-blue-600"></div>
              <p className="text-sm text-gray-500">{t.common.loading}</p>
            </div>
          </div>
        </div>
      );
    }

    // 获取状态显示信息
    const getStatusDisplay = (item: ApprovalItem) => {
      const statusMap: Record<string, { text: string; bgColor: string; textColor: string }> = {
        // 流程实例状态（InstanceStatus）
        'RUNNING': { text: locale === 'zh' ? '审批中' : 'Running', bgColor: 'bg-[#e5f2ff]', textColor: 'text-[#3370ff]' },
        'SUSPENDED': { text: locale === 'zh' ? '已暂停' : 'Suspended', bgColor: 'bg-[#f5f5f5]', textColor: 'text-[#8a8a8a]' },
        'APPROVED': { text: locale === 'zh' ? '已通过' : 'Approved', bgColor: 'bg-[#d4f4dd]', textColor: 'text-[#00b42a]' },
        'REJECTED': { text: locale === 'zh' ? '已拒绝' : 'Rejected', bgColor: 'bg-[#fbe4e8]', textColor: 'text-[#f53f3f]' },
        'WITHDRAWN': { text: locale === 'zh' ? '已撤回' : 'Withdrawn', bgColor: 'bg-[#fff7e6]', textColor: 'text-[#ff7d00]' },
        'TERMINATED': { text: locale === 'zh' ? '已终止' : 'Terminated', bgColor: 'bg-[#f5f5f5]', textColor: 'text-[#86909c]' },  // ⚠️ 修复：灰色
        'FAILED': { text: locale === 'zh' ? '失败' : 'Failed', bgColor: 'bg-[#fbe4e8]', textColor: 'text-[#f53f3f]' },
        
        // 任务状态（TaskStatus）
        'ASSIGNED': { text: locale === 'zh' ? '待处理' : 'Assigned', bgColor: 'bg-[#fff7e6]', textColor: 'text-[#ff7d00]' },
        'PENDING': { text: locale === 'zh' ? '待审批' : 'Pending', bgColor: 'bg-[#fff7e6]', textColor: 'text-[#ff7d00]' },
        'PROCESSING': { text: locale === 'zh' ? '审批中' : 'Processing', bgColor: 'bg-[#e5f2ff]', textColor: 'text-[#3370ff]' },
      };
      return statusMap[item.status] || { text: item.status, bgColor: 'bg-gray-100', textColor: 'text-gray-600' };
    };

    return (
      <div className="flex flex-col h-full">
        {/* 搜索和筛选栏 */}
        <div className="p-4 border-b bg-white space-y-3" style={{ borderColor: '#e5e6eb' }}>
          {/* 搜索框 */}
          <div className="relative">
            <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
            <input
              type="text"
              placeholder={locale === 'zh' ? '搜索标题、提交人...' : 'Search title, submitter...'}
              value={searchTerm}
              onChange={(e) => setSearchTerm(e.target.value)}
              className="w-full pl-10 pr-4 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
            />
          </div>

          {/* 表单筛选 */}
          {formKeys.length > 0 && (
            <div className="relative">
              <Filter className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 pointer-events-none z-10" />
              <select
                value={selectedFormKey}
                onChange={(e) => setSelectedFormKey(e.target.value)}
                className="w-full pl-10 pr-10 py-2 border border-gray-200 rounded-lg text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 appearance-none cursor-pointer"
              >
                <option value="all">{locale === 'zh' ? '全部表单' : 'All Forms'}</option>
                {formKeys.map(key => (
                  <option key={key} value={key}>{key}</option>
                ))}
              </select>
              <ChevronDown className="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 pointer-events-none" />
            </div>
          )}
        </div>

        {/* 列表内容 */}
        {filteredItems.length === 0 ? (
          <div className="flex-1 flex items-center justify-center px-4">
            <PageState
              variant="empty"
              title={
                activeTab === 'admin'
                  ? t.approvals.emptyStates.adminTitle
                  : t.approvals.emptyStates.noData
              }
              description={activeTab === 'admin' ? t.approvals.emptyStates.adminDesc : undefined}
              layout="center"
              className="mx-auto w-full max-w-2xl border-0 bg-transparent"
            />
          </div>
        ) : (
          <div className="flex-1 overflow-y-auto">
            <div className="p-4 space-y-3">
              {filteredItems.map(item => {
                const isSelected = selectedItem?.id === item.id;
                const statusDisplay = getStatusDisplay(item);
                // 从 formData 中提取关键字段（这里需要根据实际表单结构调整）
                const raw = item.raw as any;
                const formData = raw.variables?.formData || {};
                
                return (
                  <div
                    key={item.id}
                    onClick={() => setSelectedItem(item)}
                    className={`
                      w-full text-left transition-all rounded-lg border bg-white cursor-pointer
                      ${isSelected 
                        ? 'border-[#3370ff] shadow-lg shadow-blue-100' 
                        : 'border-[#e5e6eb] hover:border-gray-300 hover:shadow-md'
                      }
                    `}
                  >
                    <div className="p-4">
                      {/* 顶部：标题 + 状态 */}
                      <div className="flex items-center justify-between mb-3">
                        <h3 className="text-base font-semibold text-gray-900 flex-1 pr-3 truncate">
                          {item.title}
                        </h3>
                        <span className={`
                          inline-flex items-center px-2.5 py-1 rounded-md text-xs font-medium whitespace-nowrap flex-shrink-0
                          ${statusDisplay.bgColor} ${statusDisplay.textColor}
                        `}>
                          {statusDisplay.text}
                        </span>
                      </div>

                      {/* 底部：提交人信息 + 时间 + 撤回按钮 */}
                      <div className="flex items-center justify-between">
                        <div className="flex items-center gap-2">
                          {/* 头像 */}
                          <div className="w-6 h-6 rounded-full bg-[#00b42a] flex items-center justify-center text-white text-xs font-medium">
                            {item.submitter.name.substring(0, 2).toUpperCase()}
                          </div>
                          <span className="text-sm text-gray-700">
                            {item.submitter.name}
                          </span>
                        </div>
                        
                        <div className="flex items-center gap-3">
                          {/* 时间 */}
                          {item.submitTime && (
                            <div className="flex items-center gap-1 text-xs text-gray-500">
                              <span>
                                {activeTab === 'processed' 
                                  ? (locale === 'zh' ? '处理时间' : 'Processed')
                                  : (locale === 'zh' ? '提交时间' : 'Submitted')
                                }：
                              </span>
                              <span>
                                {formatDate(new Date(item.submitTime), locale).split(' ')[0]}
                              </span>
                              <span className="text-gray-400">
                                {formatDate(new Date(item.submitTime), locale).split(' ')[1]}
                              </span>
                            </div>
                          )}

                          {/* 撤回按钮 - 仅在"我发起的"Tab且状态为RUNNING/PENDING时显示 */}
                          {activeTab === 'initiated' && 
                           (item.status === 'RUNNING' || item.status === 'PENDING') && (
                            <button
                              onClick={(e) => handleWithdrawClick(item, e)}
                              className="px-3 py-1.5 text-xs font-medium text-gray-600 bg-white border border-gray-300 rounded-md hover:bg-gray-50 hover:border-gray-400 transition-colors flex items-center gap-1"
                              title={locale === 'zh' ? '撤回申请' : 'Withdraw'}
                            >
                              <RotateCcw className="w-3.5 h-3.5" />
                              <span>{locale === 'zh' ? '撤回' : 'Withdraw'}</span>
                            </button>
                          )}
                        </div>
                      </div>
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        )}
      </div>
    );
  };

  const renderDetailPanel = () => {
    if (!selectedItem) {
      return (
        <div className="flex flex-col items-center justify-center h-full text-gray-400">
          <FileText className="w-16 h-16 mb-4" />
          <p className="text-sm">{locale === 'zh' ? '请从左侧选择一个审批项' : 'Select an item from the left'}</p>
        </div>
      );
    }

    if (detailLoading) {
      return (
        <div className="flex items-center justify-center h-full">
          <div className="flex flex-col items-center gap-3">
            <div className="animate-spin rounded-full h-10 w-10 border-2 border-gray-200 border-t-blue-600"></div>
            <p className="text-sm text-gray-500">{t.common.loading}</p>
          </div>
        </div>
      );
    }

    if (!detail) {
      return (
        <div className="flex flex-col items-center justify-center h-full text-gray-400">
          <AlertCircle className="w-16 h-16 mb-4" />
          <p className="text-sm">{locale === 'zh' ? '加载详情失败' : 'Failed to load details'}</p>
        </div>
      );
    }

    // 获取状态显示信息
    const getDetailStatusDisplay = () => {
      const statusMap: Record<string, { text: string; bgColor: string; textColor: string }> = {
        'RUNNING': { text: locale === 'zh' ? '审批中' : 'Running', bgColor: 'bg-[#e5f2ff]', textColor: 'text-[#3370ff]' },
        'SUSPENDED': { text: locale === 'zh' ? '已暂停' : 'Suspended', bgColor: 'bg-[#f5f5f5]', textColor: 'text-[#8a8a8a]' },
        'APPROVED': { text: locale === 'zh' ? '已通过' : 'Approved', bgColor: 'bg-[#d4f4dd]', textColor: 'text-[#00b42a]' },
        'REJECTED': { text: locale === 'zh' ? '已拒绝' : 'Rejected', bgColor: 'bg-[#fbe4e8]', textColor: 'text-[#f53f3f]' },
        'WITHDRAWN': { text: locale === 'zh' ? '已撤回' : 'Withdrawn', bgColor: 'bg-[#fff7e6]', textColor: 'text-[#ff7d00]' },
        'TERMINATED': { text: locale === 'zh' ? '已终止' : 'Terminated', bgColor: 'bg-[#f5f5f5]', textColor: 'text-[#86909c]' },  // ⚠️ 修复：灰色
        'FAILED': { text: locale === 'zh' ? '失败' : 'Failed', bgColor: 'bg-[#fbe4e8]', textColor: 'text-[#f53f3f]' },
        'PENDING': { text: locale === 'zh' ? '待审批' : 'Pending', bgColor: 'bg-[#fff7e6]', textColor: 'text-[#ff7d00]' },
        'PROCESSING': { text: locale === 'zh' ? '审批中' : 'Processing', bgColor: 'bg-[#e5f2ff]', textColor: 'text-[#3370ff]' },
        'ASSIGNED': { text: locale === 'zh' ? '待处理' : 'Assigned', bgColor: 'bg-[#fff7e6]', textColor: 'text-[#ff7d00]' },
      };
      return statusMap[detail.status] || { text: detail.status, bgColor: 'bg-gray-100', textColor: 'text-gray-600' };
    };

    const statusDisplay = getDetailStatusDisplay();

    return (
      <div className="absolute inset-0 flex flex-col bg-[#f7f8fa]">
        {/* 详情头部 - 包含标题、状态、提交人信息 */}
        <div className="px-6 py-4 bg-white border-b" style={{ borderColor: '#e5e6eb' }}>
          {/* 标题行 */}
          <div className="flex items-start justify-between gap-3 mb-3">
            <h2 className="text-lg font-semibold text-gray-900 flex-1">{detail.title}</h2>
            <span className={`
              inline-flex items-center px-3 py-1 rounded-md text-xs font-medium whitespace-nowrap
              ${statusDisplay.bgColor} ${statusDisplay.textColor}
            `}>
              {statusDisplay.text}
            </span>
          </div>
          
          {/* 信息行 */}
          <div className="flex items-center gap-4 text-sm">
            <div className="flex items-center gap-2">
              <div className="w-6 h-6 rounded-full bg-[#00b42a] flex items-center justify-center text-white text-xs font-medium">
                {detail.submitter.name.substring(0, 2).toUpperCase()}
              </div>
              <span className="text-gray-700 font-medium">{detail.submitter.name}</span>
            </div>
            {detail.submitTime && (
              <div className="flex items-center gap-1 text-gray-500">
                <Calendar className="w-4 h-4" />
                <span>{formatDate(new Date(detail.submitTime), locale)}</span>
              </div>
            )}
            {detail.currentNode && !isProcessEnded(detail.status) && (
              <div className="flex items-center gap-1 text-gray-500">
                <span className="text-xs">{locale === 'zh' ? '当前节点' : 'Node'}:</span>
                <span className="text-xs font-medium">{detail.currentNode}</span>
              </div>
            )}
            {isProcessEnded(detail.status) && (
              <div className="flex items-center gap-1 text-gray-500">
                <CheckCircle className="w-4 h-4" />
                <span className="text-xs font-medium">{locale === 'zh' ? '已结束' : 'Ended'}</span>
              </div>
            )}
          </div>
        </div>

        {/* 详情内容 - 可滚动 */}
        <div className="flex-1 overflow-y-auto p-6" style={{ minHeight: 0 }}>
          {/* 表单数据 - 使用通用渲染引擎 */}
          {detail.formSchema && detail.formData ? (
            <div className="bg-white rounded-lg border p-6 shadow-sm mb-6" style={{ borderColor: '#e5e6eb' }}>
              <FormRenderer
                schema={detail.formSchema}
                uiSchema={detail.formUiSchema || {}}
                formData={detail.formData}
                onChange={() => {}} // 只读
                disabled={true}
                showSaveButton={false}
                showSubmitButton={false}
                showSubmitterInfo={false}
              />
            </div>
          ) : (
            <div className="bg-white rounded-lg border p-8 mb-6" style={{ borderColor: '#e5e6eb' }}>
              <PageState
                variant="empty"
                title={t.approvals.emptyStates.noFormData}
                layout="center"
                className="border-0 bg-transparent"
              />
            </div>
          )}

          {/* 审批流程预览 */}
          {detail.processVersion?.model && detail.processVersion.model.nodes && detail.processVersion.model.nodes.length > 0 && (() => {
            // ⭐ 使用统一的状态映射工具，处理所有节点（已执行 + 未执行）
            // 这个函数会自动处理：
            // 1. 已执行节点的状态（基于 history）
            // 2. 未执行节点的状态（基于 processModel 和 instanceStatus）
            // 3. START/END 节点的特殊逻辑
            const model = detail.calculatedProcess?.model || detail.processVersion.model;
            const nodeStatuses = mapApprovalHistoryToNodeStatuses(
              (detail.history || []) as HistoryItem[],
              model,
              detail.status as InstanceStatus,
              detail.submitTime,
              detail.submitter,
              detail.endReason  // ⭐ 传递流程终止原因
            );
            
            return (
              <div className="bg-white rounded-lg border p-6 shadow-sm" style={{ borderColor: '#e5e6eb' }}>
                <div className="flex items-center gap-2 mb-4">
                  <Workflow className="w-5 h-5 text-[#3370ff]" />
                  <h3 className="text-base font-semibold text-gray-900">
                    {locale === 'zh' ? '审批流程' : 'Approval Process'}
                  </h3>
                </div>
                <LarkProcessPreview
                  model={model}
                  initiatorName={(() => {
                    // ⭐ 发起人应该始终是 submitter（提交人）
                    return detail.submitter.name;
                  })()}
                  nodeStatuses={nodeStatuses}
                />
                <div className="mt-4 flex items-start gap-2 text-xs text-gray-500">
                  <span>💡</span>
                  <span>
                    {detail.calculatedProcess 
                      ? (locale === 'zh' 
                          ? '以上为根据表单数据计算的实际审批人' 
                          : 'Actual approvers calculated based on form data')
                      : (locale === 'zh' 
                          ? '流程按上述配置进行，实际审批人可能根据规则动态确定' 
                          : 'The process follows the configuration above, actual approvers may be dynamically determined')
                    }
                  </span>
                </div>
              </div>
            );
          })()}
        </div>

        {/* 管理员操作区 - 固定在底部（仅admin tab显示，且流程运行中） */}
        {activeTab === 'admin' && detail && detail.status === 'RUNNING' && (
          <div className="flex-shrink-0 px-6 py-4 bg-white border-t shadow-lg" style={{ borderColor: '#e5e6eb' }}>
            <div className="flex items-center justify-between mb-4">
              <h3 className="text-sm font-medium text-gray-900">
                {locale === 'zh' ? '管理员操作' : 'Admin Actions'}
                <span className="ml-2 text-xs text-red-600 font-normal">
                  {locale === 'zh'
                    ? '(需填写原因并记录审计日志)'
                    : '(reason required, audit logged)'}
                </span>
              </h3>
              <div className="flex items-center gap-2 px-2 py-1 bg-red-50 border border-red-200 rounded text-xs text-red-600">
                <AlertTriangle className="w-3 h-3" />
                <span>{locale === 'zh' ? '超级管理员权限' : 'Super Admin Privilege'}</span>
              </div>
            </div>
            <div className="grid grid-cols-4 gap-3">
              <button
                onClick={() => setAdminActionType('approve')}
                disabled={!('taskId' in selectedItem?.raw && selectedItem?.raw?.taskId)}
                className="flex items-center justify-center gap-2 px-4 py-3 bg-green-50 border border-green-200 rounded-lg hover:bg-green-100 text-green-700 font-medium text-sm transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
              >
                <CheckCircle className="w-4 h-4" />
                {locale === 'zh' ? '代审批通过' : 'Admin Approve'}
              </button>
              <button
                onClick={() => setAdminActionType('reject')}
                disabled={!('taskId' in selectedItem?.raw && selectedItem?.raw?.taskId)}
                className="flex items-center justify-center gap-2 px-4 py-3 bg-red-50 border border-red-200 rounded-lg hover:bg-red-100 text-red-700 font-medium text-sm transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
              >
                <XCircle className="w-4 h-4" />
                {locale === 'zh' ? '代审批驳回' : 'Admin Reject'}
              </button>
              <button
                onClick={() => setAdminActionType('reassign')}
                disabled={!('taskId' in selectedItem?.raw && selectedItem?.raw?.taskId)}
                className="flex items-center justify-center gap-2 px-4 py-3 bg-purple-50 border border-purple-200 rounded-lg hover:bg-purple-100 text-purple-700 font-medium text-sm transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
              >
                <UserCog className="w-4 h-4" />
                {locale === 'zh' ? '重新分配' : 'Reassign'}
              </button>
              <button
                onClick={() => setAdminActionType('terminate')}
                disabled={false}
                className="flex items-center justify-center gap-2 px-4 py-3 bg-orange-50 border border-orange-200 rounded-lg hover:bg-orange-100 text-orange-700 font-medium text-sm transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
              >
                <AlertTriangle className="w-4 h-4" />
                {locale === 'zh' ? '强制终止' : 'Force Terminate'}
              </button>
            </div>
          </div>
        )}

        {/* 挂起的流程：恢复（指派审批人）/ 强制终止
            ERR-20260501-004：审批人解析失败时 workflow 自动挂起，等管理员介入 */}
        {activeTab === 'admin' && detail && detail.status === 'SUSPENDED' && (
          <div className="flex-shrink-0 px-6 py-4 bg-white border-t shadow-lg" style={{ borderColor: '#e5e6eb' }}>
            <div className="flex items-center justify-between mb-2">
              <h3 className="text-sm font-medium text-gray-900">
                {locale === 'zh' ? '流程已挂起' : 'Workflow Suspended'}
                <span className="ml-2 text-xs text-orange-600 font-normal">
                  ({locale === 'zh' ? '审批人解析失败，等待管理员介入' : 'approver resolution failed, awaiting admin intervention'})
                </span>
              </h3>
              <div className="flex items-center gap-2 px-2 py-1 bg-orange-50 border border-orange-200 rounded text-xs text-orange-600">
                <AlertTriangle className="w-3 h-3" />
                <span>SUSPENDED</span>
              </div>
            </div>
            {(detail as any).endComment && (
              <p className="text-xs text-gray-600 mb-3">{(detail as any).endComment}</p>
            )}
            <div className="grid grid-cols-2 gap-3">
              <button
                onClick={() => setAdminActionType('resume')}
                className="flex items-center justify-center gap-2 px-4 py-3 bg-blue-50 border border-blue-200 rounded-lg hover:bg-blue-100 text-blue-700 font-medium text-sm transition-colors"
              >
                <UserCog className="w-4 h-4" />
                {locale === 'zh' ? '指派审批人并恢复' : 'Assign approvers and resume'}
              </button>
              <button
                onClick={() => setAdminActionType('terminate')}
                className="flex items-center justify-center gap-2 px-4 py-3 bg-orange-50 border border-orange-200 rounded-lg hover:bg-orange-100 text-orange-700 font-medium text-sm transition-colors"
              >
                <AlertTriangle className="w-4 h-4" />
                {locale === 'zh' ? '终止流程' : 'Terminate'}
              </button>
            </div>
          </div>
        )}

        {/* 挂起的流程：恢复（指派审批人）/ 强制终止
            ERR-20260501-004：审批人解析失败时 workflow 自动挂起，等管理员介入 */}
        {activeTab === 'admin' && detail && detail.status === 'SUSPENDED' && (
          <div className="flex-shrink-0 px-6 py-4 bg-white border-t shadow-lg" style={{ borderColor: '#e5e6eb' }}>
            <div className="flex items-center justify-between mb-2">
              <h3 className="text-sm font-medium text-gray-900">
                {locale === 'zh' ? '流程已挂起' : 'Workflow Suspended'}
                <span className="ml-2 text-xs text-orange-600 font-normal">
                  ({locale === 'zh' ? '审批人解析失败，等待管理员介入' : 'approver resolution failed, awaiting admin intervention'})
                </span>
              </h3>
              <div className="flex items-center gap-2 px-2 py-1 bg-orange-50 border border-orange-200 rounded text-xs text-orange-600">
                <AlertTriangle className="w-3 h-3" />
                <span>SUSPENDED</span>
              </div>
            </div>
            {(detail as any).endComment && (
              <p className="text-xs text-gray-600 mb-3">{(detail as any).endComment}</p>
            )}
            <div className="grid grid-cols-2 gap-3">
              <button
                onClick={() => setAdminActionType('resume')}
                className="flex items-center justify-center gap-2 px-4 py-3 bg-blue-50 border border-blue-200 rounded-lg hover:bg-blue-100 text-blue-700 font-medium text-sm transition-colors"
              >
                <UserCog className="w-4 h-4" />
                {locale === 'zh' ? '指派审批人并恢复' : 'Assign approvers and resume'}
              </button>
              <button
                onClick={() => setAdminActionType('terminate')}
                className="flex items-center justify-center gap-2 px-4 py-3 bg-orange-50 border border-orange-200 rounded-lg hover:bg-orange-100 text-orange-700 font-medium text-sm transition-colors"
              >
                <AlertTriangle className="w-4 h-4" />
                {locale === 'zh' ? '终止流程' : 'Terminate'}
              </button>
            </div>
          </div>
        )}

        {/* 审批操作区 - 固定在底部 */}
        {detail.canApprove && (
          <div className="flex-shrink-0 px-6 py-4 bg-white border-t shadow-lg" style={{ borderColor: '#e5e6eb' }}>
            {/* 审批意见 */}
            <div className="mb-4">
              <label className="block text-sm font-medium text-gray-700 mb-2">
                {locale === 'zh' ? '审批意见' : 'Comment'}
                <span className="text-gray-400 ml-1 text-xs">
                  ({locale === 'zh' ? '拒绝时必填' : 'Required for rejection'})
                </span>
              </label>
              <textarea
                value={comment}
                onChange={(e) => setComment(e.target.value)}
                placeholder={locale === 'zh' ? '请输入审批意见...' : 'Enter comment...'}
                rows={2}
                className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none"
              />
            </div>

            {/* 操作按钮 - 标准尺寸 */}
            <div className="flex gap-3 items-center">
              {/* 转交按钮 - 左侧 */}
              <button
                onClick={handleForwardClick}
                disabled={approving || rejecting || forwarding}
                className="h-9 px-4 rounded-lg bg-white text-gray-700 font-medium text-sm border border-gray-300 hover:bg-gray-50 hover:border-gray-400 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2"
              >
                <ArrowRightCircle className="w-4 h-4" />
                <span>{locale === 'zh' ? '转交' : 'Forward'}</span>
              </button>

              {/* 分隔线 */}
              <div className="h-6 w-px bg-gray-300"></div>

              {/* 审批按钮组 - 右侧 */}
              <div className="flex gap-3 flex-1">
                {/* ⭐ 通过按钮 - 左侧（主按钮） */}
                <button
                  onClick={handleApprove}
                  disabled={approving || rejecting || forwarding}
                  className="flex-1 h-9 px-4 rounded-lg bg-[#3b82f6] text-white font-medium text-sm hover:bg-[#2563eb] disabled:opacity-50 disabled:cursor-not-allowed transition-colors shadow-sm flex items-center justify-center gap-2"
                >
                  {approving ? (
                    <>
                      <Loader2 className="w-4 h-4 animate-spin" />
                      <span>{locale === 'zh' ? '审批中...' : 'Approving...'}</span>
                    </>
                  ) : (
                    <>
                      <Check className="w-4 h-4" />
                      <span>{locale === 'zh' ? '通过' : 'Approve'}</span>
                    </>
                  )}
                </button>
                
                {/* ⭐ 拒绝按钮 - 右侧（次要按钮，浅红背景） */}
                <button
                  onClick={handleReject}
                  disabled={approving || rejecting || forwarding}
                  className="flex-1 h-9 px-4 rounded-lg bg-white text-[#ef4444] font-medium text-sm border border-[#fecaca] hover:bg-[#fef2f2] hover:border-[#ef4444] disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center justify-center gap-2"
                >
                  {rejecting ? (
                    <>
                      <Loader2 className="w-4 h-4 animate-spin" />
                      <span>{locale === 'zh' ? '拒绝中...' : 'Rejecting...'}</span>
                    </>
                  ) : (
                    <>
                      <X className="w-4 h-4" />
                      <span>{locale === 'zh' ? '拒绝' : 'Reject'}</span>
                    </>
                  )}
                </button>
              </div>
            </div>

            {/* 次级动作（任务级：审批人撤回 / 加签 / 认领 / 取消认领），与上方主按钮（实例级 通过/拒绝/转交）分组 */}
            {detail.workflowId && (
              <div className="mt-3 pt-3 border-t border-gray-100">
                <ApprovalActions
                  businessType={(selectedItem?.raw as any)?.businessType ?? ''}
                  businessId={(selectedItem?.raw as any)?.businessId ?? ''}
                  instanceId={detail.workflowId}
                  taskId={(selectedItem?.raw as any)?.taskId ?? (selectedItem?.raw as any)?.id}
                  canOperate={detail.canApprove}
                  allowedActions={['approver-withdraw', 'add-sign', 'claim', 'unclaim']}
                  onSuccess={() => {
                    if (selectedItem) {
                      setSelectedItem(null);
                      setDetail(null);
                    }
                    setTimeout(() => loadItems(), 600);
                  }}
                />
              </div>
            )}
          </div>
        )}
      </div>
    );
  };

  // 渲染提交请求页面内容
  const renderSubmitRequestContent = () => {
    // 渲染表单卡片
    const renderFormCard = (form: FormDefinition, showCategory = false) => (
      <button
        key={form.id}
        onClick={() => handleFormClick(form)}
        className="flex items-center gap-3 p-4 bg-white border border-gray-200 rounded-lg hover:border-[#3370ff] hover:shadow-md transition-all group text-left"
      >
        {/* 图标 */}
        <div className={`w-10 h-10 rounded-lg ${getFormIconColor(form)} flex items-center justify-center text-white flex-shrink-0`}>
          {getFormIcon(form)}
        </div>
        
        {/* 内容 */}
        <div className="flex-1 min-w-0">
          <h3 className="text-sm font-medium text-gray-900 truncate group-hover:text-[#3370ff]">
            {form.name}
          </h3>
          {showCategory && form.category && (
            <p className="text-xs text-gray-500 mt-0.5 truncate">
              {form.category}
            </p>
          )}
        </div>
      </button>
    );

    if (formsLoading) {
      return (
        <div className="flex items-center justify-center h-full">
          <div className="flex flex-col items-center gap-3">
            <div className="animate-spin rounded-full h-8 w-8 border-2 border-gray-200 border-t-blue-600"></div>
            <p className="text-sm text-gray-500">{t.common.loading}</p>
          </div>
        </div>
      );
    }

    return (
      <div className="h-full overflow-y-auto">
        <div className="p-6">
          {/* 最近编辑 */}
          {!searchTerm && recentForms.length > 0 && (
            <div className="mb-6">
              <div className="flex items-center justify-between mb-4">
                <h2 className="text-sm font-medium text-gray-700">
                  {locale === 'zh' ? '最近编辑：' : 'Last edited:'}
                  <span className="ml-2 text-[#3370ff] underline cursor-pointer">
                    {recentForms[0].name}
                  </span>
                </h2>
                <button
                  onClick={() => setRecentForms([])}
                  className="text-gray-400 hover:text-gray-600 transition-colors"
                >
                  <X className="w-4 h-4" />
                </button>
              </div>
            </div>
          )}

          {/* 推荐应用 */}
          {!searchTerm && recommendedForms.length > 0 && (
            <div className="mb-6">
              <h2 className="text-base font-semibold text-gray-900 mb-4">
                {locale === 'zh' ? '推荐' : 'Recommended'}
              </h2>
              <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3">
                {recommendedForms.map(form => renderFormCard(form, true))}
              </div>
            </div>
          )}

          {/* 当前分类的表单 */}
          {categoryGroups.length === 0 ? (
            <div className="flex flex-col items-center justify-center py-16 text-gray-400">
              <PageState
                variant="empty"
                title={t.approvals.emptyStates.noFormsAvailable}
                layout="center"
                className="border-0 bg-transparent"
              />
            </div>
          ) : (
            <div>
              {categoryGroups.map(group => {
                if (selectedCategory && group.name !== selectedCategory) {
                  return null;
                }
                
                return (
                  <div key={group.name}>
                    <h2 className="text-base font-semibold text-gray-900 mb-4">
                      {group.name}
                    </h2>
                    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3">
                      {group.forms.map(form => renderFormCard(form))}
                    </div>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </div>
    );
  };

  // ========== 主渲染 ==========
  if (!isReady) {
    return (
      <div className="flex items-center justify-center min-h-screen">
        <div className="flex flex-col items-center gap-3">
          <div className="animate-spin rounded-full h-10 w-10 border-3 border-gray-200 border-t-blue-600"></div>
          <p className="text-sm text-gray-500">{t.common.loading}</p>
        </div>
      </div>
    );
  }

  return (
    <div className="h-full flex flex-col bg-[#f7f8fa]">
      {/* 标签栏 */}
      {renderTabs()}

      {/* 根据 activeTab 显示不同内容 */}
      {activeTab === 'submit' ? (
        /* 提交请求页面 - 左右分栏布局 */
        <div className="flex-1 flex overflow-hidden">
          {/* 左侧：搜索框 + 分类列表 */}
          <div className="w-[280px] bg-white border-r overflow-y-auto" style={{ borderColor: '#e5e6eb' }}>
              {/* 搜索框 */}
            <div className="p-4 border-b" style={{ borderColor: '#e5e6eb' }}>
              <div className="relative">
                <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
                <input
                  type="text"
                  placeholder={locale === 'zh' ? '搜索应用' : 'Search apps'}
                  value={searchTerm}
                  onChange={(e) => setSearchTerm(e.target.value)}
                  className="w-full pl-10 pr-4 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                />
              </div>
            </div>

            {/* 分类列表 */}
            <div className="p-2">
              {formsLoading ? (
                <div className="flex items-center justify-center py-8">
                  <div className="animate-spin rounded-full h-6 w-6 border-2 border-gray-200 border-t-blue-600"></div>
              </div>
              ) : categoryGroups.length > 0 ? (
                categoryGroups.map(group => (
                  <button
                    key={group.name}
                    onClick={() => setSelectedCategory(group.name)}
                    className={`
                      w-full px-4 py-2.5 text-left text-sm rounded-lg transition-colors
                      ${selectedCategory === group.name
                        ? 'bg-[#eef2ff] text-[#3370ff] font-medium'
                        : 'text-gray-700 hover:bg-gray-50'
                      }
                    `}
                  >
                    {group.name}
                  </button>
                ))
              ) : (
                <div className="py-8">
                  <PageState
                    variant="empty"
                    title={t.approvals.emptyStates.noCategories}
                    layout="center"
                    className="border-0 bg-transparent"
                  />
                </div>
                          )}
                        </div>
                      </div>

          {/* 右侧：表单内容 */}
          <div className="flex-1 bg-[#f7f8fa] overflow-y-auto">
            {renderSubmitRequestContent()}
          </div>
                    </div>
      ) : activeTab === 'admin' && adminView === 'analytics' && isAdmin ? (
        <div className="flex-1 overflow-y-auto p-6">
          <AdminAnalyticsPanel />
        </div>
      ) : (
        /* 审批列表页面 */
        <div className="flex-1 flex overflow-hidden">
          {/* 左侧：审批项列表（包含搜索框） */}
          <div className="w-[420px] bg-[#f7f8fa] border-r overflow-hidden flex flex-col" style={{ borderColor: '#e5e6eb' }}>
            {renderItemList()}
              </div>

          {/* 右侧：详情面板 */}
          <div className="flex-1 bg-[#f7f8fa] relative">
            {renderDetailPanel()}
          </div>
        </div>
      )}

      {/* 撤回确认对话框 */}
      {withdrawDialogOpen && (
        <div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg shadow-xl w-full max-w-md mx-4">
            {/* 头部 */}
            <div className="px-6 py-4 border-b border-gray-200">
              <div className="flex items-center justify-between">
                <h3 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
                  <RotateCcw className="w-5 h-5 text-orange-600" />
                  {locale === 'zh' ? '确认撤回申请？' : 'Confirm Withdrawal?'}
                </h3>
                <button
                  onClick={handleWithdrawCancel}
                  className="text-gray-400 hover:text-gray-600 transition-colors"
                >
                  <X className="w-5 h-5" />
                </button>
              </div>
            </div>

            {/* 内容 */}
            <div className="px-6 py-4 space-y-4">
              <p className="text-sm text-gray-600">
                {locale === 'zh' 
                  ? '撤回后该申请将终止，无法恢复。确定要撤回吗？'
                  : 'The application will be terminated after withdrawal and cannot be recovered. Are you sure?'
                }
              </p>

              {/* 撤回原因输入框 */}
              <div className="space-y-2">
                <label className="text-sm font-medium text-gray-700">
                  {locale === 'zh' ? '撤回原因（可选）' : 'Reason (Optional)'}
                </label>
                <textarea
                  value={withdrawReason}
                  onChange={(e) => setWithdrawReason(e.target.value)}
                  placeholder={locale === 'zh' ? '请输入撤回原因...' : 'Enter reason...'}
                  rows={3}
                  className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none"
                />
              </div>
            </div>

            {/* 底部按钮 */}
            <div className="px-6 py-4 bg-gray-50 border-t border-gray-200 flex justify-end gap-3 rounded-b-lg">
              <button
                onClick={handleWithdrawCancel}
                disabled={withdrawing}
                className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
              >
                {locale === 'zh' ? '取消' : 'Cancel'}
              </button>
              <button
                onClick={handleWithdrawConfirm}
                disabled={withdrawing}
                className="px-4 py-2 text-sm font-medium text-white bg-orange-600 rounded-lg hover:bg-orange-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2"
              >
                {withdrawing ? (
                  <>
                    <Loader2 className="w-4 h-4 animate-spin" />
                    <span>{locale === 'zh' ? '撤回中...' : 'Withdrawing...'}</span>
                  </>
                ) : (
                  <span>{locale === 'zh' ? '确认撤回' : 'Confirm'}</span>
                )}
              </button>
            </div>
          </div>
        </div>
      )}

      {/* 转交对话框 */}
      {forwardDialogOpen && (
        <div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg shadow-xl w-full max-w-md mx-4">
            {/* 头部 */}
            <div className="px-6 py-4 border-b border-gray-200">
              <div className="flex items-center justify-between">
                <h3 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
                  <ArrowRightCircle className="w-5 h-5 text-blue-600" />
                  {locale === 'zh' ? '转交审批' : 'Forward Approval'}
                </h3>
                <button
                  onClick={handleForwardCancel}
                  className="text-gray-400 hover:text-gray-600 transition-colors"
                >
                  <X className="w-5 h-5" />
                </button>
              </div>
            </div>

            {/* 内容 */}
            <div className="px-6 py-4 space-y-4">
              <p className="text-sm text-gray-600">
                {locale === 'zh' 
                  ? '请选择转交目标审批人，转交后该任务将从您的待办列表移除。'
                  : 'Select a target user to forward this task. The task will be removed from your pending list.'
                }
              </p>

              {/* 选择用户按钮 */}
              <div className="space-y-2">
                <label className="text-sm font-medium text-gray-700">
                  {locale === 'zh' ? '转交给' : 'Forward to'}
                  <span className="text-red-500 ml-1">*</span>
                </label>
                {forwardTargetUser ? (
                  <div className="flex items-center gap-2 px-3 py-2 border border-blue-300 bg-blue-50 rounded-lg">
                    <div className="w-8 h-8 rounded-full bg-blue-500 text-white flex items-center justify-center text-sm font-medium">
                      {forwardTargetUser.displayName.charAt(0)}
                    </div>
                    <div className="flex-1">
                      <div className="text-sm font-medium text-gray-900">
                        {forwardTargetUser.displayName}
                      </div>
                      {forwardTargetUser.department && (
                        <div className="text-xs text-gray-500">
                          {forwardTargetUser.department}
                        </div>
                      )}
                    </div>
                    <button
                      onClick={() => setUserSelectorOpen(true)}
                      className="text-sm text-blue-600 hover:text-blue-700 font-medium"
                    >
                      {locale === 'zh' ? '更换' : 'Change'}
                    </button>
                  </div>
                ) : (
                  <button
                    onClick={() => setUserSelectorOpen(true)}
                    className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm text-left hover:border-blue-500 hover:bg-blue-50 transition-colors flex items-center justify-between"
                  >
                    <span className="text-gray-500">
                      {locale === 'zh' ? '点击选择审批人...' : 'Click to select user...'}
                    </span>
                    <Users className="w-4 h-4 text-gray-400" />
                  </button>
                )}
              </div>

              {/* 转交原因输入框 */}
              <div className="space-y-2">
                <label className="text-sm font-medium text-gray-700">
                  {locale === 'zh' ? '转交原因' : 'Reason'}
                  <span className="text-red-500 ml-1">*</span>
                </label>
                <textarea
                  value={forwardComment}
                  onChange={(e) => setForwardComment(e.target.value)}
                  placeholder={locale === 'zh' ? '请输入转交原因...' : 'Enter reason...'}
                  rows={3}
                  className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none"
                />
              </div>
            </div>

            {/* 底部按钮 */}
            <div className="px-6 py-4 bg-gray-50 border-t border-gray-200 flex justify-end gap-3 rounded-b-lg">
              <button
                onClick={handleForwardCancel}
                disabled={forwarding}
                className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
              >
                {locale === 'zh' ? '取消' : 'Cancel'}
              </button>
              <button
                onClick={handleForwardSubmit}
                disabled={!forwardTargetUser || !forwardComment.trim() || forwarding}
                className="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2"
              >
                {forwarding ? (
                  <>
                    <Loader2 className="w-4 h-4 animate-spin" />
                    {locale === 'zh' ? '转交中...' : 'Forwarding...'}
                  </>
                ) : (
                  <>
                    <Send className="w-4 h-4" />
                    {locale === 'zh' ? '确定' : 'Confirm'}
                  </>
                )}
              </button>
            </div>
          </div>
        </div>
      )}

      {/* 用户选择器 */}
      <UserSelector
        open={userSelectorOpen}
        onClose={() => setUserSelectorOpen(false)}
        onConfirm={handleUserSelected}
        multiple={false}
        title={locale === 'zh' ? '选择转交目标' : 'Select Target User'}
      />

      {/* 管理员操作对话框 */}
      {adminActionType && (
        <div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg shadow-xl w-full max-w-md mx-4">
            <div className="px-6 py-4 border-b border-gray-200">
              <h3 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
                {adminActionType === 'terminate' && (
                  <>
                    <AlertTriangle className="w-5 h-5 text-orange-600" />
                    强制结束流程
                  </>
                )}
                {adminActionType === 'approve' && (
                  <>
                    <CheckCircle className="w-5 h-5 text-green-600" />
                    代审批通过
                  </>
                )}
                {adminActionType === 'reject' && (
                  <>
                    <XCircle className="w-5 h-5 text-red-600" />
                    代审批驳回
                  </>
                )}
                {adminActionType === 'reassign' && (
                  <>
                    <UserCog className="w-5 h-5 text-purple-600" />
                    重新分配任务
                  </>
                )}
                {adminActionType === 'resume' && (
                  <>
                    <UserCog className="w-5 h-5 text-blue-600" />
                    恢复挂起流程（指派审批人）
                  </>
                )}
              </h3>
            </div>

            <div className="px-6 py-4 space-y-4">
              <div className="p-3 bg-yellow-50 border border-yellow-200 rounded-lg text-sm text-yellow-800">
                <AlertTriangle className="w-4 h-4 inline mr-2" />
                此操作将被记录到审计日志
              </div>

              {/* 恢复挂起流程：填入审批人 UUID 列表 */}
              {adminActionType === 'resume' && (
                <div className="space-y-2">
                  <label className="text-sm font-medium text-gray-700">
                    审批人 UUID 列表 <span className="text-red-500">*</span>
                    <span className="ml-2 text-xs text-gray-500">（用换行或逗号分隔，每个一行）</span>
                  </label>
                  <textarea
                    value={adminApproverIdsRaw}
                    onChange={(e) => setAdminApproverIdsRaw(e.target.value)}
                    placeholder="例如：&#10;3a3186cd-9f3b-4ba5-bcdf-885166e65abf&#10;6be7a4dc-4e29-4902-b990-6d1753e58c3b"
                    rows={4}
                    className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none text-sm font-mono"
                  />
                  <p className="text-xs text-gray-500">
                    指派的审批人将替代原始流程定义中无法解析的审批人，workflow 收到信号后恢复 RUNNING。
                  </p>
                </div>
              )}

              {/* 转交时选择目标用户 */}
              {adminActionType === 'reassign' && (
                <div className="space-y-2">
                  <label className="text-sm font-medium text-gray-700">
                    目标审批人 <span className="text-red-500">*</span>
                  </label>
                  {adminTargetUser ? (
                    <div className="flex items-center gap-2 px-3 py-2 border border-purple-300 bg-purple-50 rounded-lg">
                      <div className="w-8 h-8 rounded-full bg-purple-500 text-white flex items-center justify-center text-sm font-medium">
                        {adminTargetUser.displayName?.charAt(0) || '?'}
                      </div>
                      <div className="flex-1">
                        <div className="text-sm font-medium text-gray-900">
                          {adminTargetUser.displayName}
                        </div>
                        {adminTargetUser.department && (
                          <div className="text-xs text-gray-500">
                            {adminTargetUser.department}
                          </div>
                        )}
                      </div>
                      <button
                        onClick={() => setAdminUserSelectorOpen(true)}
                        className="text-sm text-purple-600 hover:text-purple-700 font-medium"
                      >
                        更换
                      </button>
                    </div>
                  ) : (
                    <button
                      onClick={() => setAdminUserSelectorOpen(true)}
                      className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm text-left hover:border-purple-500 hover:bg-purple-50 transition-colors flex items-center justify-between"
                    >
                      <span className="text-gray-500">点击选择审批人...</span>
                      <Users className="w-4 h-4 text-gray-400" />
                    </button>
                  )}
                </div>
              )}

              {/* 操作原因（必填） */}
              <div className="space-y-2">
                <label className="text-sm font-medium text-gray-700">
                  操作原因 <span className="text-red-500">*</span>
                  <span className="ml-2 text-xs text-gray-500">（记录到审计日志，说明为什么要进行此操作）</span>
                </label>
                <textarea
                  value={adminReason}
                  onChange={(e) => setAdminReason(e.target.value)}
                  placeholder="例如：申请人紧急出差，需要加快审批流程..."
                  rows={3}
                  className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none text-sm"
                />
              </div>

              {/* 审批意见（可选，仅审批/驳回时显示） */}
              {(adminActionType === 'approve' || adminActionType === 'reject') && (
                <div className="space-y-2">
                  <label className="text-sm font-medium text-gray-700">
                    审批意见（可选）
                    <span className="ml-2 text-xs text-gray-500">（显示在审批历史中，给申请人的回复）</span>
                  </label>
                  <textarea
                    value={adminComment}
                    onChange={(e) => setAdminComment(e.target.value)}
                    placeholder="例如：已核实情况属实，同意通过..."
                    rows={2}
                    className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none text-sm"
                  />
                </div>
              )}
            </div>

            {/* 底部按钮 */}
            <div className="px-6 py-4 bg-gray-50 border-t border-gray-200 flex justify-end gap-3 rounded-b-lg">
              <button
                onClick={handleAdminCancel}
                disabled={adminProcessing}
                className="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 disabled:opacity-50 text-sm font-medium"
              >
                取消
              </button>
              <button
                onClick={handleAdminAction}
                disabled={
                  adminProcessing ||
                  !adminReason.trim() ||
                  (adminActionType === 'reassign' && !adminTargetUser) ||
                  (adminActionType === 'resume' && !adminApproverIdsRaw.trim())
                }
                className={`px-4 py-2 rounded-lg text-white font-medium disabled:opacity-50 flex items-center gap-2 text-sm ${
                  adminActionType === 'terminate' ? 'bg-orange-600 hover:bg-orange-700' :
                  adminActionType === 'approve' ? 'bg-green-600 hover:bg-green-700' :
                  adminActionType === 'reject' ? 'bg-red-600 hover:bg-red-700' :
                  'bg-purple-600 hover:bg-purple-700'
                }`}
              >
                {adminProcessing && <Loader2 className="w-4 h-4 animate-spin" />}
                {adminProcessing ? '处理中...' : '确认执行'}
              </button>
            </div>
          </div>
        </div>
      )}

      {/* 管理员用户选择器 */}
      <UserSelector
        open={adminUserSelectorOpen}
        onClose={() => setAdminUserSelectorOpen(false)}
        onConfirm={(users) => {
          if (users.length > 0) {
            setAdminTargetUser(users[0]);
            setAdminUserSelectorOpen(false);
          }
        }}
        multiple={false}
        title="选择目标审批人"
      />
    </div>
  );
}

// ============================================
// 数据映射函数
// ============================================

function mapPendingToItems(tasks: ApprovalTaskItem[]): ApprovalItem[] {
  return tasks.map((task, index) => {
    const item = {
      id: task.taskId || (task as any).id || `pending-${index}-${Date.now()}`,
      title: task.title || task.businessType,
      businessType: task.businessType,
      formKey: task.formKey, // 从后端 variables 中提取的表单定义 key
      submitter: {
        id: task.initiator.id,
        name: task.initiator.displayName || task.initiator.name || '-',
        avatar: task.initiator.avatar,
      },
      // ⭐ 修复：优先使用 createTime，回退到其他时间字段，避免使用 new Date()
      submitTime: (task as any).createTime || (task as any).startTime || (task as any).instanceStartTime || (task as any).createdAt,
      status: (task as any).status || 'PENDING',
      currentNode: task.nodeName || '',
      priority: (task as any).priority,
      raw: task,
    };
    
    // 调试日志
    if (!item.formKey) {
      console.warn('[mapPendingToItems] 任务缺少 formKey:', {
        taskId: task.taskId,
        businessType: task.businessType,
        hasFormKey: !!task.formKey,
        rawTask: task,
      });
    }
    
    if (!item.submitTime) {
      console.error('[mapPendingToItems] ❌ 缺少提交时间字段，请检查后端API返回数据');
    }
    
    return item;
  });
}

function mapInitiatedToItems(tasks: ApprovalTaskItem[]): ApprovalItem[] {
  return tasks.map((task, index) => {
    const item = {
      id: task.instanceId || `initiated-${index}-${Date.now()}`,
      title: task.title || task.businessType,
      businessType: task.businessType,
      formKey: task.formKey, // 从后端 variables 中提取的表单定义 key
      submitter: {
        id: task.initiator.id,
        name: task.initiator.displayName || task.initiator.name || '-',
      },
      // ⭐ 修复：优先使用 createTime，回退到其他时间字段
      submitTime: task.createTime || (task as any).createdAt || (task as any).startTime,
      status: task.status,
      currentNode: task.nodeName,
      priority: task.priority,
      raw: task,
    };
    
    // 调试日志
    if (!item.formKey) {
      console.warn('[mapInitiatedToItems] 任务缺少 formKey:', {
        instanceId: task.instanceId,
        businessType: task.businessType,
        hasFormKey: !!task.formKey,
        rawTask: task,
      });
    }
    
    if (!item.submitTime) {
      console.error('[mapInitiatedToItems] ❌ 缺少提交时间字段，请检查后端API返回数据');
    }
    
    return item;
  });
}

function mapProcessedToItems(tasks: ApprovalTaskItem[]): ApprovalItem[] {
  return tasks.map((task, index) => {
    const item = {
      id: task.taskId || `processed-${index}-${Date.now()}`,
      title: task.title || task.businessType,
      businessType: task.businessType,
      formKey: task.formKey, // 从后端 variables 中提取的表单定义 key
      submitter: {
        id: task.initiator?.id || '',
        name: task.initiator?.displayName || task.initiator?.name || '-',
      },
      // ⭐ 修复：优先使用 createTime，回退到其他时间字段
      submitTime: task.createTime || (task as any).createdAt || (task as any).startTime,
      status: task.status,
      currentNode: task.nodeName,
      raw: task,
    };
    
    if (!item.submitTime) {
      console.error('[mapProcessedToItems] ❌ 缺少提交时间字段，请检查后端API返回数据');
    }
    
    return item;
  });
}

function mapCCToItems(tasks: ApprovalTaskItem[]): ApprovalItem[] {
  return tasks.map((task, index) => {
    const item = {
      id: task.taskId || `cc-${index}-${Date.now()}`,
      title: task.title || task.businessType,
      businessType: task.businessType,
      formKey: task.formKey, // 从后端 variables 中提取的表单定义 key
      submitter: {
        id: task.initiator?.id || '',
        name: task.initiator?.displayName || task.initiator?.name || '-',
      },
      // ⭐ 修复：优先使用 createTime，回退到其他时间字段
      submitTime: task.createTime || (task as any).createdAt || (task as any).startTime,
      status: task.status,
      currentNode: task.nodeName,
      raw: task,
    };
    
    if (!item.submitTime) {
      console.error('[mapCCToItems] ❌ 缺少提交时间字段，请检查后端API返回数据');
    }
    
    return item;
  });
}

function mapAdminToItems(processes: AdminInstanceItem[]): ApprovalItem[] {
  return processes.map((process, index) => {
    const item = {
      id: process.instanceId || process.businessInstanceId || `admin-${index}-${Date.now()}`,
      title: process.formName || process.formKey || `实例-${process.businessInstanceId?.slice(0, 8)}`,
      businessType: process.businessType || 'FORM_INSTANCE',
      formKey: process.formKey,
      submitter: {
        id: process.submitter.id,
        name: process.submitter.displayName || process.submitter.name || '未知',
        avatar: process.submitter.avatar,
      },
      submitTime: process.submittedAt,
      status: process.status,
      currentNode: process.currentNode,
      raw: process,
    };

    if (!item.submitTime) {
      console.error('[mapAdminToItems] ❌ 缺少提交时间字段，请检查后端API返回数据');
    }

    return item;
  });
}
