import { defineStore } from 'pinia'
import { ref, computed, shallowRef, triggerRef } from 'vue'
import { useTokenStore } from './tokenStore'
import { useDailyTaskStateStore } from './dailyTaskState'
import { WebSocketPool } from '@/utils/WebSocketPool'
import { storageCache } from '@/utils/storageCache'

/**
 * 批量任务管理Store
 * 负责管理批量任务的执行、调度、统计等
 */
export const useBatchTaskStore = defineStore('batchTask', () => {
  const tokenStore = useTokenStore()
  const dailyTaskStateStore = useDailyTaskStateStore()
  
  // ==================== 性能优化配置 ====================
  
  // 🆕 日志打印控制配置
  const initLogConfig = () => {
    // 🚀 使用storageCache优化localStorage访问
    // 默认关闭所有日志以提升性能和减少内存占用
    return storageCache.get('batchTaskLogConfig', {
      dailyFix: false,          // 一键补差（默认关闭）
      climbTower: false,        // 爬塔（默认关闭）
      restartBottle: false,     // 重启盐罐机器人（默认关闭）
      legionSignIn: false,      // 俱乐部签到（默认关闭）
      autoStudy: false,         // 一键答题（默认关闭）
      claimHangupReward: false, // 领取挂机奖励（默认关闭）
      addClock: false,          // 加钟（默认关闭）
      sendCar: false,           // 发车（默认关闭）
      monthlyTask: false,       // 月度任务（钓鱼、竞技场）（默认关闭）
      blackMarket: false,       // 小号黑市购买（默认关闭）
      batch: false,             // 批量执行日志（默认关闭）
      heartbeat: false,         // 心跳日志（默认关闭）
      websocket: false,         // WebSocket连接日志（默认关闭）
      gameMessage: false        // 游戏消息处理跳过（默认关闭）
    })
  }
  
  const logConfig = ref(initLogConfig())
  
  // 保存日志配置到 localStorage
  // 🚀 使用storageCache批量写入，减少IO
  const saveLogConfig = () => {
    storageCache.set('batchTaskLogConfig', logConfig.value)
  }
  
  // 条件日志函数
  const taskLog = (taskType, ...args) => {
    if (logConfig.value[taskType]) {
      console.log(...args)
    }
  }
  
  const taskWarn = (taskType, ...args) => {
    if (logConfig.value[taskType]) {
      console.warn(...args)
    }
  }
  
  const taskError = (taskType, ...args) => {
    if (logConfig.value[taskType]) {
      console.error(...args)
    }
  }
  
  // 100并发优化：批量任务日志开关（生产环境建议设为false以提升性能）
  const ENABLE_BATCH_LOGS = false  // ⚠️ 关闭日志以减少内存占用
  
  // 🆕 连接池模式配置（v3.13.0）
  const USE_CONNECTION_POOL = ref(
    localStorage.getItem('useConnectionPool') !== null 
      ? localStorage.getItem('useConnectionPool') === 'true'
      : true // 默认启用连接池模式
  )
  const POOL_SIZE = ref(
    parseInt(localStorage.getItem('poolSize') || '10') // 默认连接池大小为10
  )
  
  // 🆕 v3.14.1: 性能模式 - 简化UI更新以降低CPU占用
  // 注意：不影响总体进度统计(executionStats)和失败原因统计(failureReasonsStats)
  // 只影响单个token的详细进度显示（进度百分比、当前任务名等）
  const PERFORMANCE_MODE = ref(
    localStorage.getItem('performanceMode') !== null
      ? localStorage.getItem('performanceMode') === 'true'
      : false // 默认关闭，当token数量>500时建议开启
  )
  
  // 🆕 v3.13.2 请求并发控制（避免同时发送太多请求导致服务器拥堵）
  const MAX_CONCURRENT_REQUESTS = ref(
    parseInt(localStorage.getItem('maxConcurrentRequests') || '5')
  )
  
  // 🆕 连接间隔时间（ms）
  const CONNECTION_INTERVAL = ref(
    parseInt(localStorage.getItem('connectionInterval') || '100')
  )
  
  // 🆕 连接池实例
  let wsPool = null
  
  // 批量任务执行进度记录（用于刷新后恢复）
  // 🚀 使用storageCache优化localStorage访问
  const savedProgress = ref(
    storageCache.get('batchTaskProgress', null)
  );
  
  // 🆕 v3.13.5: 启动时清理无效的进度数据
  (() => {
    if (savedProgress.value) {
      const progress = savedProgress.value
      
      // 检查进度数据完整性
      if (!progress.completedTokenIds || !progress.allTokenIds || !progress.tasks) {
        console.log(`🧹 [启动清理] 清除无效的进度数据（数据不完整）`)
        localStorage.removeItem('batchTaskProgress')
        savedProgress.value = null
      } else {
        const remaining = progress.allTokenIds.length - progress.completedTokenIds.length
        if (remaining > 0) {
          const elapsed = Date.now() - (progress.timestamp || 0)
          const hours = Math.floor(elapsed / 3600000)
          console.log(`📂 [启动恢复] 发现未完成的进度: ${progress.completedTokenIds.length}/${progress.allTokenIds.length} (剩余 ${remaining} 个, ${hours}小时前保存)`)
        } else {
          // 如果已经全部完成，清理进度数据
          console.log(`🧹 [启动清理] 清除已完成的进度数据`)
          localStorage.removeItem('batchTaskProgress')
          savedProgress.value = null
        }
      }
    }
  })();
  
  // 日志包装函数：根据开关决定是否输出
  const batchLog = (...args) => {
    if (ENABLE_BATCH_LOGS) {
      console.log(...args)
    }
  }
  
  /**
   * 保存批量任务执行进度（用于刷新后恢复）
   * 🚀 使用storageCache批量写入
   * 🔧 v3.13.5.6: 增加失败原因统计的保存
   */
  const saveExecutionProgress = (completedTokenIds, allTokenIds, tasks) => {
    // 🔧 使用已经增量记录的失败原因统计
    const currentFailureReasons = failureReasonsStats.value
    
    const progress = {
      completedTokenIds: completedTokenIds,
      allTokenIds: allTokenIds,
      tasks: tasks,
      timestamp: Date.now(),
      stats: {
        total: executionStats.value.total,
        success: executionStats.value.success,
        failed: executionStats.value.failed,
        skipped: executionStats.value.skipped
      },
      // 🔧 保存失败原因统计（已实时更新）
      failureReasons: currentFailureReasons
    }
    // 🚀 使用批量写入减少IO
    storageCache.set('batchTaskProgress', progress)
    savedProgress.value = progress
    batchLog(`💾 已保存进度: ${completedTokenIds.length}/${allTokenIds.length} 个Token已完成`)
  }
  
  /**
   * 清除保存的进度
   * 🚀 使用storageCache
   */
  const clearSavedProgress = () => {
    storageCache.remove('batchTaskProgress')
    savedProgress.value = null
    batchLog(`🗑️ 已清除保存的进度`)
  }
  
  /**
   * 检查是否有未完成的进度（用于提示用户）
   */
  const hasSavedProgress = computed(() => {
    if (!savedProgress.value) return false
    
    // 检查进度是否过期（超过24小时）
    const elapsed = Date.now() - savedProgress.value.timestamp
    const isExpired = elapsed > 24 * 60 * 60 * 1000 // 24小时
    
    if (isExpired) {
      clearSavedProgress()
      return false
    }
    
    // 检查是否还有未完成的token
    const remaining = savedProgress.value.allTokenIds.length - savedProgress.value.completedTokenIds.length
    return remaining > 0
  })
  
  /**
   * 检查是否在服务器维护时间
   * 每周五 4:45 AM - 7:15 AM 为维护时间
   * @returns {Object} { inMaintenance: boolean, message: string }
   */
  const checkMaintenanceTime = () => {
    const now = new Date()
    const day = now.getDay() // 0=周日, 1=周一, ..., 5=周五
    const hour = now.getHours()
    const minute = now.getMinutes()
    const totalMinutes = hour * 60 + minute // 转换为分钟数便于比较
    
    // 周五（day = 5）的 4:45 AM (285分钟) 到 7:15 AM (435分钟)
    if (day === 5) {
      const maintenanceStart = 4 * 60 + 45  // 4:45 = 285分钟
      const maintenanceEnd = 7 * 60 + 15    // 7:15 = 435分钟
      
      if (totalMinutes >= maintenanceStart && totalMinutes < maintenanceEnd) {
        const startTime = '04:45'
        const endTime = '07:15'
        return {
          inMaintenance: true,
          message: `服务器维护时间（每周五 ${startTime} - ${endTime}），请稍后再试`
        }
      }
    }
    
    return { inMaintenance: false, message: '' }
  }
  
  // ==================== UI更新节流优化 ====================
  
  // 批量UI更新队列（100并发优化）
  let uiUpdateTimer = null
  const pendingUIUpdates = new Map()
  
  /**
   * 🆕 v3.14.0: 根据Token数量动态计算节流延迟
   * 自动平衡性能和用户体验
   * 🔥 v3.14.1: 针对超大规模（500+）进一步优化延迟
   */
  const getDynamicThrottleDelay = () => {
    const tokenCount = Object.keys(taskProgress.value).length
    
    if (tokenCount <= 50) return 300   // 小规模：优秀体验（快速更新）
    if (tokenCount <= 100) return 500  // 中规模：平衡体验和性能
    if (tokenCount <= 200) return 800  // 大规模：性能优先
    if (tokenCount <= 500) return 1500 // 超大规模：极限优化
    return 3000                        // 巨型规模（500+）：大幅降低更新频率
  }
  
  /**
   * 节流版本的进度更新（用于单个token的详细进度显示）
   * 将多次更新合并为批量更新，减少Vue响应式触发频率
   * 🚀 v3.13.5.4: 优化内存清理，使用shallowRef减少响应式开销，延长节流时间
   * 🔥 v3.14.0: 使用动态节流延迟，根据Token数量自动调整
   * 🔥 v3.14.1: 性能模式 - 简化单个token的UI更新，降低CPU占用
   * 
   * ⚠️ 注意：此函数只影响taskProgress（单个token详细进度）
   * ✅ 不影响：executionStats（总体统计）和failureReasonsStats（失败原因统计）
   */
  const updateTaskProgressThrottled = (tokenId, updates) => {
    const tokenCount = Object.keys(taskProgress.value).length
    
    // 🔥 性能模式：只更新关键状态，跳过详细进度（大幅降低CPU占用）
    if (PERFORMANCE_MODE.value) {
      // 只保留关键状态变化（等待、执行中、完成、失败、跳过）
      const isCriticalUpdate = updates.status && 
        ['waiting', 'executing', 'completed', 'failed', 'skipped'].includes(updates.status)
      if (!isCriticalUpdate) {
        return // 跳过进度百分比、当前任务名等细节更新
      }
    }
    
    // 🔥 超大规模自动优化：当token数量>500时，只更新关键状态变化
    if (!PERFORMANCE_MODE.value && tokenCount > 500) {
      // 只保留关键状态变化（开始、完成、失败）
      if (!updates.status || updates.status === 'executing') {
        // 跳过执行中的细节更新（如currentTask、progress）
        return
      }
    }
    
    // 合并待更新的数据
    const existing = pendingUIUpdates.get(tokenId) || {}
    pendingUIUpdates.set(tokenId, { ...existing, ...updates })
    
    // 如果没有定时器，创建一个
    if (!uiUpdateTimer) {
      uiUpdateTimer = setTimeout(() => {
        // 🚀 批量应用所有更新（创建新对象引用，确保shallowRef能检测到变化）
        const newProgress = { ...taskProgress.value }
        pendingUIUpdates.forEach((updates, id) => {
          if (newProgress[id]) {
            newProgress[id] = {
              ...newProgress[id],
              ...updates
            }
          }
          // 🆕 立即清空对象引用，帮助GC回收
          pendingUIUpdates.set(id, null)
        })
        
        // 替换整个taskProgress对象
        taskProgress.value = newProgress
        
        // 清空Map
        pendingUIUpdates.clear()
        
        uiUpdateTimer = null
        
        // 🆕 强制建议垃圾回收（仅在开发模式下）
        if (typeof window !== 'undefined' && window.gc && process.env.NODE_ENV === 'development') {
          window.gc()
        }
      }, getDynamicThrottleDelay()) // 🔥 v3.14.0: 动态节流延迟
    }
  }
  
  /**
   * 🆕 v3.13.5: 强制清空UI更新队列（释放内存）
   */
  const clearPendingUIUpdates = () => {
    // 清空所有待更新数据的引用
    pendingUIUpdates.forEach((updates, id) => {
      pendingUIUpdates.set(id, null)
    })
    pendingUIUpdates.clear()
    
    // 清除定时器
    if (uiUpdateTimer) {
      clearTimeout(uiUpdateTimer)
      uiUpdateTimer = null
    }
    
    if (logConfig.value.batch) {
      console.log('🧹 [内存清理] 已清空UI更新队列')
    }
  }
  
  /**
   * 立即更新（关键更新使用：开始、完成、失败）
   * 🚀 性能优化：使用triggerRef手动触发shallowRef更新
   */
  const updateTaskProgressImmediate = (tokenId, updates) => {
    if (taskProgress.value[tokenId]) {
      // 🚀 创建新对象引用，确保Vue能检测到变化（shallowRef需要替换整个子对象才能触发更新）
      taskProgress.value = {
        ...taskProgress.value,
        [tokenId]: {
          ...taskProgress.value[tokenId],
          ...updates
        }
      }
    }
  }
  
  // ==================== 辅助函数 ====================
  
  /**
   * 获取今日BOSS ID
   */
  const getTodayBossId = () => {
    const DAY_BOSS_MAP = [9904, 9905, 9901, 9902, 9903, 9904, 9905] // 周日~周六
    const dayOfWeek = new Date().getDay()
    return DAY_BOSS_MAP[dayOfWeek]
  }
  
  /**
   * 切换阵容（简化版，直接切换到阵容1）
   */
  const switchToFormation = async (client, formationId = 1) => {
    try {
      await client.sendWithPromise('presetteam_changeteam', { 
        teamId: formationId 
      }, 1000)
      if (logConfig.value.batch) console.log(`✅ 已切换到阵容${formationId}`)
      await new Promise(resolve => setTimeout(resolve, 300))
    } catch (error) {
      if (logConfig.value.batch) console.log(`⚠️ 阵容切换失败: ${error.message}`)
    }
  }
  
  // ==================== 状态管理 ====================
  
  // 任务执行状态
  const isExecuting = ref(false)
  const isPaused = ref(false)
  const currentBatch = ref(null)
  const currentBatchId = ref(null) // 🔥 新增：当前批次ID，用于区分不同的执行批次
  const showProgress = ref(false) // 是否显示进度区域（执行完成后不自动隐藏）
  
  // 并发控制
  const maxConcurrency = ref(
    parseInt(localStorage.getItem('maxConcurrency') || '10')
  ) // 最大并发数（可配置1-100）- 默认10（稳健值）
  const executingTokens = ref(new Set()) // 正在执行的Token ID集合
  
  // 爬塔配置
  const climbTowerCount = ref(
    parseInt(localStorage.getItem('climbTowerCount') || '10')
  ) // 爬塔次数（0-100，默认10次）
  
  // 发车配置
  const carRefreshCount = ref(
    parseInt(localStorage.getItem('carRefreshCount') || '1')
  ) // 发车前刷新次数（0-10，0表示跳过刷新）
  
  // 任务进度追踪 { tokenId: { status, progress, currentTask, error, result } }
  // 🚀 性能优化：使用shallowRef避免深度响应式，减少700个token时的性能开销
  const taskProgress = shallowRef({})
  
  // 执行统计
  const executionStats = ref({
    total: 0,
    success: 0,
    failed: 0,
    skipped: 0,
    startTime: null,
    endTime: null
  })
  
  // 🆕 失败原因统计（用于UI显示）
  // 🔧 独立存储，不依赖taskProgress，支持增量更新
  const failureReasonsStats = ref({})
  
  /**
   * 🆕 从错误信息中提取失败原因（返回数组，因为可能有多个子任务失败）
   */
  const extractFailureReason = (errorMsg) => {
    if (!errorMsg) return ['未知原因（无错误信息）']
    
    const errorStr = String(errorMsg)
    const reasons = []
    
    // 🔍 如果是"部分任务失败"或"所有任务失败"，提取详细失败原因
    if (errorStr.includes('部分任务失败') || errorStr.includes('所有任务执行失败')) {
      const detailMatch = errorStr.match(/:\s*(.+)$/)
      if (detailMatch) {
        const details = detailMatch[1]
        const failedTaskDetails = details.split(';').map(s => s.trim()).filter(s => s)
        
        if (failedTaskDetails.length > 0) {
          failedTaskDetails.forEach(taskDetail => {
            let taskReason = taskDetail
            
            // 提取具体的错误原因
            if (taskDetail.includes('WebSocket未在') && taskDetail.includes('内连接')) {
              taskReason = 'WebSocket连接超时'
            } else if (taskDetail.includes('WebSocket未连接') || taskDetail.includes('连接失败') || taskDetail.includes('WebSocket is closed')) {
              taskReason = 'WebSocket连接失败'
            } else if (taskDetail.includes('服务器维护时间')) {
              taskReason = '服务器维护时间（周五 04:45-07:15）'
            } else if (taskDetail.includes('请求超时') || taskDetail.includes('timeout')) {
              taskReason = '请求超时'
            } else if (taskDetail.includes('200400')) {
              taskReason = '服务器限流 (200400)'
            } else if (taskDetail.includes('200350')) {
              taskReason = '服务器限流 (200350)'
            } else if (taskDetail.includes('3100080')) {
              taskReason = '未知错误 3100080'
            } else if (taskDetail.includes('2300190')) {
              taskReason = '未知错误 2300190'
            } else if (taskDetail.includes('2300070')) {
              taskReason = '未加入俱乐部 (2300070)'
            }
            
            // 提取任务名称
            const taskNameMatch = taskDetail.match(/^([^(]+)\(/)
            if (taskNameMatch) {
              const taskName = taskNameMatch[1]
              taskReason = `${taskName}: ${taskReason}`
            }
            
            reasons.push(taskReason)
          })
          return reasons
        }
      }
      
      // 如果无法解析详细信息
      reasons.push('部分任务失败（详细信息解析失败）')
      return reasons
    }
    
    // 🔍 普通错误消息的处理
    let reason = '其他错误'
    
    if (errorStr.includes('WebSocket未在') && errorStr.includes('内连接')) {
      reason = 'WebSocket连接超时'
    } else if (errorStr.includes('WebSocket未连接') || errorStr.includes('连接失败') || errorStr.includes('WebSocket is closed')) {
      reason = 'WebSocket连接失败'
    } else if (errorStr.includes('服务器维护时间')) {
      reason = '服务器维护时间（周五 04:45-07:15）'
    } else if (errorStr.includes('请求超时') || errorStr.includes('timeout')) {
      reason = '请求超时'
    } else if (errorStr.includes('200400')) {
      reason = '服务器限流 (200400)'
    } else if (errorStr.includes('200350')) {
      reason = '服务器限流 (200350)'
    } else if (errorStr.includes('3100080')) {
      reason = '未知错误 3100080'
    } else if (errorStr.includes('2300190')) {
      reason = '未知错误 2300190'
    } else if (errorStr.includes('2300070')) {
      reason = '未加入俱乐部 (2300070)'
    } else {
      reason = `其他错误: ${errorStr.substring(0, 80)}${errorStr.length > 80 ? '...' : ''}`
    }
    
    return [reason]
  }

  /**
   * 🔧 v3.13.5.6: 收集当前所有失败Token的原因统计
   * 提取为独立函数，供保存进度和完成任务时使用
   * ⚠️ 此函数现在主要用于调试和验证，实际统计使用增量更新方式
   */
  const collectFailureReasons = () => {
    const failureReasons = {}
    let processedCount = 0 // 🔧 统计已处理的失败Token数
    
    Object.entries(taskProgress.value).forEach(([tokenId, progress]) => {
      if (progress.status === 'failed') {
        let reason = '未知原因（无错误信息）'
        let reasonProcessed = false // 🔧 标记是否成功处理了这个失败原因
        
        if (progress.error) {
          const errorMsg = String(progress.error)
          
          // 🔍 如果是"部分任务失败"或"所有任务失败"，提取详细失败原因
          if (errorMsg.includes('部分任务失败') || errorMsg.includes('所有任务执行失败')) {
            // 提取 ": " 后面的详细信息
            const detailMatch = errorMsg.match(/:\s*(.+)$/)
            if (detailMatch) {
              const details = detailMatch[1]
              // 按 ";" 分割多个任务失败
              const failedTaskDetails = details.split(';').map(s => s.trim()).filter(s => s)
              
              // 为每个失败的子任务单独统计
              if (failedTaskDetails.length > 0) {
                failedTaskDetails.forEach(taskDetail => {
                  let taskReason = taskDetail
                  
                  // 尝试提取具体的错误原因
                  if (taskDetail.includes('WebSocket未在') && taskDetail.includes('内连接')) {
                    taskReason = 'WebSocket连接超时'
                  } else if (taskDetail.includes('WebSocket未连接') || taskDetail.includes('连接失败') || taskDetail.includes('WebSocket is closed')) {
                    taskReason = 'WebSocket连接失败'
                  } else if (taskDetail.includes('服务器维护时间')) {
                    taskReason = '服务器维护时间（周五 04:45-07:15）'
                  } else if (taskDetail.includes('请求超时') || taskDetail.includes('timeout')) {
                    taskReason = '请求超时'
                  } else if (taskDetail.includes('200400')) {
                    taskReason = '服务器限流 (200400)'
                  } else if (taskDetail.includes('200350')) {
                    taskReason = '服务器限流 (200350)'
                  } else if (taskDetail.includes('3100080')) {
                    taskReason = '未知错误 3100080'
                  } else if (taskDetail.includes('2300190')) {
                    taskReason = '未知错误 2300190'
                  } else if (taskDetail.includes('2300070')) {
                    taskReason = '未加入俱乐部 (2300070)'
                  }
                  
                  // 提取任务名称（格式：任务名(错误信息)）
                  const taskNameMatch = taskDetail.match(/^([^(]+)\(/)
                  if (taskNameMatch) {
                    const taskName = taskNameMatch[1]
                    taskReason = `${taskName}: ${taskReason}`
                  }
                  
                  failureReasons[taskReason] = (failureReasons[taskReason] || 0) + 1
                })
                reasonProcessed = true
                processedCount++
                return // 已处理完这个Token，跳过下面的逻辑
              }
            }
            
            // 🔧 如果无法解析详细信息，仍然统计为一个失败（避免漏统计）
            if (!reasonProcessed) {
              reason = '部分任务失败（详细信息解析失败）'
            }
          }
          
          // 🔍 普通错误消息的处理（仅在未被上面处理时执行）
          if (!reasonProcessed) {
            reason = '其他错误'
            
            if (errorMsg.includes('WebSocket未在') && errorMsg.includes('内连接')) {
              reason = 'WebSocket连接超时'
            } else if (errorMsg.includes('WebSocket未连接') || errorMsg.includes('连接失败') || errorMsg.includes('WebSocket is closed')) {
              reason = 'WebSocket连接失败'
            } else if (errorMsg.includes('服务器维护时间')) {
              reason = '服务器维护时间（周五 04:45-07:15）'
            } else if (errorMsg.includes('请求超时') || errorMsg.includes('timeout')) {
              reason = '请求超时'
            } else if (errorMsg.includes('200400')) {
              reason = '服务器限流 (200400)'
            } else if (errorMsg.includes('200350')) {
              reason = '服务器限流 (200350)'
            } else if (errorMsg.includes('3100080')) {
              reason = '未知错误 3100080'
            } else if (errorMsg.includes('2300190')) {
              reason = '未知错误 2300190'
            } else if (errorMsg.includes('2300070')) {
              reason = '未加入俱乐部 (2300070)'
            } else {
              // 🔧 保留原始错误信息（截取前80个字符）
              reason = `其他错误: ${errorMsg.substring(0, 80)}${errorMsg.length > 80 ? '...' : ''}`
            }
          }
        }
        
        // 🔧 确保每个失败的Token都被统计到（即使上面已经处理过"部分任务失败"的详细信息）
        if (!reasonProcessed) {
          failureReasons[reason] = (failureReasons[reason] || 0) + 1
          processedCount++
        }
      }
    })
    
    // 🔧 调试信息：确保统计数量正确
    const totalFailed = Object.values(taskProgress.value).filter(p => p.status === 'failed').length
    const totalCounted = Object.values(failureReasons).reduce((sum, count) => sum + count, 0)
    if (totalFailed !== totalCounted && logConfig.value.batch) {
      console.warn(`⚠️ 失败原因统计数量不匹配: 失败Token数=${totalFailed}, 统计数=${totalCounted}`)
    }
    
    return failureReasons
  }
  
  // 🚀 性能优化：限制历史记录数量（最近5次，从10次减少）
  const executionHistory = ref(
    (() => {
      try {
        const history = JSON.parse(localStorage.getItem('batchTaskHistory') || '[]')
        // 只保留最近5条记录
        return history.slice(0, 5)
      } catch {
        return []
      }
    })()
  )
  
  // 任务模板定义
  const taskTemplates = ref(
    (() => {
      const defaultTemplates = {
        '完整套餐': {
          name: '完整套餐',
          tasks: ['dailyFix', 'restartBottle', 'legionSignIn', 'autoStudy', 'claimHangupReward', 'addClock', 'sendCar', 'climbTower', 'blackMarket'],
          enabled: true
        },
        '除发车外的完整任务': {
          name: '除发车外的完整任务',
          tasks: ['dailyFix', 'restartBottle', 'legionSignIn', 'autoStudy', 'claimHangupReward', 'addClock', 'climbTower'],
          enabled: true
        },
        '除一键补差外完整任务': {
          name: '除一键补差外完整任务',
          tasks: ['restartBottle', 'legionSignIn', 'autoStudy', 'claimHangupReward', 'addClock', 'sendCar', 'climbTower'],
          enabled: true
        },
        '仅一键补差': {
          name: '仅一键补差',
          tasks: ['dailyFix'],
          enabled: true
        },
        '盐罐挂机': {
          name: '盐罐挂机',
          tasks: ['restartBottle', 'claimHangupReward', 'addClock'],
          enabled: true
        },
        '小号黑市购买': {
          name: '小号黑市购买',
          tasks: ['blackMarket'],
          enabled: true
        }
      }
      
      const saved = localStorage.getItem('taskTemplates')
      if (!saved) return defaultTemplates
      
      const templates = JSON.parse(saved)
      
      // 🆕 迁移逻辑：如果没有"小号黑市购买"模板，自动添加
      if (!templates['小号黑市购买']) {
        templates['小号黑市购买'] = {
          name: '小号黑市购买',
          tasks: ['blackMarket'],
          enabled: true
        }
        // 保存更新后的模板
        localStorage.setItem('taskTemplates', JSON.stringify(templates))
        console.log('✅ 已自动添加"小号黑市购买"任务模板')
      }
      
      return templates
    })()
  )
  
  // 当前选中的任务模板
  const selectedTemplate = ref('完整套餐')
  
  // 定时任务配置
  const schedulerConfig = ref(
    JSON.parse(localStorage.getItem('schedulerConfig') || JSON.stringify({
      enabled: false,
      type: 'interval', // 'interval' | 'daily'
      interval: 240, // 分钟（默认240分钟=4小时）
      dailyTimes: ['01:00', '06:15', '12:30', '18:00'], // 每日执行时间（兼容旧版）
      dailySchedules: [ // 🆕 每日定时详细配置（新版）- 直接指定任务列表
        { time: '01:00', tasks: ['dailyFix', 'restartBottle', 'legionSignIn', 'autoStudy', 'claimHangupReward', 'addClock', 'climbTower'] },
        { time: '06:15', tasks: ['dailyFix', 'restartBottle', 'legionSignIn', 'autoStudy', 'claimHangupReward', 'addClock', 'sendCar', 'climbTower'] },
        { time: '12:30', tasks: ['dailyFix', 'restartBottle', 'legionSignIn', 'autoStudy', 'claimHangupReward', 'addClock', 'sendCar', 'climbTower'] },
        { time: '18:00', tasks: ['restartBottle', 'claimHangupReward', 'addClock'] }
      ],
      lastExecutionTime: null
    }))
  )
  
  // 自动重试配置
  const autoRetryConfig = ref(
    JSON.parse(localStorage.getItem('autoRetryConfig') || JSON.stringify({
      enabled: true, // 默认启用自动重试
      maxRetries: 1, // 默认最大重试轮数为1
      retryDelay: 5000 // 默认重试间隔5秒
    }))
  )
  
  // 当前重试轮数计数
  const currentRetryRound = ref(0)
  
  // 🔥 自动重试等待标志（用于响应用户停止）
  const isAutoRetryWaiting = ref(false)

  // ==================== 计算属性 ====================
  
  // 当前执行进度百分比
  // 🔧 v3.13.5.8: 改用executionStats计算，避免shallowRef导致的响应式问题
  // 🔥 v3.14.2: 自动重试时显示准确的进度
  const overallProgress = computed(() => {
    const total = executionStats.value.total
    if (total === 0) return 0
    
    const completed = executionStats.value.success + executionStats.value.failed + executionStats.value.skipped
    
    // 🔥 如果正在自动重试，进度条不会回退
    // 因为重试时 success 保持不变，只有 failed 在增加
    // 例如：第1次 910成功+5失败 = 100%
    //      重试中 910成功+0失败 = 99.5%（会回退）
    //      重试后 910成功+5失败/成功 = 100%
    
    return Math.round((completed / total) * 100)
  })
  
  // 是否可以开始执行
  const canExecute = computed(() => {
    return !isExecuting.value && tokenStore.hasTokens
  })
  
  // 当前选中模板的任务列表
  const currentTemplateTasks = computed(() => {
    const template = taskTemplates.value[selectedTemplate.value]
    return template ? template.tasks : []
  })

  // ==================== 核心方法 ====================
  
  /**
   * 开始批量执行任务
   * @param {Array} tokenIds - 要执行的Token ID列表，不传则执行所有Token
   * @param {Array} tasks - 要执行的任务列表，不传则使用当前模板
   * @param {Boolean} isRetry - 是否为重试执行
   */
  const startBatchExecution = async (tokenIds = null, tasks = null, isRetry = false, continueFromSaved = false) => {
    if (isExecuting.value) {
      if (logConfig.value.batch) console.warn('⚠️ 批量任务正在执行中')
      return
    }
    
    // 🔥 v3.14.1: 开始前清理UI相关资源（修复停止后再开始CPU和内存占用高的问题）
    if (uiUpdateTimer) {
      clearTimeout(uiUpdateTimer)
      uiUpdateTimer = null
    }
    pendingUIUpdates.clear()
    
    // 清空正在执行的token集合
    executingTokens.value.clear()
    
    // 停止旧的定期清理定时器
    stopPeriodicCleanup()
    
    // 停止旧的内存监控
    stopMemoryMonitor()
    
    // ⚠️ 注意：wsPool 不在这里清理，因为连接池模式会自动创建新的，并在 finally 中清理
    
    if (logConfig.value.batch) {
      console.log('🧹 [内存清理] 开始前已清理UI和定时器资源')
    }
    
    // 🛠️ 检查服务器维护时间
    const maintenanceCheck = checkMaintenanceTime()
    if (maintenanceCheck.inMaintenance) {
      console.warn(`🛠️ ${maintenanceCheck.message}`)
      alert(`🛠️ ${maintenanceCheck.message}`)
      return
    }
    
    let targetTokens = tokenIds || tokenStore.gameTokens.map(t => t.id)
    let targetTasks = tasks || currentTemplateTasks.value
    let completedTokenIds = []
    
    // 🆕 检查是否要从保存的进度继续
    if (continueFromSaved && savedProgress.value && hasSavedProgress.value) {
      if (logConfig.value.batch) console.log('📂 从上次保存的进度继续执行')
      targetTokens = savedProgress.value.allTokenIds
      targetTasks = savedProgress.value.tasks
      completedTokenIds = savedProgress.value.completedTokenIds
      
      // 🔧 修复：检查当前token列表是否与保存的匹配，如果不匹配需要重新计算total
      const currentAvailableTokenIds = tokenStore.gameTokens.map(t => t.id)
      const stillExistTokens = targetTokens.filter(id => currentAvailableTokenIds.includes(id))
      const stillExistCompleted = completedTokenIds.filter(id => currentAvailableTokenIds.includes(id))
      
      // 如果token数量有变化，更新列表并重新计算统计
      if (stillExistTokens.length !== targetTokens.length) {
        console.warn(`⚠️ Token列表已变化：原${targetTokens.length}个 → 现${stillExistTokens.length}个`)
        targetTokens = stillExistTokens
        completedTokenIds = stillExistCompleted
      }
      
      // 恢复统计数据，但total使用当前实际的token数量
      executionStats.value = {
        ...executionStats.value,
        total: targetTokens.length, // 🔧 修复：使用当前实际token数量
        success: savedProgress.value.stats.success,
        failed: savedProgress.value.stats.failed,
        skipped: savedProgress.value.stats.skipped
      }
      
      // 🔧 修复：恢复失败原因统计（如果有保存）
      if (savedProgress.value.failureReasons) {
        failureReasonsStats.value = savedProgress.value.failureReasons
        console.log(`📊 已恢复失败原因统计：${Object.keys(savedProgress.value.failureReasons).length}种原因`)
      }
      
      if (logConfig.value.batch) {
        if (logConfig.value.batch) console.log(`✅ 已完成: ${completedTokenIds.length}/${targetTokens.length} 个Token`)
        if (logConfig.value.batch) console.log(`🔄 继续执行剩余 ${targetTokens.length - completedTokenIds.length} 个Token`)
      }
    } else {
      // 🆕 如果是全新开始，清除之前保存的进度
      if (!isRetry && savedProgress.value) {
        clearSavedProgress()
      }
    }
    
    if (targetTokens.length === 0) {
      if (logConfig.value.batch) console.warn('⚠️ 没有可用的Token')
      return
    }
    
    if (targetTasks.length === 0) {
      if (logConfig.value.batch) console.warn('⚠️ 没有选中任务')
      return
    }
    
    // 🆕 如果是首次执行（不是重试），重置重试轮数
    if (!isRetry) {
      currentRetryRound.value = 0
      isAutoRetryWaiting.value = false  // 🔥 清除自动重试等待标志
    }
    
    if (logConfig.value.batch) {
      if (logConfig.value.batch) console.log(`🚀 开始批量执行任务${isRetry ? ' (重试)' : ''}`)
      if (logConfig.value.batch) console.log(`📋 Token数量: ${targetTokens.length}`)
      if (isRetry) {
        if (logConfig.value.batch) console.log(`📋 重试Token列表:`, targetTokens)
      }
      if (logConfig.value.batch) console.log(`📋 任务列表:`, targetTasks)
    }
    
    // 重置状态
    isExecuting.value = true
    isPaused.value = false
    showProgress.value = true // 显示进度区域
    currentBatchId.value = Date.now() // 🔥 生成新的批次ID
    executingTokens.value.clear()
    
    // 🆕 如果不是继续执行，重置taskProgress
    if (!continueFromSaved) {
      // 如果是重试模式，保留成功的token进度，只重置失败的token
      if (isRetry) {
        // 🔥 标记哪些token之前失败过，用于重试成功时调整统计
        targetTokens.forEach(tokenId => {
          if (taskProgress.value[tokenId] && taskProgress.value[tokenId].status === 'failed') {
            // 保存一个标记，表示这个token之前失败过
            const wasFailed = true
            // 删除旧的进度记录
            delete taskProgress.value[tokenId]
            // 创建新的进度记录，带上标记
            taskProgress.value[tokenId] = {
              status: 'pending',
              previouslyFailed: wasFailed  // 🔥 标记之前失败过
            }
          } else if (taskProgress.value[tokenId]) {
            delete taskProgress.value[tokenId]
          }
        })
        
        if (logConfig.value.batch) {
          console.log(`🏷️ [重试] 已标记 ${targetTokens.length} 个token为重试状态`)
        }
      } else {
        // 全新开始，清空所有进度
        taskProgress.value = {}
      }
    }
    
    // 100并发优化：禁用动画以提升性能
    document.body.classList.add('batch-task-executing')
    
    // 🆕 初始化统计（如果不是继续执行）
    if (!continueFromSaved) {
      if (isRetry) {
        // 🔥 重试模式：保持所有已完成的统计，避免进度条回退
        // 关键：保持 failed 不变，这样进度条不会回退
        // 重试成功的会增加 success，重试失败的会保持 failed
        const previousStats = { ...executionStats.value }
        
        executionStats.value = {
          total: previousStats.total,  // 保持总数
          success: previousStats.success,  // 保持成功数
          failed: previousStats.failed,  // 🔥 保持失败数（不重置）
          skipped: previousStats.skipped,  // 保持跳过数
          startTime: Date.now(),
          endTime: null
        }
        
        if (logConfig.value.batch) {
          console.log(`📊 [重试] 初始统计: 总${previousStats.total} | 成功${previousStats.success} | 失败${previousStats.failed} | 跳过${previousStats.skipped}`)
        }
      } else {
        // 全新开始：重置所有统计
        executionStats.value = {
          total: targetTokens.length,
          success: 0,
          failed: 0,
          skipped: 0,
          startTime: Date.now(),
          endTime: null
        }
        
        // 🔧 清空失败原因统计（只在全新开始时清空）
        failureReasonsStats.value = {}
        if (logConfig.value.batch) console.log('🗑️ 已清空失败原因统计（开始新任务）')
      }
    } else {
      // 继续执行时，保持原有统计，只更新开始时间
      executionStats.value.startTime = Date.now()
    }
    
    // 初始化每个Token的进度
    targetTokens.forEach(tokenId => {
      // 🆕 跳过已完成的token
      if (completedTokenIds.includes(tokenId)) {
        // 已完成的token标记为跳过状态（在UI上不显示）
        if (!taskProgress.value[tokenId]) {
          taskProgress.value[tokenId] = {
            status: 'completed',
            progress: 100,
            currentTask: null,
            tasksCompleted: targetTasks.length,
            tasksTotal: targetTasks.length,
            error: null,
            result: {},
            startTime: null,
            endTime: null
          }
        }
      } else {
        // 未完成的token初始化为pending状态
        taskProgress.value[tokenId] = {
          status: 'pending',
          progress: 0,
          currentTask: null,
          tasksCompleted: 0,
          tasksTotal: targetTasks.length,
          error: null,
          result: {},
          startTime: null,
          endTime: null
        }
      }
    })
    
    // 创建批次信息
    currentBatch.value = {
      id: `batch_${Date.now()}`,
      tokens: targetTokens,
      tasks: targetTasks,
      startTime: Date.now()
    }
    
    // 🔥 v3.14.0: 启动内存监控
    startMemoryMonitor()
    
    // 🆕 过滤出需要执行的token（排除已完成的）
    const tokensToExecute = targetTokens.filter(id => !completedTokenIds.includes(id))
    
    // 🆕 根据配置选择执行模式（v3.13.0）
    if (USE_CONNECTION_POOL.value) {
      // 🌟 连接池模式（推荐用于100并发）- v3.13.3修复版
      if (logConfig.value.batch) {
        if (logConfig.value.batch) console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🏊 连接池模式已启用 (v3.13.3 修复版)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
连接池大小: ${POOL_SIZE.value} (同时存在的最大连接数)
Token数量: ${tokensToExecute.length}
工作方式: 每个token使用自己的连接（不复用给其他token）
           100个token排队使用${POOL_SIZE.value}个连接名额
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
      }
      
      // 初始化连接池
      wsPool = new WebSocketPool({
        poolSize: POOL_SIZE.value,
        reconnectWebSocket: tokenStore.reconnectWebSocket,
        closeConnection: tokenStore.closeWebSocketConnection,
        connectionInterval: CONNECTION_INTERVAL.value, // 连接间隔时间
        shouldContinue: () => isExecuting.value  // 🔥 传递停止检查函数
      })
      
      try {
        // 使用连接池模式执行
        await executeBatchWithPool(tokensToExecute, targetTasks, targetTokens, completedTokenIds)
      } finally {
        // 清理连接池
        if (wsPool) {
          await wsPool.cleanup()
          wsPool = null
        }
      }
    } else {
      // 🔧 传统模式（兼容性）
      if (logConfig.value.batch) {
        if (logConfig.value.batch) console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚙️ 传统模式
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
并发数: ${maxConcurrency.value}
Token数量: ${tokensToExecute.length}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
      }
      
      // 执行批量任务（使用并发控制）
      await executeBatchWithConcurrency(tokensToExecute, targetTasks, targetTokens, completedTokenIds)
    }
    
    // 完成执行
    await finishBatchExecution()
  }
  
  /**
   * 使用并发控制执行批量任务（带连接错开机制）
   * @param {Array} tokenIds - 需要执行的Token ID列表
   * @param {Array} tasks - 任务列表
   * @param {Array} allTokenIds - 所有Token ID列表（包括已完成的）
   * @param {Array} completedTokenIds - 已完成的Token ID列表
   */
  const executeBatchWithConcurrency = async (tokenIds, tasks, allTokenIds = null, completedTokenIds = []) => {
    const queue = [...tokenIds]
    const executing = []
    let connectionIndex = 0 // 连接序号，用于计算错开时间
    const completed = [...completedTokenIds] // 已完成的token列表（用于保存进度）
    const all = allTokenIds || tokenIds // 所有token列表
    
    while (queue.length > 0 || executing.length > 0) {
      // 🔥 检查是否已停止
      if (!isExecuting.value) {
        if (logConfig.value.batch) {
          console.log('🛑 [传统模式] 检测到停止信号，清空队列并等待执行中的任务完成')
          console.log(`   队列剩余: ${queue.length}, 执行中: ${executing.length}`)
        }
        queue.length = 0 // 清空队列，不再启动新任务
        if (executing.length === 0) {
          break // 如果没有执行中的任务，直接退出
        }
        // 否则等待执行中的任务完成
        await new Promise(resolve => setTimeout(resolve, 500))
        continue
      }
      
      // 检查是否暂停
      if (isPaused.value) {
        await new Promise(resolve => setTimeout(resolve, 500))
        continue
      }
      
      // 🛠️ 检查服务器维护时间（每次循环都检查）
      const maintenanceCheck = checkMaintenanceTime()
      if (maintenanceCheck.inMaintenance) {
        console.warn(`🛠️ ${maintenanceCheck.message}`)
        console.warn(`🛠️ 自动停止剩余任务执行，等待维护结束`)
        // 清空队列，停止新任务，但等待当前执行中的任务完成
        queue.length = 0
        if (executing.length === 0) {
          break
        }
      }
      
      // 填充执行队列（最多maxConcurrency个）
      while (executing.length < maxConcurrency.value && queue.length > 0 && isExecuting.value) {
        const tokenId = queue.shift()
        
        // 🆕 关键优化：错开连接时间，避免服务器反批量检测
        // 每个连接间隔500ms（调整为稳健值）
        const delayMs = connectionIndex * 500
        connectionIndex++
        
        const promise = (async () => {
          // 等待指定时间后再建立连接
          if (delayMs > 0) {
            batchLog(`⏳ Token ${tokenId} 将在 ${(delayMs/1000).toFixed(1)}秒 后建立连接`)
            await new Promise(resolve => setTimeout(resolve, delayMs))
          }
          
          // 执行任务（传递当前批次ID）
          return executeTokenTasks(tokenId, tasks, currentBatchId.value)
        })()
          .then(() => {
            // 从执行队列中移除
            const index = executing.indexOf(promise)
            if (index > -1) {
              executing.splice(index, 1)
            }
            executingTokens.value.delete(tokenId)
            
            // 🆕 保存进度：记录此token已完成
            completed.push(tokenId)
            saveExecutionProgress(completed, all, tasks)
            
            // 🆕 v3.13.5: 增量清理 - 每完成100个token清理一次进度数据
            if (completed.length % 100 === 0) {
              const cleaned = forceCleanupTaskProgress()
              clearPendingUIUpdates()
              console.log(`🧹 [自动清理] 已完成 ${completed.length} 个token，清理了 ${cleaned} 个任务数据`)
            }
          })
          .catch(error => {
            if (logConfig.value.batch) {
              if (logConfig.value.batch) console.error(`❌ Token ${tokenId} 执行失败:`, error)
            }
            
            // 🆕 确保失败计数被正确更新
            // 如果 executeTokenTasks 内部已经更新了状态，这里不会重复更新
            // 但如果是在到达 executeTokenTasks 之前就失败了，需要在这里更新
            const tokenProgress = taskProgress.value[tokenId]
            if (!tokenProgress || tokenProgress.status === 'pending' || tokenProgress.status === 'executing') {
              // 只有当状态还未最终确定时才更新
              updateTaskProgress(tokenId, {
                status: 'failed',
                error: error.message,
                endTime: Date.now()
              })
              executionStats.value.failed++
            }
            
            const index = executing.indexOf(promise)
            if (index > -1) {
              executing.splice(index, 1)
            }
            executingTokens.value.delete(tokenId)
            
            // 🆕 保存进度：即使失败也记录为已完成（避免下次重复执行）
            completed.push(tokenId)
            saveExecutionProgress(completed, all, tasks)
            
            // 🆕 v3.13.5: 增量清理 - 每完成100个token清理一次进度数据
            if (completed.length % 100 === 0) {
              const cleaned = forceCleanupTaskProgress()
              clearPendingUIUpdates()
              console.log(`🧹 [自动清理] 已完成 ${completed.length} 个token，清理了 ${cleaned} 个任务数据`)
            }
          })
        
        executing.push(promise)
        executingTokens.value.add(tokenId)
      }
      
      // 等待至少一个任务完成
      if (executing.length > 0) {
        await Promise.race(executing)
      }
    }
  }
  
  /**
   * 🆕 使用连接池执行批量任务（v3.13.2 优化版）
   * 
   * 核心改进：
   * 1. 连接池管理连接复用（突破浏览器限制）
   * 2. 并发控制避免请求拥堵（保护服务器）
   * 3. 滚动执行提升稳定性
   * 
   * @param {Array} tokenIds - 需要执行的Token ID列表
   * @param {Array} tasks - 任务列表
   * @param {Array} allTokenIds - 所有Token ID列表（包括已完成的）
   * @param {Array} completedTokenIds - 已完成的Token ID列表
   */
  const executeBatchWithPool = async (tokenIds, tasks, allTokenIds = null, completedTokenIds = []) => {
    const completed = [...completedTokenIds]
    const all = allTokenIds || tokenIds
    const queue = [...tokenIds]
    const executing = []
    
    // 🆕 v3.13.2 关键优化：限制同时执行的Token数量，避免请求拥堵
    const maxConcurrentExecution = MAX_CONCURRENT_REQUESTS.value
    
    if (logConfig.value.batch) {
      if (logConfig.value.batch) console.log(`
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🚀 [连接池模式 v3.13.3] 开始批量执行
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Token数量: ${tokenIds.length}
连接池大小: ${wsPool.poolSize} (同时存在的最大连接数)
同时执行数: ${maxConcurrentExecution} ⭐ 关键优化
任务列表: ${tasks.join(', ')}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
工作原理：
1. 最多${wsPool.poolSize}个token可以同时拥有连接
2. 但同时只有${maxConcurrentExecution}个token在执行任务
3. 每个token使用自己的连接（不复用给其他token）
4. 这样可以避免请求拥堵和账号混乱
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    `)
    }
    
    // 🔹 使用并发控制执行（类似传统模式，但使用连接池的连接）
    while (queue.length > 0 || executing.length > 0) {
      // 🔥 检查是否已停止
      if (!isExecuting.value) {
        if (logConfig.value.batch) {
          console.log('🛑 [连接池模式] 检测到停止信号，清空队列并等待执行中的任务完成')
          console.log(`   队列剩余: ${queue.length}, 执行中: ${executing.length}`)
        }
        queue.length = 0 // 清空队列，不再启动新任务
        if (executing.length === 0) {
          break // 如果没有执行中的任务，直接退出
        }
        // 否则等待执行中的任务完成
        await new Promise(resolve => setTimeout(resolve, 500))
        continue
      }
      
      // 检查是否暂停
      if (isPaused.value) {
        await new Promise(resolve => setTimeout(resolve, 500))
        continue
      }
      
      // 🛠️ 检查服务器维护时间（每次循环都检查）
      const maintenanceCheck = checkMaintenanceTime()
      if (maintenanceCheck.inMaintenance) {
        console.warn(`🛠️ ${maintenanceCheck.message}`)
        console.warn(`🛠️ 自动停止剩余任务执行，等待维护结束`)
        // 清空队列，停止新任务，但等待当前执行中的任务完成
        queue.length = 0
        if (executing.length === 0) {
          break
        }
      }
      
      // 填充执行队列（最多maxConcurrentExecution个）
      while (executing.length < maxConcurrentExecution && queue.length > 0 && isExecuting.value) {
        const tokenId = queue.shift()
        
        const promise = (async () => {
          // 添加到执行中集合
          executingTokens.value.add(tokenId)
          
          try {
            // 执行任务（会从连接池获取连接，传递当前批次ID）
            await executeTokenTasksWithPool(tokenId, tasks, currentBatchId.value)
            
            // 记录完成
            completed.push(tokenId)
            saveExecutionProgress(completed, all, tasks)
            
            // 🆕 v3.13.5: 增量清理 - 每完成100个token清理一次进度数据
            if (completed.length % 100 === 0) {
              const cleaned = forceCleanupTaskProgress()
              clearPendingUIUpdates()
              console.log(`🧹 [自动清理] 已完成 ${completed.length} 个token，清理了 ${cleaned} 个任务数据`)
            }
            
          } catch (error) {
            if (logConfig.value.batch) {
              if (logConfig.value.batch) console.error(`❌ [连接池] Token ${tokenId} 执行失败:`, error)
            }
            
            // 确保失败状态被正确记录
            const tokenProgress = taskProgress.value[tokenId]
            if (!tokenProgress || tokenProgress.status === 'pending' || tokenProgress.status === 'executing') {
              updateTaskProgress(tokenId, {
                status: 'failed',
                error: error.message || String(error),
                endTime: Date.now()
              })
              executionStats.value.failed++
            }
            
            // 即使失败也记录为已完成
            completed.push(tokenId)
            saveExecutionProgress(completed, all, tasks)
            
            // 🆕 v3.13.5: 增量清理 - 每完成100个token清理一次进度数据
            if (completed.length % 100 === 0) {
              const cleaned = forceCleanupTaskProgress()
              clearPendingUIUpdates()
              console.log(`🧹 [自动清理] 已完成 ${completed.length} 个token，清理了 ${cleaned} 个任务数据`)
            }
            
          } finally {
            // 从执行中集合移除
            executingTokens.value.delete(tokenId)
          }
        })()
          .then(() => {
            // 从执行队列中移除
            const index = executing.indexOf(promise)
            if (index > -1) {
              executing.splice(index, 1)
            }
          })
          .catch(error => {
            if (logConfig.value.batch) {
              if (logConfig.value.batch) console.error(`❌ Token ${tokenId} 执行异常:`, error)
            }
            const index = executing.indexOf(promise)
            if (index > -1) {
              executing.splice(index, 1)
            }
          })
        
        executing.push(promise)
        
        // 添加小延迟，避免同时启动导致瞬间压力
        // 🚀 性能优化：从200ms降至100ms
        await new Promise(resolve => setTimeout(resolve, 100))
      }
      
      // 等待至少一个任务完成
      if (executing.length > 0) {
        await Promise.race(executing)
      }
    }
    
    if (logConfig.value.batch) {
      if (logConfig.value.batch) console.log(`✅ [连接池模式 v3.13.3] 所有任务执行完成`)
    }
    
    // 打印连接池状态
    if (wsPool) {
      wsPool.printStatus()
    }
    
    // ⚠️ 注意：失败统计已移至 finishBatchExecution() 统一处理，避免重复打印
  }
  
  /**
   * 执行单个Token的所有任务
   */
  const executeTokenTasks = async (tokenId, tasks, batchId) => {
    const token = tokenStore.gameTokens.find(t => t.id === tokenId)
    if (!token) {
      if (logConfig.value.batch) console.warn(`⚠️ Token ${tokenId} 不存在`)
      updateTaskProgress(tokenId, {
        status: 'skipped',
        error: 'Token不存在',
        endTime: Date.now()
      })
      executionStats.value.skipped++
      return
    }
    
    batchLog(`🎯 开始执行 Token: ${token.name}`)
    
    // 🔥 在建立连接前检查批次ID
    if (batchId !== currentBatchId.value) {
      batchLog(`⚠️ [${token.name}] 批次已过期，任务取消（建立连接前）`)
      updateTaskProgress(tokenId, {
        status: 'skipped',
        message: '批次已过期',
        endTime: Date.now()
      })
      executionStats.value.skipped++
      return
    }
    
    // 更新状态为执行中
    updateTaskProgress(tokenId, {
      status: 'executing',
      startTime: Date.now()
    })
    
    try {
      // 🆕 确保WebSocket连接（带重试机制）
      const wsClient = await ensureConnection(tokenId, 5) // 重试5次
      
      // 🔥 连接建立后再次检查批次ID（ensureConnection是异步的）
      if (batchId !== currentBatchId.value) {
        batchLog(`⚠️ [${token.name}] 批次已过期，断开连接（建立连接后）`)
        try {
          tokenStore.closeWebSocketConnection(tokenId)
        } catch (e) {
          // 忽略关闭连接的错误
        }
        updateTaskProgress(tokenId, {
          status: 'skipped',
          message: '批次已过期',
          endTime: Date.now()
        })
        executionStats.value.skipped++
        return
      }
      
      if (!wsClient) {
        throw new Error('WebSocket连接失败')
      }
      
      // 🚀 极速优化：等待连接稳定从1秒降到100ms
      batchLog(`⏳ 等待连接稳定...`)
      await new Promise(resolve => setTimeout(resolve, 100))
      
      // 🛠️ 检查服务器维护时间（在开始执行任务前）
      const maintenanceCheck = checkMaintenanceTime()
      if (maintenanceCheck.inMaintenance) {
        throw new Error(`服务器维护时间，已自动停止任务`)
      }
      
      // 依次执行任务
      let taskFailedCount = 0 // 🆕 记录失败的任务数量
      
      for (let i = 0; i < tasks.length; i++) {
        if (isPaused.value) {
          if (logConfig.value.batch) console.log(`⏸️ 任务已暂停: ${token.name}`)
          break
        }
        
        const taskName = tasks[i]
        batchLog(`  📌 执行任务 [${i + 1}/${tasks.length}]: ${taskName}`)
        
        updateTaskProgress(tokenId, {
          currentTask: taskName,
          progress: Math.round(((i + 1) / tasks.length) * 100)
        })
        
        try {
          // 执行具体任务（传递batchId）
          const result = await executeTask(tokenId, taskName, null, batchId)
          
          // 检查任务是否真的成功（某些任务可能返回包含success字段的对象）
          const isSuccess = result?.success !== false
          
          if (!isSuccess) {
            // 任务返回失败标记
            if (logConfig.value.batch) console.error(`  ❌ 任务失败: ${taskName}`, result?.error || '未知错误')
            
            // 保存错误信息
            taskProgress.value[tokenId].result[taskName] = {
              success: false,
              error: result?.error || result?.message || '任务执行失败',
              data: result?.data
            }
            
            taskFailedCount++ // 增加失败计数
          } else {
            // 任务成功
          // 保存任务结果
          taskProgress.value[tokenId].result[taskName] = {
            success: true,
            data: result
          }
          
          // 更新完成数
          taskProgress.value[tokenId].tasksCompleted++
          
          batchLog(`  ✅ 任务完成: ${taskName}`)
          }
          
          // 🚀 极速优化：任务间隔从400ms降到50ms
          await new Promise(resolve => setTimeout(resolve, 50))
          
        } catch (error) {
          if (logConfig.value.batch) console.error(`  ❌ 任务异常: ${taskName}`, error.message)
          
          // 保存错误信息
          taskProgress.value[tokenId].result[taskName] = {
            success: false,
            error: error.message
          }
          
          taskFailedCount++ // 增加失败计数
          
          // 继续执行下一个任务（单个任务失败不影响整体）
        }
      }
      
      // 🆕 根据任务执行情况决定最终状态
      const hasAnyTaskFailed = taskFailedCount > 0
      const allTasksFailed = taskFailedCount === tasks.length
      
      if (hasAnyTaskFailed) {
        // 🔴 收集失败任务的详细信息
        const failedTasks = []
        const taskResults = taskProgress.value[tokenId].result
        
        for (const [taskName, taskResult] of Object.entries(taskResults)) {
          if (taskResult && !taskResult.success) {
            // 提取错误的关键信息（简化）
            let errorSummary = taskResult.error || '未知错误'
            // 截取前50个字符
            if (errorSummary.length > 50) {
              errorSummary = errorSummary.substring(0, 50) + '...'
            }
            failedTasks.push(`${taskName}(${errorSummary})`)
          }
        }
        
        const errorDetail = failedTasks.length > 0 
          ? failedTasks.join('; ')
          : `${taskFailedCount}个任务失败`
        
        // 🔴 任何任务失败（包括部分或全部）- 统一标记为失败，触发重试机制
        updateTaskProgress(tokenId, {
          status: 'failed',
          progress: 100,
          currentTask: null,
          error: allTasksFailed 
            ? `所有任务执行失败: ${errorDetail}`
            : `部分任务失败 (${taskFailedCount}/${tasks.length}): ${errorDetail}`,
          endTime: Date.now()
        })
        executionStats.value.failed++
        if (logConfig.value.batch) console.log(`❌ Token失败: ${token.name} (${taskFailedCount}/${tasks.length}个任务失败)`)
      } else {
        // 🟢 所有任务成功 - 标记为完成
        updateTaskProgress(tokenId, {
        status: 'completed',
        progress: 100,
        currentTask: null,
        endTime: Date.now()
      })
      
      // 🔥 如果这个token之前失败过（重试成功的情况）
      const wasPreviouslyFailed = taskProgress.value[tokenId]?.previouslyFailed === true
      if (wasPreviouslyFailed) {
        // 重试成功：failed--, success++
        executionStats.value.failed--
        if (logConfig.value.batch) console.log(`✅ Token重试成功: ${token.name} (失败 → 成功)`)
      }
      
      executionStats.value.success++
      if (logConfig.value.batch) console.log(`✅ Token完成: ${token.name}`)
      }
      
    } catch (error) {
      if (logConfig.value.batch) console.error(`❌ Token执行失败: ${token.name}`, error)
      
      updateTaskProgress(tokenId, {
        status: 'failed',
        error: error.message,
        endTime: Date.now()
      })
      
      executionStats.value.failed++
    } finally {
      // 任务完成后自动断开WebSocket连接
      try {
        if (tokenStore.wsConnections[tokenId]) {
          if (logConfig.value.batch) console.log(`🔌 断开WebSocket连接: ${token.name}`)
          tokenStore.closeWebSocketConnection(tokenId)
        }
      } catch (error) {
        if (logConfig.value.batch) console.warn(`⚠️ 断开连接失败: ${token.name}`, error.message)
      }
    }
  }
  
  /**
   * 🆕 使用连接池执行单个Token的所有任务（v3.13.3 修复版）
   * 修复：每个token使用自己的连接，不再复用给其他token
   * 优势：
   * 1. 通过连接池限制同时存在的连接数量
   * 2. 避免账号混乱问题
   * 3. 突破浏览器连接数限制
   */
  const executeTokenTasksWithPool = async (tokenId, tasks, batchId) => {
    const token = tokenStore.gameTokens.find(t => t.id === tokenId)
    if (!token) {
      if (logConfig.value.batch) console.warn(`⚠️ Token ${tokenId} 不存在`)
      updateTaskProgress(tokenId, {
        status: 'skipped',
        error: 'Token不存在',
        endTime: Date.now()
      })
      executionStats.value.skipped++
      return
    }
    
    const startTime = Date.now()
    let client = null
    
    try {
      // 🔹 步骤1：从连接池获取连接（可能需要等待）
      updateTaskProgress(tokenId, {
        status: 'waiting',
        message: '等待获取连接...',
        startTime
      })
      
      // 🔥 检查批次ID是否匹配（防止旧批次的任务在新批次中执行）
      if (batchId !== currentBatchId.value) {
        batchLog(`⚠️ [${token.name}] 批次已过期，任务取消 (旧批次: ${batchId}, 当前: ${currentBatchId.value})`)
        updateTaskProgress(tokenId, {
          status: 'skipped',
          message: '批次已过期',
          endTime: Date.now()
        })
        executionStats.value.skipped++
        return
      }
      
      // 🔥 检查wsPool是否仍然存在
      if (!wsPool) {
        batchLog(`⚠️ [${token.name}] 连接池已关闭，任务取消`)
        updateTaskProgress(tokenId, {
          status: 'skipped',
          message: '任务已停止',
          endTime: Date.now()
        })
        executionStats.value.skipped++
        return
      }
      
      batchLog(`🎫 [${token.name}] 请求连接...`)
      client = await wsPool.acquire(tokenId)
      
      // 🔥 再次检查批次ID（acquire是异步的，可能在等待期间被停止并重新开始）
      if (batchId !== currentBatchId.value) {
        batchLog(`⚠️ [${token.name}] 批次已过期，释放连接 (旧批次: ${batchId}, 当前: ${currentBatchId.value})`)
        if (client && wsPool) {
          await wsPool.release(tokenId)
        }
        updateTaskProgress(tokenId, {
          status: 'skipped',
          message: '批次已过期',
          endTime: Date.now()
        })
        executionStats.value.skipped++
        return
      }
      
      batchLog(`✅ [${token.name}] 获取连接成功 (此连接专属于此token)`)
      
      // 🛠️ 检查服务器维护时间（在开始执行任务前）
      const maintenanceCheck = checkMaintenanceTime()
      if (maintenanceCheck.inMaintenance) {
        throw new Error(`服务器维护时间，已自动停止任务`)
      }
      
      // 🔹 步骤2：更新状态为执行中
      updateTaskProgress(tokenId, {
        status: 'executing',
        message: '执行任务中...',
        currentTask: tasks[0] || '准备中'
      })
      
      // 🔹 步骤3：等待WebSocket连接真正建立（最多等待10秒，100并发下可能需要更长时间）
      const maxWaitTime = 10000
      const startWait = Date.now()
      let checkCount = 0
      
      while (!client.connected && Date.now() - startWait < maxWaitTime) {
        // 🔥 在等待循环中检查批次ID（防止卡在等待中）
        if (batchId !== currentBatchId.value) {
          batchLog(`⚠️ [${token.name}] 批次已过期，停止等待连接`)
          if (client && wsPool) {
            await wsPool.release(tokenId)
          }
          updateTaskProgress(tokenId, {
            status: 'skipped',
            message: '批次已过期',
            endTime: Date.now()
          })
          executionStats.value.skipped++
          return
        }
        
        checkCount++
        if (checkCount % 20 === 0) {
          // 每1秒（20次检查）打印一次等待状态
          const waitedSoFar = Date.now() - startWait
          batchLog(`  ⏳ [${token.name}] 等待WebSocket连接... (已等待 ${waitedSoFar}ms)`)
        }
        await new Promise(resolve => setTimeout(resolve, 50))
      }
      
      const waitedTime = Date.now() - startWait
      if (!client.connected) {
        batchLog(`  ❌ [${token.name}] WebSocket连接超时，已等待 ${waitedTime}ms`)
        throw new Error(`WebSocket未在${maxWaitTime}ms内连接 [${token.name}]`)
      }
      batchLog(`  ✅ [${token.name}] WebSocket连接已建立 (等待 ${waitedTime}ms)`)
      
      // 🔍 记录连接状态详情
      if (logConfig.value.batch) console.log(`🔍 [${token.name}] 连接状态详情:`, {
        connected: client.connected,
        hasSocket: !!client.socket,
        socketReadyState: client.socket?.readyState,
        socketReadyStateText: ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'][client.socket?.readyState] || 'unknown'
      })
      
      // 🔹 步骤4：依次执行所有任务
      let taskFailedCount = 0
      
      for (let i = 0; i < tasks.length; i++) {
        // 🔥 检查批次ID是否匹配（更精确的检查）
        if (batchId !== currentBatchId.value) {
          batchLog(`⏹️ [${token.name}] 批次已过期，终止执行 (旧批次: ${batchId}, 当前: ${currentBatchId.value})`)
          updateTaskProgress(tokenId, {
            status: 'skipped',
            message: '批次已过期'
          })
          executionStats.value.skipped++
          return
        }
        
        if (isPaused.value) {
          if (logConfig.value.batch) console.log(`⏸️ 任务已暂停: ${token.name}`)
          break
        }
        
        const taskName = tasks[i]
        batchLog(`  📌 [${token.name}] 执行任务 [${i + 1}/${tasks.length}]: ${taskName}`)
        
        // 🔍 执行前检查连接状态
        if (!client.connected) {
          if (logConfig.value.batch) console.warn(`⚠️ [${token.name}] 任务 ${taskName} 执行前检测到连接断开！`)
          if (logConfig.value.batch) console.warn(`   client.connected: ${client.connected}`)
          if (logConfig.value.batch) console.warn(`   socket.readyState: ${client.socket?.readyState}`)
        }
        
        updateTaskProgress(tokenId, {
          currentTask: taskName,
          progress: Math.round(((i + 1) / tasks.length) * 100)
        })
        
        try {
          // 执行具体任务（使用从连接池获取的client，传递batchId）
          const result = await executeTask(tokenId, taskName, client, batchId)
          
          // 检查任务是否真的成功
          const isSuccess = result?.success !== false
          
          if (!isSuccess) {
            if (logConfig.value.batch) console.error(`  ❌ 任务失败: ${taskName}`, result?.error || '未知错误')
            taskProgress.value[tokenId].result[taskName] = {
              success: false,
              error: result?.error || result?.message || '任务执行失败',
              data: result?.data
            }
            taskFailedCount++
          } else {
            // 任务成功
            taskProgress.value[tokenId].result[taskName] = {
              success: true,
              data: result
            }
            taskProgress.value[tokenId].tasksCompleted++
            batchLog(`  ✅ 任务完成: ${taskName}`)
          }
          
          // 🚀 极速优化：任务间隔从100-400ms降至50-150ms
          const taskRandomDelay = 50 + Math.floor(Math.random() * 101)
          await new Promise(resolve => setTimeout(resolve, taskRandomDelay))
          
        } catch (error) {
          if (logConfig.value.batch) console.error(`  ❌ 任务异常: ${taskName}`, error.message)
          taskProgress.value[tokenId].result[taskName] = {
            success: false,
            error: error.message
          }
          taskFailedCount++
        }
      }
      
      // 🔹 步骤5：更新最终状态
      const hasAnyTaskFailed = taskFailedCount > 0
      const allTasksFailed = taskFailedCount === tasks.length
      const duration = ((Date.now() - startTime) / 1000).toFixed(1)
      
      if (hasAnyTaskFailed) {
        // 🔴 收集失败任务的详细信息
        const failedTasks = []
        const taskResults = taskProgress.value[tokenId].result
        
        for (const [taskName, taskResult] of Object.entries(taskResults)) {
          if (taskResult && !taskResult.success) {
            // 提取错误的关键信息（简化）
            let errorSummary = taskResult.error || '未知错误'
            // 截取前50个字符
            if (errorSummary.length > 50) {
              errorSummary = errorSummary.substring(0, 50) + '...'
            }
            failedTasks.push(`${taskName}(${errorSummary})`)
          }
        }
        
        const errorDetail = failedTasks.length > 0 
          ? failedTasks.join('; ')
          : `${taskFailedCount}个任务失败`
        
        updateTaskProgress(tokenId, {
          status: 'failed',
          progress: 100,
          currentTask: null,
          error: allTasksFailed 
            ? `所有任务执行失败: ${errorDetail}`
            : `部分任务失败 (${taskFailedCount}/${tasks.length}): ${errorDetail}`,
          endTime: Date.now(),
          duration: `${duration}s`
        })
        executionStats.value.failed++
        if (logConfig.value.batch) console.log(`❌ Token失败: ${token.name} (${taskFailedCount}/${tasks.length}个任务失败, 耗时 ${duration}s)`)
      } else {
        updateTaskProgress(tokenId, {
          status: 'completed',
          progress: 100,
          currentTask: null,
          endTime: Date.now(),
          duration: `${duration}s`
        })
        
        // 🔥 如果这个token之前失败过（重试成功的情况）
        const wasPreviouslyFailed = taskProgress.value[tokenId]?.previouslyFailed === true
        if (wasPreviouslyFailed) {
          // 重试成功：failed--, success++
          executionStats.value.failed--
          if (logConfig.value.batch) console.log(`✅ Token重试成功: ${token.name} (失败 → 成功, 耗时 ${duration}s)`)
        }
        
        executionStats.value.success++
        if (logConfig.value.batch) console.log(`✅ Token完成: ${token.name} (耗时 ${duration}s)`)
      }
      
    } catch (error) {
      const duration = ((Date.now() - startTime) / 1000).toFixed(1)
      if (logConfig.value.batch) console.error(`❌ Token执行失败: ${token.name}`, error)
      
      updateTaskProgress(tokenId, {
        status: 'failed',
        error: error.message || String(error),
        endTime: Date.now(),
        duration: `${duration}s`
      })
      
      executionStats.value.failed++
      
    } finally {
      // 🔹 步骤6：释放连接（关闭此token的连接，允许等待队列中的token创建连接）
      if (client && wsPool) {
        batchLog(`🔓 [${token.name}] 释放连接`)
        await wsPool.release(tokenId)
      }
    }
  }
  
  /**
   * 执行单个子任务并跟踪状态
   * @param {string} tokenId - Token ID
   * @param {string} taskId - 任务ID（来自dailyTaskState）
   * @param {string} taskName - 任务显示名称
   * @param {Function} executor - 执行函数
   * @param {boolean} consumesResources - 是否消耗资源
   * @returns {Object} 任务执行结果
   */
  const executeSubTask = async (tokenId, taskId, taskName, executor, consumesResources = false, subTaskIndex = null) => {
    // 🆕 更新当前任务显示
    if (subTaskIndex !== null) {
      // 一键补差子任务：用序号表示
      updateTaskProgress(tokenId, {
        currentTask: `dailyFix_${subTaskIndex}` // 格式：dailyFix_1, dailyFix_2, ...
      })
    }
    
    // 如果任务消耗资源且已完成，跳过执行
    if (consumesResources && dailyTaskStateStore.isTaskCompleted(tokenId, taskId)) {
      if (logConfig.value.batch) console.log(`⏭️ 跳过已完成的任务: ${taskName}`)
      return { 
        task: taskName, 
        taskId,
        skipped: true, 
        success: true, 
        message: '已完成，跳过执行' 
      }
    }
    
    try {
      const result = await executor()
      // 标记任务为成功
      dailyTaskStateStore.markTaskCompleted(tokenId, taskId, true, null)
      if (logConfig.value.batch) console.log(`✅ ${taskName} - 成功`)
      return { task: taskName, taskId, success: true, data: result, skipped: false }
    } catch (error) {
      // 标记任务为失败
      dailyTaskStateStore.markTaskFailed(tokenId, taskId, error.message)
      if (logConfig.value.batch) console.log(`❌ ${taskName} - 失败: ${error.message}`)
      return { task: taskName, taskId, success: false, error: error.message, skipped: false }
    }
  }
  
  /**
   * 执行单个任务
   */
  const executeTask = async (tokenId, taskName, providedClient = null, batchId = null) => {
    // 🆕 支持从连接池传递client，或从tokenStore获取
    let client = providedClient
    
    if (!client) {
      // 从 tokenStore 获取连接（传统方式）
      const connection = tokenStore.wsConnections[tokenId]
      if (!connection || connection.status !== 'connected') {
        throw new Error('WebSocket未连接')
      }
      client = connection.client
    }
    
    if (!client) {
      throw new Error('WebSocket客户端不可用')
    }
    
    // 🔍 双重检查：即使外层确认了连接，这里也再次检查client.connected
    if (!client.connected) {
      if (logConfig.value.batch) console.error(`❌ [${tokenId}] client.connected为false，但外层已通过检查`)
      if (logConfig.value.batch) console.error(`   任务: ${taskName}`)
      if (logConfig.value.batch) console.error(`   client对象:`, {
        connected: client.connected,
        hasSocket: !!client.socket,
        socketReadyState: client.socket?.readyState
      })
      
      // 🔄 主动重连机制（最多尝试3次）
      if (logConfig.value.batch) console.log(`🔄 [${tokenId}] 检测到连接断开，启动自动重连机制...`)
      
      let reconnectAttempts = 0
      const maxReconnectAttempts = 3
      
      while (reconnectAttempts < maxReconnectAttempts) {
        // 🔥 在重连循环开始检查批次ID和停止状态
        if (batchId && batchId !== currentBatchId.value) {
          if (logConfig.value.batch) console.log(`⚠️ [${tokenId}] 批次已过期，终止重连`)
          return false
        }
        
        if (!isExecuting.value) {
          if (logConfig.value.batch) console.log(`⚠️ [${tokenId}] 任务已停止，终止重连`)
          return false
        }
        
        reconnectAttempts++
        
        if (logConfig.value.batch) console.log(`🔄 [${tokenId}] 重连尝试 ${reconnectAttempts}/${maxReconnectAttempts}...`)
        
        // 调用tokenStore的重连方法
        try {
          await tokenStore.reconnectWebSocket(tokenId)
          
          // 等待连接建立（最多等待10秒）
          const connectionTimeout = 10000
          const startTime = Date.now()
          
          while (!client.connected && Date.now() - startTime < connectionTimeout) {
            // 🔥 在等待循环中检查批次ID
            if (batchId && batchId !== currentBatchId.value) {
              if (logConfig.value.batch) console.log(`⚠️ [${tokenId}] 批次已过期，停止重连尝试`)
              return false
            }
            await new Promise(resolve => setTimeout(resolve, 200))
          }
          
          if (client.connected) {
            if (logConfig.value.batch) console.log(`✅ [${tokenId}] 重连成功（第${reconnectAttempts}次尝试），继续执行任务`)
            break
          } else {
            if (logConfig.value.batch) console.warn(`⚠️ [${tokenId}] 第${reconnectAttempts}次重连超时`)
          }
        } catch (error) {
          if (logConfig.value.batch) console.error(`❌ [${tokenId}] 第${reconnectAttempts}次重连失败:`, error.message)
        }
        
        // 如果还有重试机会，等待一段时间再试
        if (reconnectAttempts < maxReconnectAttempts && !client.connected) {
          // 🔥 等待前检查
          if ((batchId && batchId !== currentBatchId.value) || !isExecuting.value) {
            if (logConfig.value.batch) console.log(`⚠️ [${tokenId}] 任务已停止，终止重连`)
            return false
          }
          
          const waitTime = reconnectAttempts * 2000 // 2秒、4秒、6秒递增
          if (logConfig.value.batch) console.log(`⏰ [${tokenId}] 等待${waitTime/1000}秒后进行下一次重连尝试...`)
          
          // 🔥 等待期间分段检查（每500ms）
          const checkInterval = 500
          const checks = Math.ceil(waitTime / checkInterval)
          for (let i = 0; i < checks; i++) {
            if ((batchId && batchId !== currentBatchId.value) || !isExecuting.value) {
              if (logConfig.value.batch) console.log(`⚠️ [${tokenId}] 等待重连期间检测到停止`)
              return false
            }
            await new Promise(resolve => setTimeout(resolve, Math.min(checkInterval, waitTime - i * checkInterval)))
          }
        }
      }
      
      // 最终检查
      if (!client.connected) {
        throw new Error(`WebSocket连接失败，已尝试重连${maxReconnectAttempts}次 [${taskName}]`)
      }
    }
    
    // 🔄 辅助函数：检查并恢复连接（用于长任务中的定期检查）
    const ensureConnection = async () => {
      if (client.connected) {
        return true // 连接正常
      }
      
      // 连接已断开，尝试恢复
      if (logConfig.value.batch) console.warn(`⚠️ [${tokenId}] 检测到连接断开，尝试恢复...`)
      
      try {
        await tokenStore.reconnectWebSocket(tokenId)
        
        // 等待连接恢复（最多5秒）
        const startTime = Date.now()
        while (!client.connected && Date.now() - startTime < 5000) {
          // 🔥 在等待循环中检查批次ID（注意：这里的client是外部作用域的）
          // 由于这是在 executeTokenTasksWithPool 内部的局部函数，我们需要检查外部的状态
          if (!isExecuting.value) {
            if (logConfig.value.batch) console.log(`⚠️ [${tokenId}] 任务已停止，停止等待连接恢复`)
            return false
          }
          await new Promise(resolve => setTimeout(resolve, 200))
        }
        
        if (client.connected) {
          if (logConfig.value.batch) console.log(`✅ [${tokenId}] 连接已恢复`)
          return true
        } else {
          if (logConfig.value.batch) console.error(`❌ [${tokenId}] 连接恢复失败`)
          return false
        }
      } catch (error) {
        if (logConfig.value.batch) console.error(`❌ [${tokenId}] 连接恢复异常:`, error.message)
        return false
      }
    }
    
    // 根据任务名称执行对应操作
    switch (taskName) {
      case 'dailyFix':
        // 一键补差（完整版，包含所有原始每日任务）
        // 初始化任务状态
        dailyTaskStateStore.initTokenTaskState(tokenId)
        const fixResults = []
        
        // 🔍 【新增】获取执行前的任务完成状态
        // 注意：外层 executeTokenTasksWithPool 已经确保了连接建立，这里直接发送即可
        taskLog('dailyFix', '🔍 正在获取执行前的任务完成状态...')
        let beforeTaskStatus = {}
        
        try {
          const beforeRoleInfo = await client.sendWithPromise('role_getroleinfo', {}, 10000)
          beforeTaskStatus = beforeRoleInfo?.role?.dailyTask?.complete || {}
          taskLog('dailyFix', '📊 执行前任务状态:', JSON.stringify(beforeTaskStatus, null, 2))
        } catch (error) {
          taskWarn('dailyFix', '⚠️ 获取执行前任务状态失败:', error.message)
        }
        // 🚀 极速优化：随机延迟从100-400ms降至50-150ms
        const randomDelay = 50 + Math.floor(Math.random() * 101)
        await new Promise(resolve => setTimeout(resolve, randomDelay))
        
        // 打印所有子任务列表
        taskLog('dailyFix', '📋 一键补差包含以下子任务：')
        taskLog('dailyFix', '1. 分享游戏')
        taskLog('dailyFix', '2. 赠送好友金币')
        taskLog('dailyFix', '3. 免费招募')
        taskLog('dailyFix', '4. 付费招募')
        taskLog('dailyFix', '5. 免费点金 1/3, 2/3, 3/3')
        taskLog('dailyFix', '6. 开启宝箱×10（优先木质，不足则青铜）')
        taskLog('dailyFix', '7. 福利签到')
        taskLog('dailyFix', '8. 领取每日礼包')
        taskLog('dailyFix', '9. 领取免费礼包')
        taskLog('dailyFix', '10. 领取永久卡礼包')
        taskLog('dailyFix', '11. 领取邮件奖励')
        taskLog('dailyFix', '12. 免费钓鱼 1/3, 2/3, 3/3')
        taskLog('dailyFix', '13. 灯神免费扫荡（魏国、蜀国、吴国、群雄）')
        taskLog('dailyFix', '14. 领取免费扫荡卷 1/3, 2/3, 3/3')
        taskLog('dailyFix', '15. 黑市一键采购（需手动或使用"小号黑市购买"任务）')
        taskLog('dailyFix', '   - 小号黑市购买：青铜宝箱和铂金宝箱必买，黄金宝箱5折及以下购买')
        taskLog('dailyFix', '16. 竞技场战斗 1/3, 2/3, 3/3（用阵容1）')
        taskLog('dailyFix', '17. 军团BOSS（用阵容1）')
        taskLog('dailyFix', '18. 每日BOSS/咸王考验 1/3, 2/3, 3/3（用阵容1）')
        taskLog('dailyFix', '19. 领取盐罐奖励（停止/启动已独立）')
        taskLog('dailyFix', '20. 领取任务奖励1-10（共10个）')
        taskLog('dailyFix', '21. 领取日常任务奖励')
        taskLog('dailyFix', '22. 领取周常任务奖励')
        taskLog('dailyFix', '总计：20大类，44个子任务（盐罐机器人已独立）')
        taskLog('dailyFix', '超时时间：统一1000ms')
        taskLog('dailyFix', '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
        
        // 🆕 子任务计数器
        let subTaskIndex = 0
        const totalSubTasks = 44 // 一键补差总子任务数（已将盐罐机器人独立）
        
        // 1. 分享游戏
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          const shareResult = await client.sendWithPromise('system_mysharecallback', {
            isSkipShareCard: true,
            type: 2
          }, 3000) // 从1000ms增加到3000ms，与其他任务保持一致
          fixResults.push({ task: '分享游戏', success: true, data: shareResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '分享游戏', success: false, error: error.message })
        }
        
        // 2. 赠送好友金币
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          const friendResult = await client.sendWithPromise('friend_batch', {}, 3000)
          fixResults.push({ task: '赠送好友金币', success: true, data: friendResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '赠送好友金币', success: false, error: error.message })
        }
        
        // 3. 免费招募
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          const freeRecruitResult = await client.sendWithPromise('hero_recruit', {
            recruitType: 3,
            recruitNumber: 1
          }, 1000)
          fixResults.push({ task: '免费招募', success: true, data: freeRecruitResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '免费招募', success: false, error: error.message })
        }
        
        // 4. 付费招募（消耗资源）
        subTaskIndex++
        const paidRecruitResult = await executeSubTask(
          tokenId,
          'paid_recruit',
          '付费招募',
          async () => await client.sendWithPromise('hero_recruit', {
            recruitType: 1,
            recruitNumber: 1
          }, 1000),
          true, // 消耗资源
          subTaskIndex // 子任务序号
        )
        fixResults.push(paidRecruitResult)
        if (!paidRecruitResult.skipped) {
          await new Promise(resolve => setTimeout(resolve, 200))
        }
        
        // 5. 免费点金（3次）（消耗资源）
        const goldTaskIds = ['buy_gold_1', 'buy_gold_2', 'buy_gold_3']
        for (let i = 0; i < 3; i++) {
          subTaskIndex++
          const goldResult = await executeSubTask(
            tokenId,
            goldTaskIds[i],
            `免费点金 ${i + 1}/3`,
            async () => await client.sendWithPromise('system_buygold', { buyNum: 1 }, 3000),
            true, // 消耗资源
            subTaskIndex // 子任务序号
          )
          fixResults.push(goldResult)
          if (!goldResult.skipped) {
            await new Promise(resolve => setTimeout(resolve, 200))
          }
        }
        
        // 6. 开启木质宝箱（10个）（消耗资源）
        // 如果木制宝箱不够10个，则开青铜宝箱
        subTaskIndex++
        let openBoxResult
        try {
          // 先获取角色信息，检查宝箱数量
          const roleInfo = await client.sendWithPromise('role_getroleinfo', {}, 3000)
          const items = roleInfo?.role?.items || {}
          
          // 获取物品数量的通用函数（兼容数组和对象结构）
          const getItemCount = (items, id) => {
            if (!items) return 0
            // 数组结构：[{id/itemId, num/count/quantity}, ...]
            if (Array.isArray(items)) {
              const found = items.find((it) => Number(it.id ?? it.itemId) === id)
              if (!found) return 0
              return Number(found.num ?? found.count ?? found.quantity ?? 0)
            }
            // 对象结构：{ '2001': 3 } 或 { '2001': { num:3 } }
            const node = items[String(id)] ?? items[id]
            if (node == null) return 0
            if (typeof node === 'number') return node
            return Number(node.num ?? node.count ?? node.quantity ?? 0)
          }
          
          const woodenBoxCount = getItemCount(items, 2001) // 木制宝箱ID: 2001
          const bronzeBoxCount = getItemCount(items, 2002) // 青铜宝箱ID: 2002
          
          taskLog('dailyFix', `📦 当前宝箱数量: 木制宝箱×${woodenBoxCount}, 青铜宝箱×${bronzeBoxCount}`)
          
          if (woodenBoxCount >= 10) {
            // 木制宝箱足够，开10个木制宝箱
            openBoxResult = await executeSubTask(
              tokenId,
              'open_box',
              '开启木质宝箱×10',
              async () => await client.sendWithPromise('item_openbox', {
                itemId: 2001,
                number: 10
              }, 1000),
              true, // 消耗资源
              subTaskIndex // 子任务序号
            )
            taskLog('dailyFix', `✅ 开启木质宝箱×10`)
          } else if (bronzeBoxCount >= 10) {
            // 木制宝箱不够，但青铜宝箱够，开10个青铜宝箱
            openBoxResult = await executeSubTask(
              tokenId,
              'open_box',
              '开启青铜宝箱×10',
              async () => await client.sendWithPromise('item_openbox', {
                itemId: 2002,
                number: 10
              }, 1000),
              true, // 消耗资源
              subTaskIndex // 子任务序号
            )
            taskLog('dailyFix', `⚠️ 木制宝箱不足，改为开启青铜宝箱×10`)
          } else {
            // 两种宝箱都不够10个，尝试开启所有可用的宝箱
            if (woodenBoxCount > 0) {
              openBoxResult = await executeSubTask(
                tokenId,
                'open_box',
                `开启木质宝箱×${woodenBoxCount}`,
                async () => await client.sendWithPromise('item_openbox', {
                  itemId: 2001,
                  number: woodenBoxCount
                }, 1000),
                true, // 消耗资源
                subTaskIndex // 子任务序号
              )
              taskLog('dailyFix', `⚠️ 木制宝箱不足10个，开启现有的${woodenBoxCount}个`)
            } else if (bronzeBoxCount > 0) {
              openBoxResult = await executeSubTask(
                tokenId,
                'open_box',
                `开启青铜宝箱×${bronzeBoxCount}`,
                async () => await client.sendWithPromise('item_openbox', {
                  itemId: 2002,
                  number: bronzeBoxCount
                }, 1000),
                true, // 消耗资源
                subTaskIndex // 子任务序号
              )
              taskLog('dailyFix', `⚠️ 木制宝箱不足，青铜宝箱也不足10个，开启现有的${bronzeBoxCount}个青铜宝箱`)
            } else {
              // 没有任何宝箱可开
              openBoxResult = {
                task: 'open_box',
                success: false,
                skipped: true,
                error: '没有可用的宝箱'
              }
              taskLog('dailyFix', `⚠️ 没有可用的宝箱（木制宝箱×${woodenBoxCount}, 青铜宝箱×${bronzeBoxCount}）`)
            }
          }
        } catch (error) {
          taskLog('dailyFix', `❌ 获取宝箱信息失败: ${error.message}`)
          // 失败时仍然尝试开10个木制宝箱（保持原有行为）
          openBoxResult = await executeSubTask(
            tokenId,
            'open_box',
            '开启木质宝箱×10',
            async () => await client.sendWithPromise('item_openbox', {
              itemId: 2001,
              number: 10
            }, 1000),
            true, // 消耗资源
            subTaskIndex // 子任务序号
          )
        }
        
        fixResults.push(openBoxResult)
        if (!openBoxResult.skipped) {
          await new Promise(resolve => setTimeout(resolve, 200))
        }
        
        // 7. 福利签到
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          const signInResult = await client.sendWithPromise('system_signinreward', {}, 3000)
          fixResults.push({ task: '福利签到', success: true, data: signInResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '福利签到', success: false, error: error.message })
        }
        
        // 8. 领取每日礼包
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          const dailyGiftResult = await client.sendWithPromise('discount_claimreward', {}, 3000)
          fixResults.push({ task: '领取每日礼包', success: true, data: dailyGiftResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '领取每日礼包', success: false, error: error.message })
        }
        
        // 9. 领取免费礼包
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          const freeCardResult = await client.sendWithPromise('card_claimreward', {}, 3000)
          fixResults.push({ task: '领取免费礼包', success: true, data: freeCardResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '领取免费礼包', success: false, error: error.message })
        }
        
        // 10. 领取永久卡礼包
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          const permanentCardResult = await client.sendWithPromise('card_claimreward', {
            cardId: 4003
          }, 1000)
          fixResults.push({ task: '领取永久卡礼包', success: true, data: permanentCardResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '领取永久卡礼包', success: false, error: error.message })
        }
        
        // 🔄 定期连接检查点1（第10个子任务后）
        if (subTaskIndex >= 10) {
          taskLog('dailyFix', `🔍 [检查点1] 已完成 ${subTaskIndex}/44 个子任务，检查连接状态...`)
          const connectionOk = await ensureConnection()
          if (!connectionOk) {
            throw new Error('连接检查失败：无法恢复WebSocket连接')
          }
        }
        
        // 11. 领取邮件奖励
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          const mailResult = await client.sendWithPromise('mail_claimallattachment', {
            category: 0
          }, 1000)
          fixResults.push({ task: '领取邮件奖励', success: true, data: mailResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '领取邮件奖励', success: false, error: error.message })
        }
        
        // 12. 免费钓鱼（3次）（消耗资源）
        const fishTaskIds = ['fish_1', 'fish_2', 'fish_3']
        for (let i = 0; i < 3; i++) {
          subTaskIndex++
          const fishResult = await executeSubTask(
            tokenId,
            fishTaskIds[i],
            `免费钓鱼 ${i + 1}/3`,
            async () => await client.sendWithPromise('artifact_lottery', {
              lotteryNumber: 1,
              newFree: true,
              type: 1
            }, 1000),
            true, // 消耗资源
            subTaskIndex // 子任务序号
          )
          fixResults.push(fishResult)
          if (!fishResult.skipped) {
            await new Promise(resolve => setTimeout(resolve, 200))
          }
        }
        
        // 13. 灯神免费扫荡（4个国家）
        const kingdoms = ['魏国', '蜀国', '吴国', '群雄']
        for (let gid = 1; gid <= 4; gid++) {
          subTaskIndex++
          updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
          try {
            const genieResult = await client.sendWithPromise('genie_sweep', {
              genieId: gid
            }, 1000)
            fixResults.push({ task: `${kingdoms[gid-1]}灯神免费扫荡`, success: true, data: genieResult })
            await new Promise(resolve => setTimeout(resolve, 200))
          } catch (error) {
            fixResults.push({ task: `${kingdoms[gid-1]}灯神免费扫荡`, success: false, error: error.message })
          }
        }
        
        // 14. 领取免费扫荡卷（3次）
        for (let i = 0; i < 3; i++) {
          subTaskIndex++
          updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
          try {
            const sweepCardResult = await client.sendWithPromise('genie_buysweep', {}, 3000)
            fixResults.push({ task: `领取免费扫荡卷 ${i + 1}/3`, success: true, data: sweepCardResult })
            await new Promise(resolve => setTimeout(resolve, 200))
          } catch (error) {
            fixResults.push({ task: `领取免费扫荡卷 ${i + 1}/3`, success: false, error: error.message })
          }
        }
        
        // 🔄 定期连接检查点2（第20个子任务后）
        if (subTaskIndex >= 20) {
          taskLog('dailyFix', `🔍 [检查点2] 已完成 ${subTaskIndex}/44 个子任务，检查连接状态...`)
          const connectionOk = await ensureConnection()
          if (!connectionOk) {
            throw new Error('连接检查失败：无法恢复WebSocket连接')
          }
        }
        
        // 15. 黑市一键采购（消耗资源）
        subTaskIndex++
        const blackMarketResult = await executeSubTask(
          tokenId,
          'black_market',
          '黑市一键采购',
          async () => await client.sendWithPromise('store_purchase', { 
            goodsId: 1 
          }, 1000),
          true, // 消耗资源
          subTaskIndex // 子任务序号
        )
        fixResults.push(blackMarketResult)
        if (!blackMarketResult.skipped) {
          await new Promise(resolve => setTimeout(resolve, 200))
        }
        
        // 16. 竞技场战斗（3次，用阵容1）（消耗资源）
        try {
          // 切换到阵容1
          await switchToFormation(client, 1)
          
          // 开始竞技场
          await client.sendWithPromise('arena_startarea', {}, 3000)
          
          // 进行3场战斗
          const arenaTaskIds = ['arena_1', 'arena_2', 'arena_3']
          for (let i = 1; i <= 3; i++) {
            subTaskIndex++
            const arenaResult = await executeSubTask(
              tokenId,
              arenaTaskIds[i - 1],
              `竞技场战斗 ${i}/3`,
              async () => {
              // 获取目标
              const targets = await client.sendWithPromise('arena_getareatarget', {
                refresh: false
              }, 1000)
              
              const targetId = targets?.roleList?.[0]?.roleId
                if (!targetId) {
                  throw new Error('未找到目标')
                }
                
                await client.sendWithPromise('fight_startareaarena', {
                  targetId
                }, 1000)
                
                return { targetId }
              },
              true, // 消耗资源
              subTaskIndex // 子任务序号
            )
            fixResults.push(arenaResult)
            if (!arenaResult.skipped) {
              await new Promise(resolve => setTimeout(resolve, 200))
            }
          }
        } catch (error) {
          fixResults.push({ task: '竞技场战斗', success: false, error: error.message })
        }
        
        // 17. 军团BOSS（用阵容1）
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          // 切换到阵容1
          await switchToFormation(client, 1)
          
          // 打军团BOSS
          // 🆕 连接池模式优化：增加超时时间到5000ms，避免网络拥堵导致超时
          const legionBossResult = await client.sendWithPromise('fight_startlegionboss', {}, 5000)
          fixResults.push({ task: '军团BOSS', success: true, data: legionBossResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '军团BOSS', success: false, error: error.message })
        }
        
        // 18. 每日BOSS/咸王考验（3次，用阵容1）
        try {
          // 切换到阵容1
          await switchToFormation(client, 1)
          
          // 获取今日BOSS ID
          const todayBossId = getTodayBossId()
          
          // 进行3场战斗
          for (let i = 1; i <= 3; i++) {
            subTaskIndex++
            updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
            try {
              const bossResult = await client.sendWithPromise('fight_startboss', {
                bossId: todayBossId
              }, 1000)
              fixResults.push({ task: `每日BOSS ${i}/3`, success: true, data: bossResult })
              await new Promise(resolve => setTimeout(resolve, 200))
            } catch (error) {
              fixResults.push({ task: `每日BOSS ${i}/3`, success: false, error: error.message })
            }
          }
        } catch (error) {
          fixResults.push({ task: '每日BOSS', success: false, error: error.message })
        }
        
        // 🔄 定期连接检查点3（第30个子任务后）
        if (subTaskIndex >= 30) {
          taskLog('dailyFix', `🔍 [检查点3] 已完成 ${subTaskIndex}/44 个子任务，检查连接状态...`)
          const connectionOk = await ensureConnection()
          if (!connectionOk) {
            throw new Error('连接检查失败：无法恢复WebSocket连接')
          }
        }
        
        // 19. 领取盐罐奖励
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          const bottleRewardResult = await client.sendWithPromise('bottlehelper_claim', {}, 3000)
          fixResults.push({ task: '领取盐罐奖励', success: true, data: bottleRewardResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '领取盐罐奖励', success: false, error: error.message })
        }
        
        // 20. 领取任务奖励（1-10）
        // 【重要】在领取任务奖励前等待1秒，确保服务器已完成所有任务状态的更新
        // 原因：完成任务（如"分享游戏"）和领取任务奖励是两个操作，服务器需要时间同步状态
        // 如果不等待，可能出现"任务已完成但领取失败"的情况，第二次运行才能成功
        if (logConfig.value.batch) console.log('⏳ 等待服务器更新任务状态（1秒）...')
        await new Promise(resolve => setTimeout(resolve, 1000))
        
        for (let taskId = 1; taskId <= 10; taskId++) {
          subTaskIndex++
          updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
          try {
            const taskRewardResult = await client.sendWithPromise('task_claimdailypoint', {
              taskId
            }, 1000)
            fixResults.push({ task: `领取任务奖励${taskId}`, success: true, data: taskRewardResult })
            await new Promise(resolve => setTimeout(resolve, 200))
          } catch (error) {
            fixResults.push({ task: `领取任务奖励${taskId}`, success: false, error: error.message })
          }
        }
        
        // 🔄 定期连接检查点4（第40个子任务后）
        if (subTaskIndex >= 40) {
          taskLog('dailyFix', `🔍 [检查点4] 已完成 ${subTaskIndex}/44 个子任务，检查连接状态...`)
          const connectionOk = await ensureConnection()
          if (!connectionOk) {
            throw new Error('连接检查失败：无法恢复WebSocket连接')
          }
        }
        
        // 21. 领取日常任务奖励
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          const dailyRewardResult = await client.sendWithPromise('task_claimdailyreward', {}, 3000)
          fixResults.push({ task: '领取日常任务奖励', success: true, data: dailyRewardResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '领取日常任务奖励', success: false, error: error.message })
        }
        
        // 22. 领取周常任务奖励
        subTaskIndex++
        updateTaskProgress(tokenId, { currentTask: `dailyFix_${subTaskIndex}` })
        try {
          const weekRewardResult = await client.sendWithPromise('task_claimweekreward', {}, 3000)
          fixResults.push({ task: '领取周常任务奖励', success: true, data: weekRewardResult })
          await new Promise(resolve => setTimeout(resolve, 200))
        } catch (error) {
          fixResults.push({ task: '领取周常任务奖励', success: false, error: error.message })
        }
        
        // 🔍 【新增】获取执行后的任务完成状态
        if (logConfig.value.batch) console.log('🔍 正在获取执行后的任务完成状态...')
        let afterTaskStatus = {}
        try {
          const afterRoleInfo = await client.sendWithPromise('role_getroleinfo', {}, 10000)
          afterTaskStatus = afterRoleInfo?.role?.dailyTask?.complete || {}
          if (logConfig.value.batch) console.log('📊 执行后任务状态:', JSON.stringify(afterTaskStatus, null, 2))
        } catch (error) {
          if (logConfig.value.batch) console.warn('⚠️ 获取执行后任务状态失败:', error.message)
        }
        
        // 🔍 【新增】对比任务状态变化
        if (logConfig.value.batch) console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
        if (logConfig.value.batch) console.log('📋 每日任务完成状态对比分析')
        if (logConfig.value.batch) console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
        
        const taskStatusComparison = []
        const allTaskIds = new Set([
          ...Object.keys(beforeTaskStatus),
          ...Object.keys(afterTaskStatus)
        ])
        
        for (const taskId of Array.from(allTaskIds).sort((a, b) => Number(a) - Number(b))) {
          const before = beforeTaskStatus[taskId] || 0
          const after = afterTaskStatus[taskId] || 0
          const changed = before !== after
          const status = after === -1 ? '✅ 已完成' : (after === 0 ? '❌ 未完成' : `⏳ 进行中(${after})`)
          
          const comparison = {
            taskId: Number(taskId),
            before: before === -1 ? '已完成' : (before === 0 ? '未完成' : `进行中(${before})`),
            after: after === -1 ? '已完成' : (after === 0 ? '未完成' : `进行中(${after})`),
            changed: changed,
            status: status
          }
          
          taskStatusComparison.push(comparison)
          
          if (changed) {
            if (logConfig.value.batch) console.log(`任务${taskId}: ${comparison.before} → ${comparison.after} ${status}`)
          } else {
            if (logConfig.value.batch) console.log(`任务${taskId}: ${comparison.after} (无变化) ${status}`)
          }
        }
        
        if (logConfig.value.batch) console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
        
        // 统计信息
        const completedCount = Object.values(afterTaskStatus).filter(v => v === -1).length
        const totalCount = Object.keys(afterTaskStatus).length
        const changedCount = taskStatusComparison.filter(t => t.changed).length
        
        if (logConfig.value.batch) console.log(`📊 统计: 已完成 ${completedCount}/${totalCount}，本次改变 ${changedCount} 个任务`)
        if (logConfig.value.batch) console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
        
        // 将任务状态对比结果添加到返回数据中
        fixResults.push({
          task: '任务状态分析',
          success: true,
          data: {
            beforeTaskStatus,
            afterTaskStatus,
            taskStatusComparison,
            statistics: {
              completedCount,
              totalCount,
              changedCount
            }
          }
        })
        
        return fixResults
        
      case 'restartBottle':
        // 重启盐罐机器人（停止→启动）
        const bottleResults = []
        
        // 0. 预热：刷新角色信息（不等待结果，直接继续）
        // 注意：外层 executeTokenTasksWithPool 已经确保了连接建立，这里直接发送即可
        try {
          taskLog('restartBottle', '🔥 预热：发送角色信息刷新请求...')
          client.sendWithPromise('role_getroleinfo', {}, 200).catch(() => {})
          // 🚀 极速优化：随机延迟从200-700ms降至50-150ms
          const randomDelay = 50 + Math.floor(Math.random() * 101)
          await new Promise(resolve => setTimeout(resolve, randomDelay))
        } catch (error) {
          taskWarn('restartBottle', `⚠️ [${tokenId}] 预热失败:`, error.message)
        }
        
        // 1. 停止机器人
        try {
          const bottleStopResult = await client.sendWithPromise('bottlehelper_stop', {
            bottleType: -1
          }, 1000)
          bottleResults.push({ task: '停止盐罐机器人', success: true, data: bottleStopResult })
          await new Promise(resolve => setTimeout(resolve, 500))
        } catch (error) {
          // 机器人可能未启动，跳过停止步骤
          bottleResults.push({ task: '停止盐罐机器人', success: false, error: '机器人未启动，跳过' })
        }
        
        // 2. 启动机器人
        try {
          const bottleStartResult = await client.sendWithPromise('bottlehelper_start', {
            bottleType: -1
          }, 1000)
          bottleResults.push({ task: '启动盐罐机器人', success: true, data: bottleStartResult })
          await new Promise(resolve => setTimeout(resolve, 500))
        } catch (error) {
          bottleResults.push({ task: '启动盐罐机器人', success: false, error: error.message })
        }
        
        return bottleResults
        
      case 'legionSignIn':
        // 俱乐部签到
        
        // 🔥 预热：刷新角色信息（不等待结果，直接继续）
        // 注意：外层 executeTokenTasksWithPool 已经确保了连接建立，这里直接发送即可
        try {
          taskLog('legionSignIn', '🔥 [俱乐部签到] 预热：发送角色信息刷新请求...')
          client.sendWithPromise('role_getroleinfo', {}, 200).catch(() => {})
          // 🚀 极速优化：随机延迟从200-700ms降至50-150ms
          const randomDelay = 50 + Math.floor(Math.random() * 101)
          await new Promise(resolve => setTimeout(resolve, randomDelay))
        } catch (error) {
          taskWarn('legionSignIn', `⚠️ [${tokenId}] 预热失败:`, error.message)
        }
        
        return await executeSubTask(
          tokenId,
          'legion_signin',
          '俱乐部签到',
          async () => {
            const maxRetries = 3 // 最多重试3次
            let lastError = null
            
            for (let attempt = 0; attempt <= maxRetries; attempt++) {
              try {
                // 🚀 极速优化：超时时间设为200ms，快速检测失败
                const result = await client.sendWithPromise('legion_signin', {}, 200)
                
                // 如果是重试成功的，记录日志
                if (attempt > 0) {
                  taskLog('legionSignIn', `✅ [${tokenId}] 俱乐部签到重试成功（第${attempt}次重试）`)
                }
                
                return result
              } catch (error) {
                const errorMsg = error.message || String(error)
                lastError = error
                
                // 错误码 2300190 或 200020 表示"今日已签到"，不应视为错误
                if (errorMsg.includes('2300190') || errorMsg.includes('200020')) {
                  taskLog('legionSignIn', 'ℹ️ 俱乐部今日已签到，跳过')
                  return { alreadySignedIn: true }
                }
                
                // 错误码 2300070 表示"未加入俱乐部"（不需要重试）
                if (errorMsg.includes('2300070')) {
                  taskLog('legionSignIn', '⚠️ 俱乐部签到失败：该账号未加入俱乐部')
                  throw new Error('该账号未加入俱乐部，无法签到')
                }
                
                // 超时错误：提示用户检查游戏内实际状态
                if (errorMsg.includes('请求超时') || errorMsg.includes('timeout')) {
                  taskWarn('legionSignIn', '⚠️ 俱乐部签到超时，请检查游戏内是否已签到')
                  // 超时时不抛出错误，避免误判（操作可能已成功）
                  return { timeout: true, message: '超时（可能已成功，请检查游戏内状态）' }
                }
                
                // 检查是否是服务器限流错误（200400 或 200350）
                const isRateLimit = errorMsg.includes('200400') || errorMsg.includes('200350')
                
                if (isRateLimit && attempt < maxRetries) {
                  const errorCode = errorMsg.includes('200400') ? '200400' : '200350'
                  const waitTime = (attempt + 1) * 1000 // 1秒、2秒、3秒递增
                  taskLog('legionSignIn', `⏰ [${tokenId}] 俱乐部签到被限流（${errorCode}），等待${waitTime/1000}秒后重试（${attempt + 1}/${maxRetries}）...`)
                  await new Promise(resolve => setTimeout(resolve, waitTime))
                  continue // 继续下一次循环重试
                }
                
                // 非限流错误或已达最大重试次数，抛出错误
                if (attempt >= maxRetries) {
                  taskError('legionSignIn', `❌ [${tokenId}] 俱乐部签到失败，已达最大重试次数（${maxRetries}次）`)
                }
                throw error
              }
            }
            
            // 理论上不会执行到这里，但为了类型安全
            throw lastError || new Error('俱乐部签到失败')
          },
          false
        )
        
      case 'autoStudy':
        // 一键答题（触发自动答题流程）
        
        // 🔥 预热：刷新角色信息（不等待结果，直接继续）
        // 注意：外层 executeTokenTasksWithPool 已经确保了连接建立，这里直接发送即可
        try {
          taskLog('autoStudy', '🔥 [一键答题] 预热：发送角色信息刷新请求...')
          client.sendWithPromise('role_getroleinfo', {}, 200).catch(() => {})
          // 🚀 极速优化：随机延迟从200-700ms降至50-150ms
          const randomDelay = 50 + Math.floor(Math.random() * 101)
          await new Promise(resolve => setTimeout(resolve, randomDelay))
        } catch (error) {
          taskWarn('autoStudy', `⚠️ [${tokenId}] 预热失败:`, error.message)
        }
        
        const maxRetries = 3 // 最多重试3次
        let lastError = null
        
        for (let attempt = 0; attempt <= maxRetries; attempt++) {
          try {
            // 🆕 连接池模式优化：增加超时时间到5000ms，避免网络拥堵导致超时
            const result = await client.sendWithPromise('study_startgame', {}, 5000)
            
            // 如果是重试成功的，记录日志
            if (attempt > 0) {
              taskLog('autoStudy', `✅ [${tokenId}] 一键答题重试成功（第${attempt}次重试）`)
            }
            
            return {
              task: '一键答题',
              taskId: 'auto_study',
              success: true,
              data: result,
              message: '答题完成'
            }
          } catch (error) {
            const errorMsg = error.message || String(error)
            lastError = error
            
            // 错误码 3100080 或 200160 表示答题次数已用完或答题功能未开启（不需要重试）
            if (errorMsg.includes('3100080') || errorMsg.includes('200160')) {
              taskLog('autoStudy', `⚠️ [${tokenId}] 答题任务: 答题次数已用完或功能未开启`)
              return {
                task: '一键答题',
                taskId: 'auto_study',
                success: true, // 视为成功，不影响整体任务
                skipped: true,
                message: '答题次数已用完或功能未开启'
              }
            }
            
            // 检查是否是服务器限流错误（200400 或 200350）
            const isRateLimit = errorMsg.includes('200400') || errorMsg.includes('200350')
            
            if (isRateLimit && attempt < maxRetries) {
              const errorCode = errorMsg.includes('200400') ? '200400' : '200350'
              const waitTime = (attempt + 1) * 1000 // 1秒、2秒、3秒递增
              taskLog('autoStudy', `⏰ [${tokenId}] 一键答题被限流（${errorCode}），等待${waitTime/1000}秒后重试（${attempt + 1}/${maxRetries}）...`)
              await new Promise(resolve => setTimeout(resolve, waitTime))
              continue // 继续下一次循环重试
            }
            
            // 非限流错误或已达最大重试次数，抛出错误
            if (attempt >= maxRetries) {
              taskError('autoStudy', `❌ [${tokenId}] 一键答题失败，已达最大重试次数（${maxRetries}次）`)
            }
            throw error
          }
        }
        
        // 理论上不会执行到这里，但为了类型安全
        throw lastError || new Error('一键答题失败')
        
      case 'claimHangupReward':
        // 领取挂机奖励
        
        // 🔥 预热：刷新角色信息（不等待结果，直接继续）
        // 注意：外层 executeTokenTasksWithPool 已经确保了连接建立，这里直接发送即可
        try {
          taskLog('claimHangupReward', '🔥 [领取挂机奖励] 预热：发送角色信息刷新请求...')
          client.sendWithPromise('role_getroleinfo', {}, 200).catch(() => {})
          // 🚀 极速优化：随机延迟从200-700ms降至50-150ms
          const randomDelay = 50 + Math.floor(Math.random() * 101)
          await new Promise(resolve => setTimeout(resolve, randomDelay))
        } catch (error) {
          taskWarn('claimHangupReward', `⚠️ [${tokenId}] 预热失败:`, error.message)
        }
        
        return await executeSubTask(
          tokenId,
          'claim_hangup_reward',
          '领取挂机奖励',
          async () => {
            const maxRetries = 3 // 最多重试3次
            let lastError = null
            
            for (let attempt = 0; attempt <= maxRetries; attempt++) {
              try {
                // 🆕 连接池模式优化：增加超时时间到5000ms，避免网络拥堵导致超时
                const result = await client.sendWithPromise('system_claimhangupreward', {}, 5000)
                
                // 如果是重试成功的，记录日志
                if (attempt > 0) {
                  taskLog('claimHangupReward', `✅ [${tokenId}] 领取挂机奖励重试成功（第${attempt}次重试）`)
                }
                
                return result
              } catch (error) {
                const errorMsg = error.message || String(error)
                lastError = error
                
                // 错误码 -10006 表示挂机奖励功能未开启（不需要重试）
                if (errorMsg.includes('-10006')) {
                  taskLog('claimHangupReward', `⚠️ [${tokenId}] 领取挂机奖励: 功能未开启`)
                  return {
                    notEnabled: true,
                    message: '挂机奖励功能未开启'
                  }
                }
                
                // 检查是否是服务器限流错误（200400 或 200350）
                const isRateLimit = errorMsg.includes('200400') || errorMsg.includes('200350')
                
                if (isRateLimit && attempt < maxRetries) {
                  const errorCode = errorMsg.includes('200400') ? '200400' : '200350'
                  const waitTime = (attempt + 1) * 1000 // 1秒、2秒、3秒递增
                  taskLog('claimHangupReward', `⏰ [${tokenId}] 领取挂机奖励被限流（${errorCode}），等待${waitTime/1000}秒后重试（${attempt + 1}/${maxRetries}）...`)
                  await new Promise(resolve => setTimeout(resolve, waitTime))
                  continue // 继续下一次循环重试
                }
                
                // 非限流错误或已达最大重试次数，抛出错误
                if (attempt >= maxRetries) {
                  taskError('claimHangupReward', `❌ [${tokenId}] 领取挂机奖励失败，已达最大重试次数（${maxRetries}次）`)
                }
                throw error
              }
            }
            
            // 理论上不会执行到这里，但为了类型安全
            throw lastError || new Error('领取挂机奖励失败')
          },
          false
        )
        
      case 'addClock':
        // 加钟（挂机时间延长）- 必须在领取挂机奖励之后
        // 🔧 修复：参考游戏功能模块的加钟逻辑，使用 type: 2 并发送4次
        
        // 🔥 预热：刷新角色信息（不等待结果，直接继续）
        // 注意：外层 executeTokenTasksWithPool 已经确保了连接建立，这里直接发送即可
        try {
          taskLog('addClock', '🔥 [加钟] 预热：发送角色信息刷新请求...')
          client.sendWithPromise('role_getroleinfo', {}, 200).catch(() => {})
          // 🚀 极速优化：随机延迟从200-700ms降至50-150ms
          const randomDelay = 50 + Math.floor(Math.random() * 101)
          await new Promise(resolve => setTimeout(resolve, randomDelay))
        } catch (error) {
          taskWarn('addClock', `⚠️ [${tokenId}] 预热失败:`, error.message)
        }
        
        return await executeSubTask(
          tokenId,
          'add_clock',
          '加钟',
          async () => {
            const maxRetries = 3 // 最多重试3次
            let lastError = null
            
            for (let attempt = 0; attempt <= maxRetries; attempt++) {
              try {
                if (logConfig.value.batch) console.log(`🕐 [${tokenId}] 开始加钟操作（一次性同时发送10次请求）`)
                
                // 🔧 修改：一次性同时发送10次加钟请求，无延迟
                // 参考 GameStatus.vue 的 extendHangUp 函数，使用 type: 2
                const promises = []
                for (let i = 0; i < 10; i++) {
                  if (logConfig.value.batch) console.log(`🕐 [${tokenId}] 发送第${i+1}/10次加钟请求`)
                  const promise = client.sendWithPromise('system_mysharecallback', {
                    isSkipShareCard: true,
                    type: 2  // 使用 type: 2（分享/加钟）
                  }, 5000)
                    .then(result => {
                      if (logConfig.value.batch) console.log(`✅ [${tokenId}] 第${i+1}/10次加钟请求完成`)
                      return result
                    })
                    .catch(error => {
                      if (logConfig.value.batch) console.warn(`⚠️ [${tokenId}] 第${i+1}/10次加钟请求失败: ${error.message}`)
                      return null // 即使失败也返回null，不影响其他请求
                    })
                  
                  promises.push(promise)
                }
                
                // 等待所有请求完成
                const results = await Promise.all(promises)
                const successCount = results.filter(r => r !== null).length
                if (logConfig.value.batch) console.log(`✅ [${tokenId}] 加钟操作完成（一次性发送10次，成功${successCount}次）`)
                
                // 如果是重试成功的，记录日志
                if (attempt > 0) {
                  taskLog('addClock', `✅ [${tokenId}] 加钟重试成功（第${attempt}次重试）`)
                }
                
                return {
                  success: true,
                  message: '加钟完成',
                  results: results
                }
              } catch (error) {
                const errorMsg = error.message || String(error)
                lastError = error
                
                // 错误码 3100030 表示加钟次数已达上限或其他限制（不需要重试）
                if (errorMsg.includes('3100030')) {
                  taskLog('addClock', `⚠️ [${tokenId}] 加钟: 次数已达上限或功能受限`)
                  return {
                    limitReached: true,
                    message: '加钟次数已达上限或功能受限'
                  }
                }
                
                // 检查是否是服务器限流错误（200400 或 200350）
                const isRateLimit = errorMsg.includes('200400') || errorMsg.includes('200350')
                
                if (isRateLimit && attempt < maxRetries) {
                  const errorCode = errorMsg.includes('200400') ? '200400' : '200350'
                  const waitTime = (attempt + 1) * 1000 // 1秒、2秒、3秒递增
                  taskLog('addClock', `⏰ [${tokenId}] 加钟被限流（${errorCode}），等待${waitTime/1000}秒后重试（${attempt + 1}/${maxRetries}）...`)
                  await new Promise(resolve => setTimeout(resolve, waitTime))
                  continue // 继续下一次循环重试
                }
                
                // 非限流错误或已达最大重试次数，抛出错误
                if (attempt >= maxRetries) {
                  taskError('addClock', `❌ [${tokenId}] 加钟失败，已达最大重试次数（${maxRetries}次）`)
                }
                throw error
              }
            }
            
            // 理论上不会执行到这里，但为了类型安全
            throw lastError || new Error('加钟失败')
          },
          false
        )
        
      case 'climbTower':
        // 爬塔任务（咸将塔）
        const climbResults = []
        const count = climbTowerCount.value
        
        if (count === 0) {
          return { 
            task: '爬塔', 
            skipped: true, 
            success: true, 
            message: `爬塔次数设置为0，跳过执行` 
          }
        }
        
        if (logConfig.value.batch) console.log(`🗼 开始爬塔，设置次数：${count}`)
        
        // 爬塔前先发送3次 role_getroleinfo 预热请求，并尝试领取未领取的奖励
        let currentTowerId = null  // 记录当前塔层ID
        let towerRewardStatus = null  // 记录奖励领取状态
        try {
          if (logConfig.value.batch) console.log(`🔥 开始预热流程：发送3次 role_getroleinfo 请求...`)
          
          // 发送3次预热请求
          for (let i = 1; i <= 3; i++) {
            try {
              const roleInfoResp = await client.sendWithPromise('role_getroleinfo', {}, 5000)
              if (logConfig.value.batch) console.log(`✅ 预热请求 ${i}/3 成功`)
              
              // 只要还没获取到塔层信息，就尝试提取（防止第一次请求失败）
              if (!currentTowerId) {
                const tower = roleInfoResp?.role?.tower
                if (logConfig.value.batch) console.log(`🔍 [预热请求 ${i}/3] tower对象结构:`, JSON.stringify(tower, null, 2))
                
                if (tower && tower.id !== undefined) {
                  // 从 tower.id 提取当前塔层（例如：700 ÷ 10 = 70层）
                  const towerLevel = Math.floor(tower.id / 10)
                  if (logConfig.value.batch) console.log(`🔍 [预热请求 ${i}/3] 提取到的towerLevel: ${towerLevel} (tower.id=${tower.id})`)
                  
                  if (towerLevel !== undefined && towerLevel !== null) {
                    currentTowerId = towerLevel
                    towerRewardStatus = tower.reward || {}  // 保存奖励状态
                    if (logConfig.value.batch) console.log(`📍 检测到当前塔层: ${currentTowerId}`)
                  }
                } else {
                  if (logConfig.value.batch) console.warn(`⚠️ [预热请求 ${i}/3] tower对象为空或无tower.id字段`)
                }
              }
              
              await new Promise(resolve => setTimeout(resolve, 300))
            } catch (err) {
              if (logConfig.value.batch) console.warn(`⚠️ 预热请求 ${i}/3 失败: ${err.message}`)
            }
          }
          
          // 尝试领取3次未领取的奖励（如果有currentTowerId，检查并领取未领取的奖励）
          if (currentTowerId && currentTowerId > 1) {
            const previousFloor = currentTowerId - 1  // 上一层
            
            // 检查上一层奖励是否已领取
            if (towerRewardStatus && towerRewardStatus[previousFloor]) {
              if (logConfig.value.batch) console.log(`ℹ️ 第${previousFloor}层奖励已领取，跳过领取流程`)
            } else {
              if (logConfig.value.batch) console.log(`🎁 开始尝试领取奖励，目标层数: ${previousFloor}（当前层 ${currentTowerId} 的上一层）`)
              
              for (let i = 1; i <= 3; i++) {
                try {
                  await client.sendWithPromise('tower_claimreward', { rewardId: previousFloor }, 5000)
                  if (logConfig.value.batch) console.log(`✅ 领取奖励 ${i}/3 成功 (层数: ${previousFloor})`)
                  await new Promise(resolve => setTimeout(resolve, 300))
                  break  // 领取成功后跳出循环
                } catch (err) {
                  // 可能已经领取过了，不算错误
                  const errMsg = err.message || String(err)
                  if (errMsg.includes('200120') || errMsg.includes('已经领取')) {
                    if (logConfig.value.batch) console.log(`ℹ️ 领取奖励 ${i}/3: 已经领取过了`)
                    break  // 已领取，跳出循环
                  } else if (errMsg.includes('1500030') || errMsg.includes('层数不足')) {
                    if (logConfig.value.batch) console.log(`ℹ️ 领取奖励 ${i}/3: 层数不足，可能没有可领取的奖励`)
                    break  // 层数不足，跳出循环
                  } else {
                    if (logConfig.value.batch) console.warn(`⚠️ 领取奖励 ${i}/3 失败: ${err.message}`)
                  }
                  await new Promise(resolve => setTimeout(resolve, 300))
                }
              }
            }
            if (logConfig.value.batch) console.log(`✅ 预热流程完成，开始正式爬塔`)
          } else {
            if (logConfig.value.batch) console.log(`⚠️ 无法获取当前塔层信息，跳过领取奖励，直接开始爬塔`)
          }
        } catch (error) {
          if (logConfig.value.batch) console.warn(`⚠️ 预热流程失败，继续爬塔: ${error.message}`)
        }
        
        let actualExecuted = 0  // 实际执行次数
        
        for (let i = 1; i <= count; i++) {
          try {
            // 使用正确的爬塔指令 fight_starttower（咸将塔）
            const towerResult = await client.sendWithPromise('fight_starttower', {}, 5000)
            actualExecuted++
            
            // 判断爬塔结果
            const battleData = towerResult?.battleData
            let isSuccess = false
            let curHP = 0
            
            if (battleData) {
              curHP = battleData.result?.sponsor?.ext?.curHP || 0
              isSuccess = curHP > 0
              // 获取塔层ID并转换为奖励ID
              const rawTowerId = battleData?.options?.towerId
              if (rawTowerId !== undefined) {
                currentTowerId = Math.floor(rawTowerId / 10)  // 转换为奖励层数
              }
            }
            
            climbResults.push({ 
              task: `爬塔 ${i}/${count}`, 
              success: true, 
              data: {
                battleResult: isSuccess ? '胜利' : '失败',
                curHP: curHP,
                towerId: currentTowerId
              }
            })
            
            if (logConfig.value.batch) console.log(`✅ 爬塔 ${i}/${count} - ${isSuccess ? '胜利' : '失败'} (剩余血量: ${curHP})`)
            
            // 每次爬塔间隔100ms
            await new Promise(resolve => setTimeout(resolve, 100))
          } catch (error) {
            const errorMsg = error.message || String(error)
            actualExecuted++
            
            // 🔧 错误码识别
            let errorType = '未知错误'
            let shouldStop = false
            let shouldRetry = false
            
            // 检测能量不足 (1500020)
            if (errorMsg.includes('1500020') || errorMsg.includes('能量不足')) {
              errorType = '能量不足'
              shouldStop = true
              if (logConfig.value.batch) console.log(`❌ [爬塔 ${i}/${count}] ${errorType}，立即停止爬塔`)
              
              climbResults.push({ 
                task: `爬塔 ${i}/${count}`, 
                success: false, 
                error: `${errorType}，提前终止`,
                errorCode: '1500020'
              })
              
              break  // 立即跳出循环
            }
            
            // 检测奖励未领取 (1500040)
            else if (errorMsg.includes('1500040') || errorMsg.includes('奖励未领取')) {
              errorType = '奖励未领取'
              taskLog('climbTower', `⚠️ [爬塔 ${i}/${count}] ${errorType}，尝试领取...`)
              
              try {
                // 领取当前塔层的奖励
                if (currentTowerId) {
                  await client.sendWithPromise('tower_claimreward', { rewardId: currentTowerId }, 5000)
                  if (logConfig.value.batch) console.log(`✅ [爬塔 ${i}/${count}] 成功领取塔层 ${currentTowerId} 的奖励`)
                  
                  // 延迟后重试本次爬塔
                  await new Promise(resolve => setTimeout(resolve, 500))
                  i--  // 计数器减1，重试本次
                  actualExecuted--  // 实际执行次数减1
                  continue
                } else {
                  if (logConfig.value.batch) console.warn(`⚠️ [爬塔 ${i}/${count}] 无法获取塔层ID，跳过领取奖励`)
                }
              } catch (claimError) {
                if (logConfig.value.batch) console.warn(`❌ [爬塔 ${i}/${count}] 领取奖励失败: ${claimError.message}`)
              }
            }
            
            // 检测操作太快 (200400)
            else if (errorMsg.includes('200400') || errorMsg.includes('操作太快')) {
              errorType = '操作太快'
              shouldRetry = true
              taskLog('climbTower', `⚠️ [爬塔 ${i}/${count}] ${errorType}，等待1秒后重试...`)
              
              await new Promise(resolve => setTimeout(resolve, 1000))
              i--  // 计数器减1，重试本次
              actualExecuted--  // 实际执行次数减1
              continue
            }
            
            // 其他错误
            else {
              // 尝试提取错误码
              const codeMatch = errorMsg.match(/(\d{6,7})/)
              const errorCode = codeMatch ? codeMatch[1] : '未知'
              errorType = `服务器错误: ${errorCode}`
            }
            
            // 记录失败结果（非重试的情况）
            if (!shouldRetry) {
              climbResults.push({ 
                task: `爬塔 ${i}/${count}`, 
                success: false, 
                error: errorType,
                errorMsg: errorMsg
              })
              if (logConfig.value.batch) console.log(`❌ 爬塔 ${i}/${count} - 失败: ${errorType}`)
              
              // 失败后延迟100ms
              await new Promise(resolve => setTimeout(resolve, 100))
            }
          }
        }
        
        // 统计成功和失败次数
        const successCount = climbResults.filter(r => r.success && r.data?.battleResult === '胜利').length
        const failCount = climbResults.filter(r => !r.success).length
        const battleFailCount = climbResults.filter(r => r.success && r.data?.battleResult === '失败').length
        
        // 标记爬塔任务完成
        dailyTaskStateStore.markTaskCompleted(tokenId, 'climb_tower', true, null)
        
        if (logConfig.value.batch) console.log(`🗼 爬塔完成：总计${count}次，实际执行${actualExecuted}次，胜利${successCount}次，战斗失败${battleFailCount}次，错误失败${failCount}次`)
        
        return {
          task: '爬塔',
          taskId: 'climb_tower',
          success: true,
          data: climbResults,
          message: `完成${count}次爬塔 (实际执行${actualExecuted}次，胜利${successCount}次)`
        }
        
      case 'sendCar':
        // 发车任务 - 直接复用游戏功能模块（CarManagement.vue）的逻辑
        // 步骤：预热 → 时间检查 → 查询车辆 → 批量刷新（可选）→ 批量收获 → 批量发送
        
        const sendCarResults = []
        
        // 🧪 测试模式开关（测试时设为true，正式使用时设为false）
        const FORCE_ENABLE_CAR_SEND = false // ⚠️ 测试模式：忽略时间限制
        
        // 🔥 预热：发送 role_getroleinfo 请求（不等待结果，直接继续）
        // 注意：外层 executeTokenTasksWithPool 已经确保了连接建立，这里直接发送即可
        try {
          taskLog('sendCar', '🔥🚗 [发车] 预热：发送角色信息刷新请求...')
          client.sendWithPromise('role_getroleinfo', {}, 200).catch(() => {})
          // 🚀 极速优化：随机延迟从200-700ms降至50-150ms
          const randomDelay = 50 + Math.floor(Math.random() * 101)
          await new Promise(resolve => setTimeout(resolve, randomDelay))
        } catch (error) {
          taskWarn('sendCar', `⚠️🚗 [${tokenId}] 车-预热失败:`, error.message)
        }
        
        // ⏰ 时间判断：检查是否在发车时段
        const isInCarSendPeriod = () => {
          const now = new Date()
          const dayOfWeek = now.getDay() // 0=周日, 1=周一, ..., 6=周六
          const hour = now.getHours()
          
          // 发车时段：周一(1)、周二(2)、周三(3) 的 6:00-20:00
          const isValidDay = dayOfWeek >= 1 && dayOfWeek <= 3
          const isValidHour = hour >= 6 && hour < 20
          
          return isValidDay && isValidHour
        }
        
        // 获取友好的时间提示信息
        const getCarSendTimeInfo = () => {
          const now = new Date()
          const dayOfWeek = now.getDay()
          const hour = now.getHours()
          
          const dayNames = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
          const currentDay = dayNames[dayOfWeek]
          const currentTime = `${hour.toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`
          
          if (dayOfWeek < 1 || dayOfWeek > 3) {
            return `当前${currentDay}不在发车日期（仅周一至周三），只执行查车和收车`
          }
          
          if (hour < 6) {
            return `当前${currentTime}未到发车时间（6:00-20:00），只执行查车和收车`
          }
          
          if (hour >= 20) {
            return `当前${currentTime}已过发车时间（6:00-20:00），只执行查车和收车`
          }
          
          return `当前在发车时段（${currentDay} ${currentTime}），执行完整发车流程`
        }
        
        const canSendCar = FORCE_ENABLE_CAR_SEND || isInCarSendPeriod()
        const timeInfo = getCarSendTimeInfo()
        
        if (FORCE_ENABLE_CAR_SEND) {
          taskLog('sendCar', `🧪🚗 [${tokenId}] 车-测试模式已启用，忽略时间限制，强制执行发车`)
          taskLog('sendCar', `⏰🚗 [${tokenId}] 车-实际时间: ${timeInfo}`)
          sendCarResults.push({ 
            task: '时间检查', 
            success: true, 
            message: `🧪 测试模式（实际: ${timeInfo}）`,
            canSend: canSendCar
          })
        } else {
          taskLog('sendCar', `⏰🚗 [${tokenId}] 车-${timeInfo}`)
          sendCarResults.push({ 
            task: '时间检查', 
            success: true, 
            message: timeInfo,
            canSend: canSendCar
          })
        }
        
        // 辅助函数：获取今日发车次数的key
        const getTodayKey = (tokenId) => {
          const today = new Date().toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' })
          return `car_daily_send_count_${today}_${tokenId}`
        }
        
        // 辅助函数：检查车辆是否有刷新票
        const carHasRefreshTicket = (carInfo) => {
          if (!carInfo?.rewards || !Array.isArray(carInfo.rewards)) {
            return false
          }
          // 刷新票的itemId是35002
          return carInfo.rewards.some(reward => reward.itemId === 35002)
        }
        
        // 辅助函数：计算车辆状态（与 CarManagement.vue 保持一致）
        const getCarState = (carInfo) => {
          if (!carInfo) return 0
          
          const { sendAt = 0, claimAt = 0, color = 1 } = carInfo
          
          // 运输时间（秒）
          const transportDuration = (color === 1 || color === 2) ? 9000 :   // 普通/稀有: 150分钟
                                   (color === 3) ? 10800 :                  // 史诗: 180分钟
                                   14400                                    // 神话/传奇: 240分钟
          
          // 状态判断
          if (sendAt === 0) {
            return 0 // 待发车
          } else if (claimAt === 0) {
            const now = Math.floor(Date.now() / 1000)
            const elapsed = now - sendAt
            if (elapsed >= transportDuration) {
              return 2 // 已到达
            } else {
              return 1 // 运输中
            }
          } else {
            return 0 // 待发车（已收获）
          }
        }
        
        // 辅助函数：查询车辆（与 CarManagement.vue 保持一致）
        const queryClubCars = async () => {
          taskLog('sendCar', `🚗🔍 [${tokenId}] 车-开始查询俱乐部车辆...`)
          
          const maxRetries = 3 // 最多重试3次
          let lastError = null
          
          for (let attempt = 0; attempt <= maxRetries; attempt++) {
            try {
              // 🚀 优化：超时时间设为3秒
              const response = await tokenStore.sendMessageAsync(tokenId, 'car_getrolecar', {}, 3000)
              
              if (!response || !response.roleCar) {
                throw new Error('查询车辆失败：未返回车辆数据')
              }
              
              const carDataMap = response.roleCar.carDataMap || {}
              const carIds = Object.keys(carDataMap).sort() // 按ID排序
              
              // 如果是重试成功的，记录日志
              if (attempt > 0) {
                taskLog('sendCar', `✅🚗 [${tokenId}] 车-查车重试成功（第${attempt}次重试）`)
              }
              
              return { carDataMap, carIds }
            } catch (error) {
              const errorMsg = error.message || String(error)
              lastError = error
              
              // 检查是否是未加入俱乐部的错误（这类错误不需要重试）
              if (errorMsg.includes('2300070') || errorMsg.includes('3100030')) {
                throw new Error('该账号未加入俱乐部或没有赛车权限')
              }
              
              // 检查是否是服务器限流错误（200400 或 200350）
              const isRateLimit = errorMsg.includes('200400') || errorMsg.includes('200350')
              
              if (isRateLimit && attempt < maxRetries) {
                const errorCode = errorMsg.includes('200400') ? '200400' : '200350'
                const waitTime = (attempt + 1) * 1000 // 1秒、2秒、3秒递增
                taskLog('sendCar', `⏰🚗 [${tokenId}] 车-查车被限流（${errorCode}），等待${waitTime/1000}秒后重试（${attempt + 1}/${maxRetries}）...`)
                await new Promise(resolve => setTimeout(resolve, waitTime))
                continue // 继续下一次循环重试
              }
              
              // 非限流错误或已达最大重试次数，抛出错误
              if (attempt >= maxRetries) {
                taskError('sendCar', `❌🚗 [${tokenId}] 车-查车失败，已达最大重试次数（${maxRetries}次）`)
              }
              throw error
            }
          }
          
          // 理论上不会执行到这里，但为了类型安全
          throw lastError || new Error('查车失败')
        }
        
        try {
          // 第1步：查询车辆
          const { carDataMap, carIds } = await queryClubCars()
          
          // 获取客户端的发车次数记录
          const dailySendKey = getTodayKey(tokenId)
          let dailySendCount = parseInt(localStorage.getItem(dailySendKey) || '0')
          
          taskLog('sendCar', `✅🚗 [${tokenId}] 车-查询到 ${carIds.length} 辆车（今日已发车: ${dailySendCount}/4）`)
          
          // 统计各状态的车辆数量
          const carsInTransit = carIds.filter(carId => getCarState(carDataMap[carId]) === 1)
          const carsArrived = carIds.filter(carId => getCarState(carDataMap[carId]) === 2)
          const carsReady = carIds.filter(carId => getCarState(carDataMap[carId]) === 0)
          
          taskLog('sendCar', `📊🚗 [${tokenId}] 车-车辆状态统计: 运输中${carsInTransit.length}辆, 已到达${carsArrived.length}辆, 待发车${carsReady.length}辆`)
          
          // 如果有车正在运输中，将其算作今日已发车
          if (carsInTransit.length > 0) {
            // 计算实际应该记录的发车数（考虑运输中的车辆）
            const expectedSendCount = carsInTransit.length
            
            // 如果客户端记录的发车数小于运输中的车辆数，更新为运输中的车辆数
            if (dailySendCount < expectedSendCount) {
              taskLog('sendCar', `🚗🔄 [${tokenId}] 车-检测到 ${carsInTransit.length} 辆车正在运输中，更新今日发车次数: ${dailySendCount} → ${expectedSendCount}`)
              dailySendCount = expectedSendCount
              localStorage.setItem(dailySendKey, dailySendCount.toString())
            }
          }
          
          sendCarResults.push({ 
            task: '查询车辆', 
            success: true, 
            message: `查询到${carIds.length}辆车，今日已发车${dailySendCount}/4 (运输中${carsInTransit.length}辆)`
          })
          
          if (carIds.length === 0) {
            return {
              task: '发车',
              taskId: 'send_car',
              success: true,
              data: sendCarResults,
              message: '没有车辆可操作'
            }
          }
          
          // 如果所有车辆都在运输中，且达到4辆，直接返回成功
          if (carsInTransit.length === 4 && carsReady.length === 0 && carsArrived.length === 0) {
            taskLog('sendCar', `✅🚗 [${tokenId}] 车-全部4辆车都在运输中，视为今日发车任务已完成`)
            sendCarResults.push({ 
              task: '批量刷新', 
              success: true, 
              skipped: true,
              message: '所有车辆都在运输中，跳过刷新'
            })
            sendCarResults.push({ 
              task: '批量收获', 
              success: true, 
              skipped: true,
              message: '所有车辆都在运输中，跳过收获'
            })
            sendCarResults.push({ 
              task: '批量发送', 
              success: true, 
              message: `4辆车都在运输中，视为今日发车已完成`
            })
            
            return {
              task: '发车',
              taskId: 'send_car',
              success: true,
              data: sendCarResults,
              message: `发车完成：今日已发车${dailySendCount}/4 (全部运输中)`
            }
          }
          
          // 第2步：批量刷新（仅在发车时段执行）
          const refreshCount = carRefreshCount.value
          if (canSendCar && refreshCount > 0) {
            taskLog('sendCar', `🔄🚗 [${tokenId}] 车-当前在发车时段，开始批量刷新车辆（${refreshCount}轮）...`)
            let refreshSuccessCount = 0
            let refreshSkipCount = 0
            let refreshFailCount = 0
            
            for (let round = 1; round <= refreshCount; round++) {
              taskLog('sendCar', `🔄🚗 [${tokenId}] 车-第${round}轮刷新...`)
              
              for (const carId of carIds) {
                const carInfo = carDataMap[carId]
                
                // 跳过有刷新票的车辆
                if (carHasRefreshTicket(carInfo)) {
                  taskLog('sendCar', `⏭️🚗 [${tokenId}] 车-跳过有刷新票的车辆: ${carId}`)
                  refreshSkipCount++
                  continue
                }
                
                try {
                  // 🚀 优化：超时时间设为1秒
                  await tokenStore.sendMessageAsync(tokenId, 'car_refresh', { carId: carId }, 1000)
                  refreshSuccessCount++
                  taskLog('sendCar', `✅🚗 [${tokenId}] 车-刷新车辆成功: ${carId}`)
                } catch (error) {
                  const errorMsg = error.message || String(error)
                  if (errorMsg.includes('200020')) {
                    taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-车辆 ${carId} 处于冷却期`)
                  } else {
                    taskLog('sendCar', `❌🚗 [${tokenId}] 车-刷新车辆失败: ${carId} - ${errorMsg}`)
                  }
                  refreshFailCount++
                }
                
                // 刷新间隔（与 CarManagement.vue 保持一致）
                await new Promise(resolve => setTimeout(resolve, 300))
              }
            }
            
            taskLog('sendCar', `🔄🚗 [${tokenId}] 车-刷新完成：成功${refreshSuccessCount}，跳过${refreshSkipCount}，失败${refreshFailCount}`)
            sendCarResults.push({ 
              task: `刷新车辆(${refreshCount}轮)`, 
              success: true, 
              message: `成功${refreshSuccessCount}，跳过${refreshSkipCount}，失败${refreshFailCount}`
            })
            
            // 重新查询车辆状态（与 CarManagement.vue 保持一致）
            await new Promise(resolve => setTimeout(resolve, 500))
            const { carDataMap: newCarDataMap } = await queryClubCars()
            Object.assign(carDataMap, newCarDataMap)
          } else if (!canSendCar) {
            taskLog('sendCar', `⏭️🚗 [${tokenId}] 车-非发车时段，跳过刷新步骤`)
            sendCarResults.push({ 
              task: '批量刷新', 
              success: true, 
              skipped: true,
              message: '非发车时段，跳过刷新'
            })
          } else {
            taskLog('sendCar', `⏭️🚗 [${tokenId}] 车-刷新次数设置为0，跳过刷新`)
            sendCarResults.push({ 
              task: '批量刷新', 
              success: true, 
              skipped: true,
              message: '刷新次数设置为0，跳过'
            })
          }
          
          // 第3步：一键发车（批量收获 → 批量发送）
          // 这部分逻辑与 CarManagement.vue 的 batchClaimAndSendCars() 保持完全一致
          
          taskLog('sendCar', `🎯🚗 [${tokenId}] 车-开始一键发车（收获 + 发送）...`)
          
          let claimSuccessCount = 0
          let sendSuccessCount = 0
          let sendSkipCount = 0
          
          // Step 3.1: 批量收获已到达的车辆（state: 2）
          taskLog('sendCar', `🎁🚗 [${tokenId}] 车-第1步：批量收获已到达的车辆`)
          const arrivedCars = carIds.filter(carId => getCarState(carDataMap[carId]) === 2)
          const shippingCars = carIds.filter(carId => getCarState(carDataMap[carId]) === 1)
          
          if (arrivedCars.length === 0) {
            taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-没有已到达的车辆可以收获`)
            if (shippingCars.length > 0) {
              taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-${shippingCars.length}辆车正在运输中`)
            }
          } else {
            taskLog('sendCar', `🎁🚗 [${tokenId}] 车-找到 ${arrivedCars.length} 辆已到达的车辆`)
            
            for (let i = 0; i < arrivedCars.length; i++) {
              const carId = arrivedCars[i]
              taskLog('sendCar', `🎁🚗 [${tokenId}] 车-收获进度: ${i + 1}/${arrivedCars.length}`)
              
              try {
                await tokenStore.sendMessageAsync(tokenId, 'car_claim', { carId: carId }, 5000)
                claimSuccessCount++
                taskLog('sendCar', `✅🚗 [${tokenId}] 车-收获车辆成功: ${carId}`)
              } catch (error) {
                taskError('sendCar', `❌🚗 [${tokenId}] 车-收获车辆失败: ${carId} - ${error.message}`)
              }
              
              // 添加间隔（与 CarManagement.vue 保持一致）
              if (i < arrivedCars.length - 1) {
                await new Promise(resolve => setTimeout(resolve, 300))
              }
            }
            
            taskLog('sendCar', `🎁🚗 [${tokenId}] 车-收获完成：成功 ${claimSuccessCount}, 失败 ${arrivedCars.length - claimSuccessCount}`)
          }
          
          sendCarResults.push({ 
            task: '批量收获', 
            success: true, 
            message: `成功${claimSuccessCount}，跳过${carIds.length - arrivedCars.length}`
          })
          
          // 如果有收获成功的车辆，重新查询车辆列表（与 CarManagement.vue 保持一致）
          if (claimSuccessCount > 0) {
            taskLog('sendCar', `🔄🚗 [${tokenId}] 车-收获成功，等待1秒后重新查询车辆状态...`)
            await new Promise(resolve => setTimeout(resolve, 1000))
            const { carDataMap: newCarDataMap } = await queryClubCars()
            Object.assign(carDataMap, newCarDataMap)
          }
          
          // Step 3.2: 批量发送待发车的车辆（仅在发车时段执行）
          taskLog('sendCar', `🚀🚗 [${tokenId}] 车-第2步：批量发送待发车的车辆`)
          
          // 如果不在发车时段，跳过发送步骤
          if (!canSendCar) {
            taskLog('sendCar', `⏭️🚗 [${tokenId}] 车-非发车时段，跳过发送步骤`)
            sendCarResults.push({ 
              task: '批量发送', 
              success: true, 
              skipped: true,
              message: '非发车时段（仅周一-周三 6:00-20:00可发车）'
            })
            
            return {
              task: '发车',
              taskId: 'send_car',
              success: true,
              data: sendCarResults,
              message: `完成收车任务 (收获${claimSuccessCount}，非发车时段已跳过发送)`
            }
          }
          
          // 重新获取客户端的发车次数（可能在其他任务中有更新）
          dailySendCount = parseInt(localStorage.getItem(dailySendKey) || '0')
          
          // 检查每日发车次数限制
          if (dailySendCount >= 4) {
            taskWarn('sendCar', `⚠️🚗 [${tokenId}] 车-今日发车次数已达上限: ${dailySendCount}/4，跳过发送步骤`)
            sendCarResults.push({ 
              task: '批量发送', 
              success: true, 
              message: `今日发车次数已达上限(${dailySendCount}/4)，跳过发送`
            })
            
            return {
              task: '发车',
              taskId: 'send_car',
              success: true,
              data: sendCarResults,
              message: `收获完成，今日发车次数已达上限(${dailySendCount}/4)`
            }
          }
          
          // 筛选待发车的车辆（state: 0）
          const readyToSendCars = carIds.filter(carId => getCarState(carDataMap[carId]) === 0)
          const currentShippingCars = carIds.filter(carId => getCarState(carDataMap[carId]) === 1)
          
          // 计算剩余可发车次数
          const remainingSendCount = 4 - dailySendCount
          taskLog('sendCar', `📊🚗 [${tokenId}] 车-今日已发${dailySendCount}辆，剩余可发${remainingSendCount}辆`)
          
          if (readyToSendCars.length === 0) {
            if (claimSuccessCount === 0 && currentShippingCars.length > 0) {
              taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-所有车辆都在运输中`)
              sendCarResults.push({ 
                task: '批量发送', 
                success: true, 
                message: '所有车辆都在运输中，无需操作'
              })
            } else if (claimSuccessCount === 0) {
              taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-没有可操作的车辆`)
              sendCarResults.push({ 
                task: '批量发送', 
                success: true, 
                message: '没有可操作的车辆'
              })
            } else {
              taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-没有待发车的车辆`)
            }
          } else {
            taskLog('sendCar', `🚀🚗 [${tokenId}] 车-找到 ${readyToSendCars.length} 辆待发车的车辆`)
            
            // 如果待发车数量大于剩余可发数量，显示提示
            if (readyToSendCars.length > remainingSendCount) {
              taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-待发车${readyToSendCars.length}辆，但今日仅剩${remainingSendCount}个发车名额`)
            }
            
            // 限制发送数量不超过剩余可发次数
            const carsToSend = readyToSendCars.slice(0, remainingSendCount)
            
            for (let i = 0; i < carsToSend.length; i++) {
              const carId = carsToSend[i]
              taskLog('sendCar', `🚀🚗 [${tokenId}] 车-发送进度: ${i + 1}/${carsToSend.length}（今日已发${dailySendCount}/4）`)
              
              try {
                // 🚀 优化：超时时间设为500ms
                await tokenStore.sendMessageAsync(tokenId, 'car_send', {
                  carId: carId,
                  helperId: 0,
                  text: ""
                }, 500)
                sendSuccessCount++
                taskLog('sendCar', `✅🚗 [${tokenId}] 车-发送车辆成功: ${carId}`)
                
                // 发送成功后，增加今日发车次数（与 CarManagement.vue 保持一致）
                dailySendCount++
                localStorage.setItem(dailySendKey, dailySendCount.toString())
                
                // 发送成功后检查是否达到上限
                if (dailySendCount >= 4) {
                  taskLog('sendCar', `✅🚗 [${tokenId}] 车-今日发车次数已达上限，停止继续发送`)
                  break
                }
              } catch (error) {
                const errorMsg = error.message || String(error)
                
                // 区分不同的错误类型
                if (errorMsg.includes('12000050')) {
                  taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-车辆 ${carId} 发送失败: 今日发车次数已达上限（服务器端限制）`)
                  // 服务器返回已达上限，更新客户端记录
                  localStorage.setItem(dailySendKey, '4')
                  dailySendCount = 4
                  break
                } else if (errorMsg.includes('200020')) {
                  taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-车辆 ${carId} 处于发送冷却期`)
                } else if (errorMsg.includes('200350')) {
                  // 错误码200350：主要是未加入俱乐部，也可能是非发车时间或已发车后收车
                  if (!canSendCar) {
                    taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-确认为非发车时间（服务器验证），停止发送`)
                  } else {
                    taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-车辆 ${carId} 发送失败: 可能是未加入俱乐部或已发车后收车`)
                  }
                  // 这是一个可预期的状态，不计为真正的失败
                  sendSkipCount++
                  // 不再继续尝试其他车辆
                  break
                } else if (errorMsg.includes('2300070')) {
                  // 错误码2300070：未加入俱乐部
                  taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-发车失败: 该账号未加入俱乐部`)
                  // 这是一个可预期的状态，不计为真正的失败
                  sendSkipCount++
                  // 不再继续尝试其他车辆
                  break
                } else if (errorMsg.includes('3100030')) {
                  // 错误码3100030：在发车场景下通常表示未加入俱乐部或权限不足
                  taskLog('sendCar', `⚠️🚗 [${tokenId}] 车-发车失败: 未加入俱乐部或权限不足`)
                  // 这是一个可预期的状态，不计为真正的失败
                  sendSkipCount++
                  // 不再继续尝试其他车辆
                  break
                } else {
                  taskError('sendCar', `❌🚗 [${tokenId}] 车-发送车辆失败: ${carId} - ${errorMsg}`)
                }
              }
              
              // 添加间隔（与 CarManagement.vue 保持一致）
              if (i < carsToSend.length - 1) {
                await new Promise(resolve => setTimeout(resolve, 300))
              }
            }
          }
          
          // 计算跳过的发送次数（待发车数量超过剩余额度的部分）
          sendSkipCount = readyToSendCars.length > remainingSendCount ? readyToSendCars.length - remainingSendCount : 0
          
          taskLog('sendCar', `🚀🚗 [${tokenId}] 车-发送完成：成功${sendSuccessCount}次，跳过${sendSkipCount}次`)
          sendCarResults.push({ 
            task: '批量发送', 
            success: true, 
            message: `成功${sendSuccessCount}，跳过${sendSkipCount}，今日${dailySendCount}/4`
          })
          
          // 第4步：最终验证 - 仅在发车时段且有发送成功时执行
          if (canSendCar && sendSuccessCount > 0) {
            taskLog('sendCar', `🔍🚗 [${tokenId}] 车-开始最终验证，重新查询车辆状态...`)
            try {
              await new Promise(resolve => setTimeout(resolve, 1000)) // 等待1秒让服务器状态同步
              const { carDataMap: finalCarDataMap, carIds: finalCarIds } = await queryClubCars()
              
              // 统计最终运输中的车辆数量
              const finalCarsInTransit = finalCarIds.filter(carId => getCarState(finalCarDataMap[carId]) === 1)
              
              taskLog('sendCar', `📊🚗 [${tokenId}] 车-最终验证：运输中${finalCarsInTransit.length}辆车`)
              
              // 如果运输中的车辆数量大于当前记录，更新为运输中的数量
              if (finalCarsInTransit.length > dailySendCount) {
                taskLog('sendCar', `🔄🚗 [${tokenId}] 车-最终验证发现差异，更新发车次数: ${dailySendCount} → ${finalCarsInTransit.length}`)
                dailySendCount = finalCarsInTransit.length
                localStorage.setItem(dailySendKey, dailySendCount.toString())
              }
              
              sendCarResults.push({ 
                task: '最终验证', 
                success: true, 
                message: `运输中${finalCarsInTransit.length}辆，今日发车${dailySendCount}/4`
              })
              
              taskLog('sendCar', `✅🚗 [${tokenId}] 车-发车任务完成（最终验证: ${dailySendCount}/4）`)
            } catch (verifyError) {
              taskWarn('sendCar', `⚠️🚗 [${tokenId}] 车-最终验证失败: ${verifyError.message}，使用当前记录: ${dailySendCount}/4`)
              sendCarResults.push({ 
                task: '最终验证', 
                success: false, 
                message: `验证失败，使用记录: ${dailySendCount}/4`
              })
            }
          } else {
            taskLog('sendCar', `⏭️🚗 [${tokenId}] 车-跳过最终验证（${!canSendCar ? '非发车时段' : '无发车操作'}）`)
            sendCarResults.push({ 
              task: '最终验证', 
              success: true, 
              skipped: true,
              message: !canSendCar ? '非发车时段，跳过验证' : '无发车操作，跳过验证'
            })
          }
          
          const resultMessage = canSendCar 
            ? `完成发车任务 (收获${claimSuccessCount}，发送${sendSuccessCount}，今日${dailySendCount}/4)` 
            : `完成收车任务 (收获${claimSuccessCount}，非发车时段已跳过发送)`
          
          if (FORCE_ENABLE_CAR_SEND) {
            taskWarn('sendCar', `🧪🚗 [${tokenId}] 车-测试模式执行完成，请记得关闭测试模式！`)
          }
          
          return {
            task: '发车',
            taskId: 'send_car',
            success: true,
            data: sendCarResults,
            message: FORCE_ENABLE_CAR_SEND ? `🧪 ${resultMessage}（测试模式）` : resultMessage
          }
        } catch (error) {
          taskError('sendCar', `❌🚗 [${tokenId}] 车-发车任务失败:`, error)
          return {
            task: '发车',
            taskId: 'send_car',
            success: false,
            error: error.message,
            data: sendCarResults
          }
        }
        
      case 'blackMarket':
        // 小号黑市购买任务
        // 默认配置：青铜宝箱和铂金宝箱必买，黄金宝箱5折及以下购买
        
        taskLog('blackMarket', `🛒 [${tokenId}] 开始黑市购买任务...`)
        
        // 🔍 检查每日任务中的"黑市购买1次物品"是否完成
        taskLog('blackMarket', `🔍 [${tokenId}] 检查每日任务完成状态...`)
        let marketTaskCompleted = false
        
        try {
          const roleInfo = await client.sendWithPromise('role_getroleinfo', {}, 5000)
          const dailyTaskComplete = roleInfo?.role?.dailyTask?.complete || {}
          
          // 任务ID 315 是"黑市购买1次物品"
          if (dailyTaskComplete['315']) {
            marketTaskCompleted = true
            taskLog('blackMarket', `✅ [${tokenId}] 每日任务"黑市购买1次物品"已完成，跳过黑市购买`)
            
            return {
              task: '小号黑市购买',
              taskId: 'black_market',
              success: true,
              skipped: true,
              message: '每日任务已完成，自动跳过'
            }
          } else {
            taskLog('blackMarket', `📋 [${tokenId}] 每日任务未完成，开始执行黑市购买`)
          }
        } catch (error) {
          taskWarn('blackMarket', `⚠️ [${tokenId}] 无法获取每日任务状态: ${error.message}，继续执行黑市购买`)
        }
        
        taskLog('blackMarket', `📋 黑市购买包含以下步骤：`)
        taskLog('blackMarket', `1. 获取黑市信息`)
        taskLog('blackMarket', `2. 第一轮购买（青铜、黄金≤5折、铂金）`)
        taskLog('blackMarket', `3. 刷新黑市`)
        taskLog('blackMarket', `4. 第二轮购买（青铜、黄金≤5折、铂金）`)
        taskLog('blackMarket', `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
        
        // 更新任务进度
        updateTaskProgress(tokenId, { currentTask: 'blackMarket_check' })
        
        const blackMarketResults = []
        const purchaseConfig = {
          1: { name: '青铜宝箱', price: 400, mustBuy: true },   // 必买
          2: { name: '黄金宝箱', price: 375, maxDiscount: 0.5 }, // 5折及以下才买
          3: { name: '铂金宝箱', price: 625, mustBuy: true }    // 必买
        }
        
        // 第一步：获取黑市信息（仅发送命令）
        updateTaskProgress(tokenId, { currentTask: 'blackMarket_getInfo' })
        try {
          client.send('store_goodslist', { storeId: 1 })
          await new Promise(resolve => setTimeout(resolve, 500))
          taskLog('blackMarket', `✅ [${tokenId}] 获取黑市信息命令已发送`)
        } catch (error) {
          taskLog('blackMarket', `⚠️ [${tokenId}] 获取黑市信息失败: ${error.message}`)
        }
        
        // 第二步：第一轮购买
        updateTaskProgress(tokenId, { currentTask: 'blackMarket_round1' })
        taskLog('blackMarket', `🛍️ [${tokenId}] 开始第一轮购买...`)
        for (const [goodsId, config] of Object.entries(purchaseConfig)) {
          const id = parseInt(goodsId)
          
          // 黄金宝箱需要检查折扣，这里默认按5折购买
          if (id === 2 && !config.mustBuy) {
            taskLog('blackMarket', `⏭️ [${tokenId}] ${config.name}需5折及以下才购买，跳过第一轮`)
            continue
          }
          
          if (config.mustBuy || id === 2) {
            try {
              client.send('store_buy', { goodsId: id })
              await new Promise(resolve => setTimeout(resolve, 300))
              blackMarketResults.push({ task: `购买${config.name}`, success: true, round: 1 })
              taskLog('blackMarket', `✅ [${tokenId}] 第一轮购买${config.name}命令已发送`)
            } catch (error) {
              blackMarketResults.push({ task: `购买${config.name}`, success: false, error: error.message, round: 1 })
              taskLog('blackMarket', `⚠️ [${tokenId}] 第一轮购买${config.name}失败: ${error.message}`)
            }
          }
        }
        
        // 第三步：刷新黑市
        updateTaskProgress(tokenId, { currentTask: 'blackMarket_refresh' })
        try {
          client.send('store_refresh', { storeId: 1 })
          await new Promise(resolve => setTimeout(resolve, 500))
          taskLog('blackMarket', `✅ [${tokenId}] 刷新黑市命令已发送`)
          blackMarketResults.push({ task: '刷新黑市', success: true })
        } catch (error) {
          blackMarketResults.push({ task: '刷新黑市', success: false, error: error.message })
          taskLog('blackMarket', `⚠️ [${tokenId}] 刷新黑市失败: ${error.message}`)
        }
        
        // 第四步：第二轮购买
        updateTaskProgress(tokenId, { currentTask: 'blackMarket_round2' })
        taskLog('blackMarket', `🛍️ [${tokenId}] 开始第二轮购买...`)
        for (const [goodsId, config] of Object.entries(purchaseConfig)) {
          const id = parseInt(goodsId)
          
          // 黄金宝箱需要检查折扣，这里默认按5折购买
          if (id === 2 && !config.mustBuy) {
            taskLog('blackMarket', `⏭️ [${tokenId}] ${config.name}需5折及以下才购买，跳过第二轮`)
            continue
          }
          
          if (config.mustBuy || id === 2) {
            try {
              client.send('store_buy', { goodsId: id })
              await new Promise(resolve => setTimeout(resolve, 300))
              blackMarketResults.push({ task: `购买${config.name}`, success: true, round: 2 })
              taskLog('blackMarket', `✅ [${tokenId}] 第二轮购买${config.name}命令已发送`)
            } catch (error) {
              blackMarketResults.push({ task: `购买${config.name}`, success: false, error: error.message, round: 2 })
              taskLog('blackMarket', `⚠️ [${tokenId}] 第二轮购买${config.name}失败: ${error.message}`)
            }
          }
        }
        
        const totalPurchases = blackMarketResults.filter(r => r.task.includes('购买') && r.success).length
        taskLog('blackMarket', `✅ [${tokenId}] 黑市购买任务完成，成功发送${totalPurchases}个购买命令`)
        
        return {
          task: '小号黑市购买',
          taskId: 'black_market',
          success: true,
          data: blackMarketResults,
          message: `黑市购买完成 (发送${totalPurchases}个购买命令)`
        }
        
      default:
        throw new Error(`未知任务: ${taskName}`)
    }
  }
  
  /**
   * 确保WebSocket连接（带重试机制）
   */
  const ensureConnection = async (tokenId, maxRetries = 5) => {
    let retryCount = 0
    let lastError = null
    
    while (retryCount < maxRetries) {
      // 🔥 在重试循环中检查是否已停止
      if (!isExecuting.value) {
        if (logConfig.value.batch) console.log(`⚠️ [${tokenId}] 任务已停止，终止连接尝试`)
        throw new Error('任务已停止')
      }
      
      try {
    const connection = tokenStore.wsConnections[tokenId]
    
    // 如果已连接，直接返回
    if (connection && connection.status === 'connected') {
      if (logConfig.value.batch) console.log(`✓ WebSocket已连接: ${tokenId}`)
      return connection.client
    }
    
        // 尝试连接
        if (logConfig.value.batch) console.log(`🔄 连接WebSocket: ${tokenId} (尝试 ${retryCount + 1}/${maxRetries})`)
    const wsClient = await tokenStore.reconnectWebSocket(tokenId)
    
        if (wsClient) {
          if (logConfig.value.batch) console.log(`✅ WebSocket连接成功: ${tokenId}`)
          return wsClient
        }
        
        throw new Error('连接返回null')
        
      } catch (error) {
        lastError = error
        retryCount++
        
        if (retryCount < maxRetries) {
          // 🔥 在等待重试前检查是否已停止
          if (!isExecuting.value) {
            if (logConfig.value.batch) console.log(`⚠️ [${tokenId}] 任务已停止，终止重试`)
            throw new Error('任务已停止')
          }
          
          // 🆕 优化的指数退避策略
          // 第1次: 2秒, 第2次: 3秒, 第3次: 5秒, 第4次: 8秒, 第5次: 10秒
          // 最大等待时间不超过10秒
          const baseWaitTime = Math.pow(1.5, retryCount) * 1000
          const waitTime = Math.min(baseWaitTime, 10000)
          if (logConfig.value.batch) console.warn(`⚠️ 连接失败，${(waitTime/1000).toFixed(1)}秒后重试 (${retryCount}/${maxRetries}): ${error.message}`)
          
          // 🔥 在等待期间分段检查（每500ms检查一次）
          const checkInterval = 500
          const checks = Math.ceil(waitTime / checkInterval)
          for (let i = 0; i < checks; i++) {
            if (!isExecuting.value) {
              if (logConfig.value.batch) console.log(`⚠️ [${tokenId}] 等待重试期间检测到停止`)
              throw new Error('任务已停止')
            }
            await new Promise(resolve => setTimeout(resolve, Math.min(checkInterval, waitTime - i * checkInterval)))
          }
        }
      }
    }
    
    // 所有重试都失败
    if (logConfig.value.batch) console.error(`❌ WebSocket连接失败（已重试${maxRetries}次）: ${tokenId}`, lastError)
    throw new Error(`WebSocket连接失败（已重试${maxRetries}次）: ${lastError?.message || '未知错误'}`)
  }
  
  /**
   * 更新任务进度（智能选择立即更新或节流更新）
   * 100并发优化：关键状态立即更新，进度更新使用节流
   * 🔧 v3.13.5.6: 失败时实时更新失败原因统计
   */
  const updateTaskProgress = (tokenId, updates) => {
    // 关键状态变更：立即更新（开始、完成、失败、跳过）
    const isCriticalUpdate = updates.status && 
      ['executing', 'completed', 'failed', 'skipped'].includes(updates.status)
    
    // 错误信息：立即更新
    const hasError = updates.error !== undefined
    
    // 开始/结束时间：立即更新
    const hasTimestamp = updates.startTime !== undefined || updates.endTime !== undefined
    
    // 🚀 当前任务和消息：立即更新（确保用户能实时看到进度）
    const hasCurrentTask = updates.currentTask !== undefined
    const hasMessage = updates.message !== undefined
    
    if (isCriticalUpdate || hasError || hasTimestamp || hasCurrentTask || hasMessage) {
      // 关键更新：立即应用
      updateTaskProgressImmediate(tokenId, updates)
      
      // 🔧 v3.13.5.6: 任务失败时，立即记录到失败原因统计（增量更新）
      if (updates.status === 'failed' && updates.error) {
        // 🚀 增量更新：直接分析当前失败token的错误原因并累加
        const progress = taskProgress.value[tokenId]
        if (progress) {
          const reasons = extractFailureReason(progress.error)
          reasons.forEach(reason => {
            failureReasonsStats.value[reason] = (failureReasonsStats.value[reason] || 0) + 1
          })
        }
      }
      
      // 100并发优化：清理已完成任务的详细数据，释放内存
      if (updates.status === 'completed' || updates.status === 'failed') {
        setTimeout(() => compactCompletedTaskData(tokenId), 2000)
      }
    } else {
      // 非关键更新（仅进度百分比等）：使用节流
      updateTaskProgressThrottled(tokenId, updates)
    }
  }
  
  /**
   * 简化已完成任务的数据（100并发优化：减少内存占用）
   * 🔥 v3.14.0: 精简result数据，减少80%内存占用，同时保留失败原因统计所需的信息
   */
  const compactCompletedTaskData = (tokenId) => {
    const progress = taskProgress.value[tokenId]
    if (!progress) return
    
    // 只处理已完成或失败的任务
    if (progress.status !== 'completed' && progress.status !== 'failed') {
      return
    }
    
    let savedMemory = 0
    
    // 🔥 精简result中的data字段（保留success和error，用于任务详情弹窗）
    if (progress.result) {
      Object.keys(progress.result).forEach(taskId => {
        const taskResult = progress.result[taskId]
        if (taskResult && taskResult.data) {
          // 估算data对象大小（粗略估算）
          savedMemory += JSON.stringify(taskResult.data).length
          
          // 只保留成功/失败状态和错误信息
          progress.result[taskId] = {
            success: taskResult.success,
            error: taskResult.error || null
            // data字段被删除，释放内存
          }
        }
      })
    }
    
    // ⚠️ 保留 progress.error 字段不变（失败原因统计依赖此字段）
    // 只简化大型错误对象，转为字符串
    if (progress.error && typeof progress.error === 'object') {
      progress.error = String(progress.error.message || progress.error)
    }
    
    if (savedMemory > 0) {
      batchLog(`🔧 已精简Token ${tokenId} 的进度数据，释放约 ${Math.round(savedMemory / 1024)}KB`)
    }
  }
  
  /**
   * 完成批量执行
   */
  const finishBatchExecution = async () => {
    // 🔥 检查是否被用户手动停止（通过isExecuting判断）
    // 如果 isExecuting = false 且不是在自动重试等待中，说明被用户停止了
    const wasStoppedByUser = !isExecuting.value && !isAutoRetryWaiting.value
    
    if (wasStoppedByUser) {
      console.log(`🛑 [完成执行] 检测到用户已停止任务，跳过自动重试检查`)
      // 执行基本清理，但不触发自动重试
      executionStats.value.endTime = Date.now()
      
      // 停止定期清理定时器
      stopPeriodicCleanup()
      
      // 停止内存监控
      stopMemoryMonitor()
      
      // 保存历史记录
      saveExecutionHistory()
      
      console.log(`✅ [完成执行] 用户停止，已跳过自动重试`)
      return // 直接返回，不触发自动重试
    }
    
    executionStats.value.endTime = Date.now()
    const duration = executionStats.value.endTime - executionStats.value.startTime
    
    // 🔥 v3.14.1: 清理UI和定时器资源，防止内存泄漏
    if (uiUpdateTimer) {
      clearTimeout(uiUpdateTimer)
      uiUpdateTimer = null
    }
    pendingUIUpdates.clear()
    
    // 清空正在执行的token集合
    executingTokens.value.clear()
    
    // 停止定期清理定时器
    stopPeriodicCleanup()
    
    // 停止内存监控
    stopMemoryMonitor()
    
    // ⚠️ 注意：wsPool 会在连接池模式的 finally 块中自动清理，这里不需要清理
    
    if (logConfig.value.batch) {
      console.log('🧹 [内存清理] 执行完成，已清理UI和定时器资源')
    }
    
    // 100并发优化：恢复动画
    document.body.classList.remove('batch-task-executing')
    
    // ⚠️ 基本统计信息总是显示
    console.log(`
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🎉 批量任务执行完成
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊 执行结果: 成功 ${executionStats.value.success} | 失败 ${executionStats.value.failed} | 跳过 ${executionStats.value.skipped}
⏱️ 总耗时: ${Math.round(duration / 1000)}秒
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    `)
    
    // 🔧 使用已经增量记录的失败原因统计（不需要重新收集）
    // failureReasonsStats 已经在每次token失败时实时更新
    const failureReasons = failureReasonsStats.value
    
    // 🔍 调试：打印失败统计的原始数据
    console.log(`
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔍 调试：失败统计数据
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
executionStats.failed: ${executionStats.value.failed}
failureReasons对象键数: ${Object.keys(failureReasons).length}
failureReasons内容: ${JSON.stringify(failureReasons, null, 2)}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    `)
    
    // 打印失败原因统计（⚠️ 总是显示，不受日志开关控制）
    if (Object.keys(failureReasons).length > 0) {
      console.log(`
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 失败原因统计（共 ${executionStats.value.failed} 个Token失败）
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
${Object.entries(failureReasons).map(([reason, count]) => `   • ${reason}: ${count}个Token`).join('\n')}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
      `)
    } else if (executionStats.value.failed > 0) {
      console.warn(`⚠️ 有 ${executionStats.value.failed} 个失败Token，但failureReasons为空！`)
      // 打印所有失败Token的错误信息用于调试
      console.log('失败的Token详情:')
      Object.entries(taskProgress.value).forEach(([tokenId, progress]) => {
        if (progress.status === 'failed') {
          console.log(`  - ${tokenId}: ${progress.error}`)
        }
      })
    }
    
    // 保存到历史记录
    saveExecutionHistory()
    
    // 🆕 检查是否需要自动重试失败的任务
    const failedCount = executionStats.value.failed
    const shouldAutoRetry = autoRetryConfig.value.enabled && 
                           failedCount > 0 && 
                           currentRetryRound.value < autoRetryConfig.value.maxRetries
    
    console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
    console.log(`🔍 [自动重试判断]`)
    console.log(`   autoRetryConfig.enabled: ${autoRetryConfig.value.enabled}`)
    console.log(`   failedCount: ${failedCount}`)
    console.log(`   currentRetryRound: ${currentRetryRound.value}`)
    console.log(`   maxRetries: ${autoRetryConfig.value.maxRetries}`)
    console.log(`   shouldAutoRetry: ${shouldAutoRetry}`)
    console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
    
    if (shouldAutoRetry) {
      currentRetryRound.value++
      const retryDelay = autoRetryConfig.value.retryDelay
      
      if (logConfig.value.batch) console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
      if (logConfig.value.batch) console.log(`🔄 自动重试失败任务`)
      if (logConfig.value.batch) console.log(`📊 失败数量: ${failedCount}`)
      if (logConfig.value.batch) console.log(`🔢 重试轮数: ${currentRetryRound.value}/${autoRetryConfig.value.maxRetries}`)
      if (logConfig.value.batch) console.log(`⏳ 等待 ${retryDelay/1000} 秒后开始重试...`)
      if (logConfig.value.batch) console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
      
      // 🔥 关键修复：保持 isExecuting = true，防止用户在重试等待期间点击开始
      // 不重置 isExecuting，保持任务执行状态
      // isExecuting.value = false  ← 删除这行
      
      // 🔥 在重试前清理上一轮的连接和状态（避免冲突）
      if (logConfig.value.batch) console.log(`🔌 [自动重试] 清理上一轮的连接和状态...`)
      
      // 清理所有WebSocket连接
      Object.keys(taskProgress.value).forEach(tokenId => {
        try {
          if (tokenStore.wsConnections[tokenId]) {
            tokenStore.closeWebSocketConnection(tokenId)
          }
        } catch (error) {
          // 忽略错误
        }
      })
      
      // 🔥 重置批次ID（自动重试时会生成新批次ID，避免与旧批次冲突）
      // 注意：不能在这里设置新的批次ID，因为 startBatchExecution 会生成
      // 但要确保旧批次ID失效
      if (logConfig.value.batch) console.log(`📋 [自动重试] 当前批次ID: ${currentBatchId.value}（将在重试开始时更新）`)
      
      currentBatch.value = null
      executingTokens.value.clear()
      
      // 🔥 清理UI更新相关的定时器和数据（避免干扰重试）
      if (uiUpdateTimer) {
        clearTimeout(uiUpdateTimer)
        uiUpdateTimer = null
      }
      pendingUIUpdates.clear()
      
      // 🔥 关键修复：在等待前就重置 isExecuting，避免在等待期间被其他代码重置导致提前返回
      console.log(`🔧 [自动重试] 重置 isExecuting.value = false，允许重试准备`)
      const wasExecuting = isExecuting.value
      isExecuting.value = false
      
      // 🔥 设置自动重试等待标志（用于响应用户停止）
      isAutoRetryWaiting.value = true
      
      // 🔥 分段等待：可响应用户停止
      console.log(`⏳ [自动重试] 开始等待 ${retryDelay/1000} 秒（可响应用户停止）...`)
      const checkInterval = 500
      const checks = Math.ceil(retryDelay / checkInterval)
      
      for (let i = 0; i < checks; i++) {
        // 检查用户是否点击停止（通过isAutoRetryWaiting标志）
        if (!isAutoRetryWaiting.value) {
          console.log(`⚠️ [自动重试] 用户点击停止，取消自动重试`)
          return
        }
        await new Promise(resolve => setTimeout(resolve, Math.min(checkInterval, retryDelay - i * checkInterval)))
      }
      
      // 等待完成，再次检查是否被取消
      if (!isAutoRetryWaiting.value) {
        console.log(`⚠️ [自动重试] 用户点击停止，取消自动重试`)
        return
      }
      
      console.log(`✅ [自动重试] 等待完成，开始执行重试`)
      
      // 自动重试
      await retryFailedTasks()
      
      // 重试完成，清除等待标志
      isAutoRetryWaiting.value = false
      
      return // 不在这里完全重置，等重试完成后再说
    }
    
    // 重置重试轮数（完成所有重试或没有失败任务）
    console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
    console.log(`✅ [完成执行] 开始重置状态`)
    console.log(`   当前 isExecuting: ${isExecuting.value}`)
    currentRetryRound.value = 0
    isAutoRetryWaiting.value = false  // 🔥 清除自动重试等待标志
    
    // 重置状态
    isExecuting.value = false
    console.log(`   重置后 isExecuting: ${isExecuting.value}`)
    currentBatch.value = null
    executingTokens.value.clear()
    console.log(`✅ [完成执行] 状态重置完成`)
    console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
    
    // 🔥 v3.14.0: 停止内存监控
    stopMemoryMonitor()
    
    // 🆕 清除保存的进度（任务已全部完成）
    clearSavedProgress()
    
    // 🆕 v3.13.5: 执行内存清理
    if (logConfig.value.batch) {
      console.log('🧹 [内存清理] 开始清理批量任务数据...')
    }
    
    // 清空UI更新队列
    clearPendingUIUpdates()
    
    // 立即清理已完成的任务进度
    setTimeout(() => {
      const cleaned = forceCleanupTaskProgress()
      clearPendingUIUpdates()
      
      // 🔥 不清理 failureReasonsStats，让用户可以一直查看失败统计
      // failureReasonsStats 会在下一次执行新任务时清理（第955行）
      
      console.log(`✅ [自动清理] 批量任务完成，已清理 ${cleaned} 个任务数据`)
      console.log(`📊 [保留] 失败原因统计已保留，可在界面查看（下次执行新任务时自动清理）`)
    }, 3000) // 3秒后清理，给UI足够时间显示结果
    
    // 🆕 显示最终结果
    if (failedCount === 0) {
      if (logConfig.value.batch) console.log(`✅ 所有任务成功完成！`)
    } else {
      if (logConfig.value.batch) console.log(`⚠️ 仍有 ${failedCount} 个任务失败（已达最大重试次数）`)
    }
  }
  
  /**
   * 保存执行历史
   * 🆕 v3.13.5: 优化存储，只保存摘要信息
   */
  const saveExecutionHistory = () => {
    // 获取最主要的失败原因（取前3个）
    const topFailureReasons = Object.entries(failureReasonsStats.value || {})
      .sort((a, b) => b[1] - a[1])  // 按数量降序
      .slice(0, 3)  // 只取前3个
      .map(([reason, count]) => `${reason}(${count})`)
      .join(', ') || '无'
    
    // 🆕 精简历史记录，只保存必要信息
    const historyItem = {
      id: currentBatch.value?.id || `batch_${Date.now()}`,
      template: selectedTemplate.value,
      // ✅ 只保存统计数字，不保存详细数据
      stats: {
        total: executionStats.value.total,
        success: executionStats.value.success,
        failed: executionStats.value.failed,
        skipped: executionStats.value.skipped
      },
      // 🆕 保存开始时间和结束时间
      startTime: executionStats.value.startTime,
      endTime: executionStats.value.endTime,
      timestamp: Date.now(),
      duration: executionStats.value.endTime - executionStats.value.startTime,
      // ✅ 只保存最主要的失败原因摘要，不保存完整的failureReasonsStats
      topFailureReasons: topFailureReasons
    }
    
    executionHistory.value.unshift(historyItem)
    
    // 🆕 v3.13.5: 只保留最近3次，减少localStorage占用
    if (executionHistory.value.length > 3) {
      executionHistory.value = executionHistory.value.slice(0, 3)
    }
    
    try {
      localStorage.setItem('batchTaskHistory', JSON.stringify(executionHistory.value))
      
      if (logConfig.value.batch) {
        const size = new Blob([JSON.stringify(executionHistory.value)]).size
        console.log(`💾 [历史记录] 已保存，大小: ${(size / 1024).toFixed(2)} KB`)
      }
    } catch (error) {
      // localStorage配额超限处理
      if (error.message && error.message.includes('quota')) {
        console.warn('⚠️ [历史记录] localStorage空间不足，清除旧记录')
        // 只保留最新1条
        executionHistory.value = executionHistory.value.slice(0, 1)
        try {
          localStorage.setItem('batchTaskHistory', JSON.stringify(executionHistory.value))
        } catch (e) {
          console.error('❌ [历史记录] 保存失败，已清空历史记录')
          executionHistory.value = []
          localStorage.removeItem('batchTaskHistory')
        }
      } else {
        console.error('❌ [历史记录] 保存失败:', error)
      }
    }
  }
  
  /**
   * 暂停执行
   */
  const pauseExecution = () => {
    if (isExecuting.value) {
      isPaused.value = true
      if (logConfig.value.batch) console.log('⏸️ 批量任务已暂停')
    }
  }
  
  /**
   * 继续执行
   */
  const resumeExecution = () => {
    if (isExecuting.value && isPaused.value) {
      isPaused.value = false
      if (logConfig.value.batch) console.log('▶️ 批量任务继续执行')
    }
  }
  
  /**
   * 停止执行
   */
  const stopExecution = async () => {
    // 🔥 检查是否正在等待自动重试
    if (isAutoRetryWaiting.value) {
      console.log('🛑 [停止] 检测到正在等待自动重试，取消重试...')
      isAutoRetryWaiting.value = false  // 取消自动重试
      
      // 重置状态
      currentRetryRound.value = 0
      isExecuting.value = false
      isPaused.value = false
      currentBatch.value = null
      executingTokens.value.clear()
      
      console.log('✅ [停止] 已取消自动重试，任务已停止')
      return
    }
    
    if (isExecuting.value) {
      if (logConfig.value.batch) {
        console.log('🛑 [停止] 开始停止批量任务...')
      }
      
      // 🔥 第1步：设置停止标志（让正在执行的任务知道要停止）
      isExecuting.value = false
      isPaused.value = false
      
      // 🔥 第2步：等待一小段时间，让正在执行的任务有机会检测停止信号并优雅退出
      if (logConfig.value.batch) {
        console.log('⏳ [停止] 等待正在执行的任务响应停止信号...')
      }
      await new Promise(resolve => setTimeout(resolve, 500))
      
      // 🔥 第3步：清理UI更新定时器（修复停止后再开始CPU占用高的问题）
      if (uiUpdateTimer) {
        clearTimeout(uiUpdateTimer)
        uiUpdateTimer = null
      }
      
      // 🔥 第4步：清空待更新的UI数据
      pendingUIUpdates.clear()
      
      // 🔥 第5步：清空正在执行的token集合
      executingTokens.value.clear()
      
      // 🔥 第6步：停止定期清理定时器
      stopPeriodicCleanup()
      
      // 🔥 第7步：停止内存监控
      stopMemoryMonitor()
      
      // 🔥 第8步：断开所有正在执行的token的WebSocket连接（两次扫描）
      if (logConfig.value.batch) {
        console.log('🔌 [停止] 断开所有WebSocket连接（第1次扫描）...')
      }
      
      // 第1次扫描：断开已经存在的连接
      const closeActiveConnections = () => {
        // 获取所有正在执行的token（从taskProgress中）
        const activeTokenIds = Object.keys(taskProgress.value).filter(tokenId => {
          const status = taskProgress.value[tokenId]?.status
          return status === 'executing' || status === 'waiting'
        })
        
        let closedCount = 0
        activeTokenIds.forEach(tokenId => {
          try {
            if (tokenStore.wsConnections[tokenId]) {
              tokenStore.closeWebSocketConnection(tokenId)
              closedCount++
            }
          } catch (error) {
            // 忽略断开连接的错误
            if (logConfig.value.batch) {
              console.log(`   ⚠️ 断开 ${tokenId} 失败（已忽略）:`, error.message)
            }
          }
        })
        
        return closedCount
      }
      
      const firstRound = closeActiveConnections()
      if (logConfig.value.batch) {
        console.log(`   第1次扫描：断开 ${firstRound} 个连接`)
      }
      
      // 🔥 等待1800ms后进行第2次扫描，抓住漏网之鱼
      const delayTime = 1800  // 固定1800ms，足够时间让所有连接创建完成
      if (logConfig.value.batch) {
        console.log(`⏳ [停止] 等待 ${delayTime}ms 后进行第2次扫描（抓住漏网之鱼）...`)
      }
      await new Promise(resolve => setTimeout(resolve, delayTime))
      
      // 第2次扫描：断开在等待期间创建的连接
      if (logConfig.value.batch) {
        console.log('🔌 [停止] 第2次扫描，抓住漏网之鱼...')
      }
      const secondRound = closeActiveConnections()
      if (logConfig.value.batch) {
        console.log(`   第2次扫描：断开 ${secondRound} 个连接`)
        console.log(`✅ [停止] 已断开所有连接（总计: ${firstRound + secondRound} 个）`)
      }
      
      // ⚠️ 注意：wsPool 会在连接池模式的 finally 块中自动清理
      // 通过上面的延迟等待，正在执行的任务应该已经检测到停止信号并退出
      // 避免了竞态条件：任务尝试访问已清理的 wsPool
      
      // 🔥 第9步：手动清理（不触发自动重试）
      // 因为isExecuting已经是false，不调用finishBatchExecution避免触发不必要的检查
      executionStats.value.endTime = Date.now()
      currentRetryRound.value = 0
      isAutoRetryWaiting.value = false  // 🔥 清除自动重试等待标志（防止遗留）
      currentBatch.value = null
      
      // 保存历史记录
      saveExecutionHistory()
      
      if (logConfig.value.batch) {
        console.log('✅ [停止] 批量任务已停止')
        console.log('🧹 [内存清理] 已清理：UI定时器、待更新数据、执行中token、定期清理、内存监控')
      }
    }
  }
  
  /**
   * 重试失败的任务
   */
  const retryFailedTasks = async () => {
    console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
    console.log(`🔍 [retryFailedTasks] 开始检查失败任务`)
    
    // 获取所有失败的token ID
    const failedTokenIds = Object.keys(taskProgress.value).filter(
      tokenId => taskProgress.value[tokenId].status === 'failed'
    )
    
    console.log(`📊 taskProgress中的所有token数量: ${Object.keys(taskProgress.value).length}`)
    console.log(`📊 状态为failed的token数量: ${failedTokenIds.length}`)
    console.log(`📋 失败Token ID列表:`, failedTokenIds)
    console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
    
    if (failedTokenIds.length === 0) {
      console.warn('⚠️ 没有失败的任务需要重试（可能已被清理）')
      console.log(`🔍 [调试] 当前所有token的状态:`)
      Object.entries(taskProgress.value).forEach(([tokenId, progress]) => {
        console.log(`   ${tokenId}: status=${progress.status}`)
      })
      return
    }
    
    if (logConfig.value.batch) console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
    if (logConfig.value.batch) console.log(`🔄 开始重试失败任务`)
    if (logConfig.value.batch) console.log(`📊 失败Token数量: ${failedTokenIds.length}`)
    if (logConfig.value.batch) console.log(`📋 失败Token列表:`, failedTokenIds)
    if (logConfig.value.batch) console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
    
    // 使用当前模板的任务列表
    const tasks = currentTemplateTasks.value
    
    // 执行失败的token（标记为重试）
    await startBatchExecution(failedTokenIds, tasks, true)
  }
  
  /**
   * 保存任务模板
   */
  const saveTaskTemplate = (name, tasks) => {
    taskTemplates.value[name] = {
      name,
      tasks,
      enabled: true,
      createdAt: Date.now()
    }
    localStorage.setItem('taskTemplates', JSON.stringify(taskTemplates.value))
    if (logConfig.value.batch) console.log(`💾 任务模板已保存: ${name}`)
  }
  
  /**
   * 删除任务模板
   */
  const deleteTaskTemplate = (name) => {
    delete taskTemplates.value[name]
    localStorage.setItem('taskTemplates', JSON.stringify(taskTemplates.value))
    if (logConfig.value.batch) console.log(`🗑️ 任务模板已删除: ${name}`)
  }
  
  /**
   * 保存调度器配置
   */
  const saveSchedulerConfig = (config) => {
    Object.assign(schedulerConfig.value, config)
    localStorage.setItem('schedulerConfig', JSON.stringify(schedulerConfig.value))
    if (logConfig.value.batch) console.log(`💾 调度器配置已保存`)
  }
  
  /**
   * 保存自动重试配置
   */
  const saveAutoRetryConfig = (config) => {
    Object.assign(autoRetryConfig.value, config)
    localStorage.setItem('autoRetryConfig', JSON.stringify(autoRetryConfig.value))
    if (logConfig.value.batch) console.log(`💾 自动重试配置已保存:`, config)
  }
  
  /**
   * 清空执行历史
   */
  const clearHistory = () => {
    executionHistory.value = []
    localStorage.removeItem('batchTaskHistory')
    if (logConfig.value.batch) console.log(`🗑️ 执行历史已清空`)
  }
  
  /**
   * 设置并发数
   */
  const setMaxConcurrency = (count) => {
    if (count < 1 || count > 100) {
      if (logConfig.value.batch) console.warn('⚠️ 并发数必须在1-100之间')
      return
    }
    maxConcurrency.value = count
    localStorage.setItem('maxConcurrency', count.toString())
    if (logConfig.value.batch) console.log(`⚙️ 并发数已设置为: ${count}`)
  }
  
  /**
   * 设置爬塔次数
   */
  const setClimbTowerCount = (count) => {
    if (count < 0 || count > 100) {
      if (logConfig.value.batch) console.warn('⚠️ 爬塔次数必须在0-100之间')
      return
    }
    climbTowerCount.value = count
    localStorage.setItem('climbTowerCount', count.toString())
    if (logConfig.value.batch) console.log(`🗼 爬塔次数已设置为: ${count}`)
  }
  
  /**
   * 设置发车刷新次数
   */
  const setCarRefreshCount = (count) => {
    if (count < 0 || count > 10) {
      if (logConfig.value.batch) console.warn('⚠️ 发车刷新次数必须在0-10之间')
      return
    }
    carRefreshCount.value = count
    localStorage.setItem('carRefreshCount', count.toString())
    if (logConfig.value.batch) console.log(`🚗 发车刷新次数已设置为: ${count}`)
  }
  
  /**
   * 关闭进度显示
   */
  const closeProgressDisplay = () => {
    showProgress.value = false
    if (logConfig.value.batch) console.log(`🔒 进度显示已关闭`)
  }

  /**
   * 🆕 设置连接池模式（v3.13.0）
   */
  const setUseConnectionPool = (enabled) => {
    USE_CONNECTION_POOL.value = enabled
    localStorage.setItem('useConnectionPool', enabled.toString())
    if (logConfig.value.batch) console.log(`${enabled ? '🏊 连接池模式已启用' : '⚙️ 连接池模式已禁用'}`)
    
    if (enabled) {
      if (logConfig.value.batch) console.log(`
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🌟 连接池模式优势
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ 突破浏览器WebSocket连接数限制（10-20个）
✅ 实现真正的100并发稳定运行
✅ 连接复用，节省建立时间
✅ 内存占用更低（20连接 vs 100连接）
✅ 实时统计和监控
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
推荐配置：
  连接池大小: 20
  Token数量: 任意（100+也可以）
  预期效率: 比传统模式快2-3倍
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
      `)
    }
  }
  
  /**
   * 🆕 设置连接池大小（v3.13.0）
   */
  const setPoolSize = (size) => {
    if (size < 1 || size > 100) {
      if (logConfig.value.batch) console.warn('⚠️ 连接池大小必须在1-100之间')
      return
    }
    POOL_SIZE.value = size
    localStorage.setItem('poolSize', size.toString())
    if (logConfig.value.batch) console.log(`⚙️ 连接池大小已设置为: ${size}`)
    
    // 提供配置建议
    if (size <= 10) {
      if (logConfig.value.batch) console.log(`💡 适用场景: 网络环境一般，追求稳定性`)
    } else if (size <= 20) {
      if (logConfig.value.batch) console.log(`💡 适用场景: 网络环境良好，平衡性能与稳定性（推荐）`)
    } else {
      if (logConfig.value.batch) console.log(`💡 适用场景: 网络环境极好（企业/专线），追求极致性能`)
    }
  }
  
  /**
   * 🆕 设置最大并发请求数（v3.13.2）
   */
  const setMaxConcurrentRequests = (count) => {
    if (count < 1 || count > 100) {
      if (logConfig.value.batch) console.warn('⚠️ 最大并发请求数必须在1-100之间')
      return
    }
    MAX_CONCURRENT_REQUESTS.value = count
    localStorage.setItem('maxConcurrentRequests', count.toString())
    if (logConfig.value.batch) console.log(`⚙️ 最大并发请求数已设置为: ${count}`)
    if (logConfig.value.batch) console.log(`
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
💡 并发请求数说明
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
这个参数控制"同时执行任务的Token数量"

推荐配置：
1-3：极度保守，适合网络很差的情况
4-6：推荐配置，平衡稳定性和效率
7-10：激进配置，适合网络很好的情况
>10：不推荐，可能导致请求拥堵

当前设置：${count}
连接池大小：${POOL_SIZE.value}

工作原理：
- 连接池提供${POOL_SIZE.value}个可复用的连接
- 但同时只有${count}个Token在执行任务
- 这样避免了所有连接同时发请求导致拥堵
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    `)
  }

  /**
   * 🆕 设置性能模式（v3.14.1）
   * 简化单个token的UI更新以降低CPU占用
   * 
   * ✅ 不影响：总体进度统计、失败原因统计
   * 🎛️ 只影响：单个token的详细进度（进度条、当前任务名）
   */
  const setPerformanceMode = (enabled) => {
    PERFORMANCE_MODE.value = enabled
    localStorage.setItem('performanceMode', enabled.toString())
    
    const tokenCount = Object.keys(taskProgress.value).length
    
    if (enabled) {
      if (logConfig.value.batch) console.log(`
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🚀 性能模式已启用 (v3.14.1)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ 大幅降低CPU占用（可降低50%-70%）
✅ 简化单个token的UI更新（只显示关键状态）
✅ 适合超大规模并发（500+ tokens）

━━━ 保留的显示 ━━━
✔️ 总体进度统计（成功/失败/跳过数量）
✔️ 失败原因统计
✔️ Token状态（等待/执行中/完成/失败）

━━━ 隐藏的显示 ━━━
✖️ 单个token的进度百分比
✖️ 单个token的当前任务名称

当前token数量: ${tokenCount}
推荐使用场景: ${tokenCount > 500 ? '✅ 强烈推荐' : tokenCount > 200 ? '⚠️ 可选' : '❌ 不需要'}

⚠️ 注意：只影响界面显示，不影响任务执行和统计数据
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
      `)
    } else {
      if (logConfig.value.batch) console.log(`
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚙️ 性能模式已禁用
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ 恢复完整UI更新
✅ 显示进度百分比和当前任务
⚠️ CPU占用会相应增加

当前token数量: ${tokenCount}
${tokenCount > 500 ? '⚠️ 建议启用性能模式以降低CPU占用' : ''}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
      `)
    }
  }
  
  /**
   * 🆕 设置连接间隔时间
   */
  const setConnectionInterval = (interval) => {
    if (interval < 100 || interval > 1000) {
      if (logConfig.value.batch) console.warn('⚠️ 连接间隔必须在100-1000ms之间')
      return
    }
    CONNECTION_INTERVAL.value = interval
    localStorage.setItem('connectionInterval', interval.toString())
    if (logConfig.value.batch) console.log(`⏱️ 连接间隔已设置为: ${interval}ms`)
  }
  
  // ==================== 🆕 内存清理机制优化 v3.13.5 ====================
  
  /**
   * 清理已完成任务的进度数据（释放内存）
   * 🚀 v3.13.5.4: 缩短清理延迟至2分钟，更及时释放内存（700token优化）
   */
  const cleanupCompletedTaskProgress = () => {
    const now = Date.now()
    const CLEANUP_DELAY = 2 * 60 * 1000 // 🚀 从5分钟改为2分钟，更快清理
    let cleanedCount = 0
    
    // 🚀 使用Object.entries减少对象访问次数
    Object.entries(taskProgress.value).forEach(([tokenId, progress]) => {
      // 🔧 清理2分钟前完成的任务（包括成功、失败、跳过）
      // 失败原因已经在失败时记录到 failureReasonsStats，可以安全清理
      if ((progress.status === 'completed' || 
           progress.status === 'failed' ||
           progress.status === 'skipped') &&
          progress.endTime &&
          now - progress.endTime > CLEANUP_DELAY) {
        
        if (logConfig.value.batch) {
          console.log(`🧹 [内存清理] 清理token ${tokenId} 的进度数据 (完成于 ${Math.floor((now - progress.endTime) / 60000)} 分钟前)`)
        }
        
        // 🚀 显式清空对象属性，帮助GC
        if (progress.result) {
          Object.keys(progress.result).forEach(key => {
            progress.result[key] = null
          })
          progress.result = null
        }
        
        delete taskProgress.value[tokenId]
        cleanedCount++
      }
    })
    
    // 🚀 清理后手动触发shallowRef更新
    if (cleanedCount > 0) {
      triggerRef(taskProgress)
      if (logConfig.value.batch) {
        console.log(`✅ [内存清理] 清理了 ${cleanedCount} 个已完成任务的进度数据`)
      }
    }
    
    return cleanedCount
  }
  
  /**
   * 强制清理所有已完成任务的进度数据（立即释放内存）
   * 🆕 v3.14.0: 增强内存清理，只保留失败token的精简信息
   */
  const forceCleanupTaskProgress = () => {
    let cleanedCount = 0
    const failedTokensToKeep = {} // 只保留失败token的精简信息
    
    Object.keys(taskProgress.value).forEach(tokenId => {
      const progress = taskProgress.value[tokenId]
      
      // 🔧 成功和跳过的token完全删除
      if (progress.status === 'completed' || progress.status === 'skipped') {
        delete taskProgress.value[tokenId]
        cleanedCount++
      } 
      // 🔧 失败的token只保留关键信息（减少80%内存占用）
      else if (progress.status === 'failed') {
        failedTokensToKeep[tokenId] = {
          status: 'failed',
          error: progress.error,
          endTime: progress.endTime
          // 不保存result、currentTask等详细数据
        }
        delete taskProgress.value[tokenId]
        cleanedCount++
      }
    })
    
    // 将失败token的精简信息放回
    Object.assign(taskProgress.value, failedTokensToKeep)
    
    if (cleanedCount > 0) {
      console.log(`✅ [强制清理] 清理了 ${cleanedCount} 个任务的进度数据`)
      if (Object.keys(failedTokensToKeep).length > 0) {
        console.log(`📊 [内存优化] 保留了 ${Object.keys(failedTokensToKeep).length} 个失败token的精简信息`)
      }
    }
    
    return cleanedCount
  }
  
  // 定期清理定时器（每2分钟执行一次）
  let cleanupTimer = null
  
  /**
   * 🚀 v3.13.5.4: 启动定期清理机制（优化清理频率）
   */
  const startPeriodicCleanup = () => {
    // 清除旧的定时器
    if (cleanupTimer) {
      clearInterval(cleanupTimer)
    }
    
    // 🚀 从每5分钟改为每2分钟，更频繁清理（700token优化）
    cleanupTimer = setInterval(() => {
      cleanupCompletedTaskProgress()
      // 🚀 同时清理UI更新队列
      clearPendingUIUpdates()
    }, 2 * 60 * 1000)
    
    if (logConfig.value.batch) {
      console.log('🔄 [内存清理] 定期清理机制已启动（每2分钟）')
    }
  }
  
  /**
   * 停止定期清理机制
   */
  const stopPeriodicCleanup = () => {
    if (cleanupTimer) {
      clearInterval(cleanupTimer)
      cleanupTimer = null
      if (logConfig.value.batch) {
        console.log('🛑 [内存清理] 定期清理机制已停止')
      }
    }
  }
  
  // 启动定期清理（应用初始化时）
  startPeriodicCleanup()
  
  // ==================== 🆕 内存监控机制 v3.14.0 (P4) ====================
  
  /**
   * 获取当前内存使用情况（MB）
   * @returns {Object|null} { used, total, limit } 或 null（不支持的浏览器）
   */
  const getMemoryUsage = () => {
    if (!performance.memory) {
      return null  // Firefox/Safari等浏览器不支持
    }
    
    return {
      used: Math.round(performance.memory.usedJSHeapSize / 1048576),   // MB
      total: Math.round(performance.memory.totalJSHeapSize / 1048576), // MB
      limit: Math.round(performance.memory.jsHeapSizeLimit / 1048576)  // MB
    }
  }
  
  /**
   * 监控内存使用，超限时自动清理
   */
  const monitorMemoryUsage = () => {
    if (!isExecuting.value) return
    
    const memory = getMemoryUsage()
    if (!memory) return  // 浏览器不支持，直接返回
    
    const usagePercent = (memory.used / memory.limit) * 100
    
    // 🟡 警告级别：内存使用超过60%（从70%降低到60%，更早触发清理）
    if (usagePercent > 60 && usagePercent <= 80) {
      console.warn(
        `⚠️ [自动清理] 内存使用率: ${usagePercent.toFixed(1)}% ` +
        `(${memory.used}MB / ${memory.limit}MB) - 触发标准清理`
      )
      
      // 执行标准清理
      const cleaned = forceCleanupTaskProgress()
      clearPendingUIUpdates()
      console.log(`🧹 [自动清理] 已清理 ${cleaned} 个任务数据`)
    }
    
    // 🔴 危险级别：内存使用超过80%（从85%降低到80%）
    if (usagePercent > 80) {
      console.error(
        `🚨 [内存监控] 内存使用率危险: ${usagePercent.toFixed(1)}% ` +
        `(${memory.used}MB / ${memory.limit}MB) - 触发紧急清理`
      )
      
      // 执行标准清理
      const cleaned = forceCleanupTaskProgress()
      clearPendingUIUpdates()
      clearConsoleLogs() // 🆕 v3.14.0: 清空控制台日志
      console.log(`🧹 [紧急清理] 已清理 ${cleaned} 个任务数据`)
      
      // 🔥 紧急措施：删除所有任务的详细result数据
      let deletedCount = 0
      Object.keys(taskProgress.value).forEach(tokenId => {
        const progress = taskProgress.value[tokenId]
        if (progress && progress.result) {
          delete progress.result
          deletedCount++
        }
      })
      
      if (deletedCount > 0) {
        triggerRef(taskProgress)
        console.error(`🗑️ [紧急清理] 已删除 ${deletedCount} 个Token的详细结果数据`)
      }
      
      // 建议垃圾回收（Chrome需要启动参数 --expose-gc）
      if (typeof window !== 'undefined' && window.gc) {
        window.gc()
        console.warn('♻️ [紧急清理] 已触发强制垃圾回收')
      }
    }
  }
  
  /**
   * 启动内存监控定时器（每30秒检查一次）
   */
  let memoryMonitorTimer = null
  
  const startMemoryMonitor = () => {
    if (memoryMonitorTimer) return  // 已启动，避免重复
    
    // 立即执行一次检查
    monitorMemoryUsage()
    
    // 每30秒检查一次
    memoryMonitorTimer = setInterval(() => {
      monitorMemoryUsage()
    }, 30000) // 30秒检查一次
    
    console.log('🔄 [内存监控] 已启动（每30秒自动检查并清理）')
  }
  
  /**
   * 停止内存监控
   */
  const stopMemoryMonitor = () => {
    if (memoryMonitorTimer) {
      clearInterval(memoryMonitorTimer)
      memoryMonitorTimer = null
      
      if (logConfig.value.batch) {
        console.log('⏹️ [内存监控] 已停止')
      }
    }
  }
  
  /**
   * 🆕 v3.14.0: 清理控制台日志（减少内存占用）
   * 浏览器控制台会保留所有日志历史，对于916个token的批量任务，
   * 可能产生数万条日志，占用大量内存
   */
  const clearConsoleLogs = () => {
    try {
      console.clear()
      console.log('🧹 [日志清理] 已清空控制台日志历史，释放内存')
    } catch (e) {
      // 某些浏览器可能不支持console.clear()
      console.log('⚠️ [日志清理] 浏览器不支持清空控制台')
    }
  }
  
  // ==================== 结束：内存监控机制 ====================
  // ==================== 结束：内存清理机制 ====================
  
  return {
    // 状态
    isExecuting,
    isPaused,
    currentBatch,
    showProgress,
    maxConcurrency,
    climbTowerCount,
    carRefreshCount,
    executingTokens,
    taskProgress,
    executionStats,
    failureReasonsStats, // 🆕 失败原因统计
    executionHistory,
    taskTemplates,
    selectedTemplate,
    schedulerConfig,
    autoRetryConfig,
    currentRetryRound,
    isAutoRetryWaiting,  // 🔥 自动重试等待标志
    savedProgress,
    
    // 🆕 日志控制配置
    logConfig,
    saveLogConfig,
    
    // 🆕 v3.13.0 连接池配置
    USE_CONNECTION_POOL,
    POOL_SIZE,
    
    // 🆕 v3.13.2 请求并发控制
    MAX_CONCURRENT_REQUESTS,
    
    // 🆕 连接间隔配置
    CONNECTION_INTERVAL,
    
    // 🆕 v3.14.1 性能模式
    PERFORMANCE_MODE,
    
    // 计算属性
    overallProgress,
    canExecute,
    currentTemplateTasks,
    hasSavedProgress,
    
    // 方法
    startBatchExecution,
    pauseExecution,
    resumeExecution,
    stopExecution,
    retryFailedTasks,
    saveTaskTemplate,
    deleteTaskTemplate,
    saveSchedulerConfig,
    saveAutoRetryConfig,
    clearHistory,
    setMaxConcurrency,
    setClimbTowerCount,
    setCarRefreshCount,
    closeProgressDisplay,
    clearSavedProgress,
    
    // 🆕 v3.13.0 连接池方法
    setUseConnectionPool,
    setPoolSize,
    
    // 🆕 v3.13.2 请求并发控制方法
    setMaxConcurrentRequests,
    
    // 🆕 连接间隔配置方法
    setConnectionInterval,
    
    // 🆕 v3.14.1 性能模式方法
    setPerformanceMode,
    
    // 🆕 v3.13.5 内存清理方法
    cleanupCompletedTaskProgress,
    forceCleanupTaskProgress,
    startPeriodicCleanup,
    stopPeriodicCleanup,
    clearPendingUIUpdates,
    
    // 🆕 v3.14.0 内存监控方法
    getMemoryUsage,
    monitorMemoryUsage,
    clearConsoleLogs
  }
})

