# 问题修复 - 发车显示不及时 (v3.10.2)

## 📋 问题描述

用户反馈："执行进度里，token的发车显示不及时"

### 具体表现

在批量任务执行过程中，`TaskProgressCard.vue` 组件显示的发车状态和发车上限信息不会实时更新：

```
批量任务开始时：
┌─────────────────────┐
│ 809服-xxx           │
│ 发车: 0/4  今日未发车│  ← 初始显示
└─────────────────────┘

发车任务执行中...
└─ 服务器返回 12000050
└─ localStorage 更新为 4/4

执行完成后：
┌─────────────────────┐
│ 809服-xxx           │
│ 发车: 0/4  今日未发车│  ← 仍然显示旧数据！
└─────────────────────┘
```

## 🔍 问题根源

### 技术原因

`TaskProgressCard.vue` 中的 `dailyCarSendCount` 是一个 `computed` 属性，直接从 `localStorage` 读取数据：

```javascript
// 原代码（有问题）
const dailyCarSendCount = computed(() => {
  const today = new Date().toLocaleDateString('zh-CN', { 
    year: 'numeric', 
    month: '2-digit', 
    day: '2-digit' 
  })
  const key = `car_daily_send_count_${today}_${props.tokenId}`
  return parseInt(localStorage.getItem(key) || '0')
})
```

### 为什么不更新？

**Vue 的响应式系统无法追踪 `localStorage` 的变化！**

1. **`computed` 的响应式机制**：
   - `computed` 只会在其依赖的 **响应式数据** 发生变化时重新计算
   - `localStorage.getItem()` 不是响应式的

2. **数据流向**：
   ```
   batchTaskStore.js
   └─ 更新 localStorage.setItem('car_daily_send_count_...', '4')
      ↓
   localStorage 已更新
      ↓
   TaskProgressCard.vue
   └─ computed 不知道 localStorage 变了
   └─ 继续显示旧值 0
   ```

3. **无法自动检测**：
   - Vue 无法监听到 `localStorage` 的 `setItem` 操作
   - 即使数据已经更新，组件也不会重新渲染

## 💡 v3.10.2 修复方案

### 核心思路

**将 `computed` 改为 `ref`，并手动触发刷新**

1. 使用 `ref` 代替 `computed`，以便手动更新
2. 监听任务结果的变化，自动刷新发车次数
3. 在组件挂载时刷新一次，确保初始显示正确

### 修复内容

#### 1. 改用 `ref` + 手动刷新函数

**修改前**：
```javascript
const dailyCarSendCount = computed(() => {
  const today = new Date().toLocaleDateString('zh-CN', { 
    year: 'numeric', 
    month: '2-digit', 
    day: '2-digit' 
  })
  const key = `car_daily_send_count_${today}_${props.tokenId}`
  return parseInt(localStorage.getItem(key) || '0')
})
```

**修改后**：
```javascript
// 获取今日发车次数的 key
const getCarSendCountKey = () => {
  const today = new Date().toLocaleDateString('zh-CN', { 
    year: 'numeric', 
    month: '2-digit', 
    day: '2-digit' 
  })
  return `car_daily_send_count_${today}_${props.tokenId}`
}

// 使用 ref 而不是 computed，以便手动刷新
const dailyCarSendCount = ref(parseInt(localStorage.getItem(getCarSendCountKey()) || '0'))

// 刷新发车次数的函数
const refreshCarSendCount = () => {
  const key = getCarSendCountKey()
  const newCount = parseInt(localStorage.getItem(key) || '0')
  dailyCarSendCount.value = newCount
  console.log(`🔄 [${props.tokenId}] 刷新发车次数显示: ${newCount}/4`)
}
```

#### 2. 监听任务结果变化

```javascript
// 监听任务结果变化，自动刷新发车次数
watch(() => props.progress?.result?.sendCar, (newResult, oldResult) => {
  if (newResult && newResult !== oldResult) {
    // 发车任务有新结果，等待一小段时间确保 localStorage 已更新
    setTimeout(() => {
      refreshCarSendCount()
    }, 100)
  }
}, { deep: true })
```

**工作原理**：
- 监听 `props.progress.result.sendCar` 的变化
- 当 `sendCar` 任务有新结果时（成功或失败）
- 等待 100ms 确保 `localStorage` 已更新
- 调用 `refreshCarSendCount()` 从 `localStorage` 读取最新值

#### 3. 监听任务状态变化

```javascript
// 监听任务状态变化，当任务完成或失败时刷新
watch(() => props.progress?.status, (newStatus, oldStatus) => {
  if (newStatus !== oldStatus && (newStatus === 'completed' || newStatus === 'failed')) {
    // 任务完成或失败时，刷新发车次数
    setTimeout(() => {
      refreshCarSendCount()
    }, 100)
  }
})
```

**工作原理**：
- 监听整个任务的状态变化
- 当任务完成或失败时，刷新发车次数
- 作为兜底机制，确保任务结束后一定会刷新

#### 4. 组件挂载时刷新

```javascript
// 组件挂载时刷新发车次数
onMounted(() => {
  refreshCarSendCount()
})
```

**工作原理**：
- 组件首次渲染时从 `localStorage` 读取最新值
- 确保初始显示是准确的

#### 5. 添加必要的导入

```javascript
import { ref, computed, watch, onMounted } from 'vue'
```

## 📊 修复效果对比

### 修改前（v3.10.1）

```
时间线：
00:00 - 批量任务开始
        TaskProgressCard 显示: 发车: 0/4 ✓
        
00:05 - sendCar 任务执行
        batchTaskStore 更新 localStorage: 0 → 4
        
00:06 - sendCar 任务完成
        TaskProgressCard 显示: 发车: 0/4 ✗ (未更新！)
        
00:10 - 批量任务完成
        TaskProgressCard 显示: 发车: 0/4 ✗ (仍未更新！)
        
用户需要刷新页面才能看到正确的 4/4
```

### 修改后（v3.10.2）

```
时间线：
00:00 - 批量任务开始
        TaskProgressCard 显示: 发车: 0/4 ✓
        
00:05 - sendCar 任务执行
        batchTaskStore 更新 localStorage: 0 → 4
        
00:06 - sendCar 任务完成
        props.progress.result.sendCar 更新
        触发 watch 回调
        100ms 后调用 refreshCarSendCount()
        TaskProgressCard 显示: 发车: 4/4 ✓ (自动更新！)
        
00:10 - 批量任务完成
        再次触发刷新（兜底）
        TaskProgressCard 显示: 发车: 4/4 ✓
        
用户无需刷新页面，自动显示正确的 4/4
```

## 🎯 关键优势

| 特性 | 修改前 | 修改后 |
|------|--------|--------|
| **数据类型** | `computed` | `ref` + 手动刷新 |
| **更新机制** | 依赖响应式系统 | 主动监听和刷新 |
| **初始显示** | 可能不准确 | `onMounted` 确保准确 |
| **任务执行中** | 不更新 | **实时更新** |
| **任务完成后** | 不更新 | **自动更新** |
| **用户体验** | ❌ 需要手动刷新页面 | ✅ 自动显示最新数据 |

## 📝 技术细节

### 为什么使用 `setTimeout(100)`？

```javascript
setTimeout(() => {
  refreshCarSendCount()
}, 100)
```

**原因**：
1. **确保 localStorage 已更新**：
   - `batchTaskStore` 更新 `localStorage`
   - Vue 更新 `props.progress.result.sendCar`
   - `watch` 回调触发
   - 这些操作可能不是完全同步的

2. **异步写入的保险**：
   - 虽然 `localStorage.setItem()` 通常是同步的
   - 但在某些浏览器或情况下可能有延迟
   - 100ms 的延迟可以确保数据已经写入

3. **避免竞态条件**：
   - 如果立即读取，可能还是旧值
   - 延迟后读取，确保是最新值

### 为什么使用两个 `watch`？

1. **第一个 watch**：监听 `sendCar` 任务结果
   - 更精确：只在发车任务有结果时触发
   - 更及时：任务一完成就立即刷新

2. **第二个 watch**：监听整体任务状态
   - 兜底机制：确保任务结束时一定会刷新
   - 更全面：即使第一个 watch 没触发，这个也会

### 为什么使用 `{ deep: true }`？

```javascript
watch(() => props.progress?.result?.sendCar, ..., { deep: true })
```

**原因**：
- `result.sendCar` 是一个对象，包含 `success`、`data`、`message` 等字段
- `deep: true` 确保对象内部任何属性变化都会触发 watch
- 这样无论任务成功还是失败，都能正确触发刷新

## 🧪 测试建议

### 测试场景1：首次打开批量任务面板

1. 打开批量任务面板
2. 观察 Token 卡片的发车显示
3. **预期结果**：显示正确的发车次数（从 localStorage 读取）

### 测试场景2：执行发车任务

1. 执行包含发车任务的批量自动化
2. 观察 Token 卡片的发车显示
3. **预期结果**：
   - 发车任务执行过程中，显示实时更新
   - 任务完成后，立即显示最新的发车次数
   - 控制台输出：`🔄 [token_xxx] 刷新发车次数显示: X/4`

### 测试场景3：服务器端已达上限

1. 使用已达上限的账号（服务器端4次）
2. 客户端 localStorage 为 0/4
3. 执行批量任务
4. **预期结果**：
   - 初始显示：0/4
   - 任务执行后立即更新为：4/4（根据错误码 12000050 更新）
   - Token 卡片显示："今日已达上限"

### 测试场景4：多 Token 并发

1. 选择多个 Token 执行批量任务
2. 观察每个 Token 卡片的发车显示
3. **预期结果**：
   - 每个 Token 的发车次数独立更新
   - 不会互相干扰
   - 所有 Token 都显示正确的发车次数

## 🔗 相关修复

本次修复建立在以下修复的基础上：

1. **v3.10.0** - 同步服务器发车次数（失败）
2. **v3.10.1** - 修复服务器 `sendCount` 不可靠
3. **v3.10.2** - 修复发车显示不及时（本次）

## 📋 更新日志

**版本**: v3.10.2  
**日期**: 2025-10-08  
**类型**: 问题修复

**修改内容**:
1. ✅ 将 `dailyCarSendCount` 从 `computed` 改为 `ref`
2. ✅ 添加 `refreshCarSendCount()` 手动刷新函数
3. ✅ 监听 `props.progress.result.sendCar` 变化，自动刷新
4. ✅ 监听 `props.progress.status` 变化，兜底刷新
5. ✅ 在 `onMounted` 时刷新，确保初始显示准确
6. ✅ 添加必要的导入：`watch`、`onMounted`

**影响范围**:
- `src/components/TaskProgressCard.vue`

**解决问题**:
- 发车次数显示不及时
- 任务执行后显示不更新
- 需要刷新页面才能看到最新数据

**用户体验提升**:
- ✅ 发车次数实时更新
- ✅ 任务完成后自动刷新
- ✅ 无需手动刷新页面
- ✅ 初始显示准确

