10 KiB
10 KiB
问题修复 - 发车显示不及时 (v3.10.2)
📋 问题描述
用户反馈:"执行进度里,token的发车显示不及时"
具体表现
在批量任务执行过程中,TaskProgressCard.vue 组件显示的发车状态和发车上限信息不会实时更新:
批量任务开始时:
┌─────────────────────┐
│ 809服-xxx │
│ 发车: 0/4 今日未发车│ ← 初始显示
└─────────────────────┘
发车任务执行中...
└─ 服务器返回 12000050
└─ localStorage 更新为 4/4
执行完成后:
┌─────────────────────┐
│ 809服-xxx │
│ 发车: 0/4 今日未发车│ ← 仍然显示旧数据!
└─────────────────────┘
🔍 问题根源
技术原因
TaskProgressCard.vue 中的 dailyCarSendCount 是一个 computed 属性,直接从 localStorage 读取数据:
// 原代码(有问题)
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 的变化!
-
computed的响应式机制:computed只会在其依赖的 响应式数据 发生变化时重新计算localStorage.getItem()不是响应式的
-
数据流向:
batchTaskStore.js └─ 更新 localStorage.setItem('car_daily_send_count_...', '4') ↓ localStorage 已更新 ↓ TaskProgressCard.vue └─ computed 不知道 localStorage 变了 └─ 继续显示旧值 0 -
无法自动检测:
- Vue 无法监听到
localStorage的setItem操作 - 即使数据已经更新,组件也不会重新渲染
- Vue 无法监听到
💡 v3.10.2 修复方案
核心思路
将 computed 改为 ref,并手动触发刷新
- 使用
ref代替computed,以便手动更新 - 监听任务结果的变化,自动刷新发车次数
- 在组件挂载时刷新一次,确保初始显示正确
修复内容
1. 改用 ref + 手动刷新函数
修改前:
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')
})
修改后:
// 获取今日发车次数的 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. 监听任务结果变化
// 监听任务结果变化,自动刷新发车次数
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. 监听任务状态变化
// 监听任务状态变化,当任务完成或失败时刷新
watch(() => props.progress?.status, (newStatus, oldStatus) => {
if (newStatus !== oldStatus && (newStatus === 'completed' || newStatus === 'failed')) {
// 任务完成或失败时,刷新发车次数
setTimeout(() => {
refreshCarSendCount()
}, 100)
}
})
工作原理:
- 监听整个任务的状态变化
- 当任务完成或失败时,刷新发车次数
- 作为兜底机制,确保任务结束后一定会刷新
4. 组件挂载时刷新
// 组件挂载时刷新发车次数
onMounted(() => {
refreshCarSendCount()
})
工作原理:
- 组件首次渲染时从
localStorage读取最新值 - 确保初始显示是准确的
5. 添加必要的导入
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)?
setTimeout(() => {
refreshCarSendCount()
}, 100)
原因:
-
确保 localStorage 已更新:
batchTaskStore更新localStorage- Vue 更新
props.progress.result.sendCar watch回调触发- 这些操作可能不是完全同步的
-
异步写入的保险:
- 虽然
localStorage.setItem()通常是同步的 - 但在某些浏览器或情况下可能有延迟
- 100ms 的延迟可以确保数据已经写入
- 虽然
-
避免竞态条件:
- 如果立即读取,可能还是旧值
- 延迟后读取,确保是最新值
为什么使用两个 watch?
-
第一个 watch:监听
sendCar任务结果- 更精确:只在发车任务有结果时触发
- 更及时:任务一完成就立即刷新
-
第二个 watch:监听整体任务状态
- 兜底机制:确保任务结束时一定会刷新
- 更全面:即使第一个 watch 没触发,这个也会
为什么使用 { deep: true }?
watch(() => props.progress?.result?.sendCar, ..., { deep: true })
原因:
result.sendCar是一个对象,包含success、data、message等字段deep: true确保对象内部任何属性变化都会触发 watch- 这样无论任务成功还是失败,都能正确触发刷新
🧪 测试建议
测试场景1:首次打开批量任务面板
- 打开批量任务面板
- 观察 Token 卡片的发车显示
- 预期结果:显示正确的发车次数(从 localStorage 读取)
测试场景2:执行发车任务
- 执行包含发车任务的批量自动化
- 观察 Token 卡片的发车显示
- 预期结果:
- 发车任务执行过程中,显示实时更新
- 任务完成后,立即显示最新的发车次数
- 控制台输出:
🔄 [token_xxx] 刷新发车次数显示: X/4
测试场景3:服务器端已达上限
- 使用已达上限的账号(服务器端4次)
- 客户端 localStorage 为 0/4
- 执行批量任务
- 预期结果:
- 初始显示:0/4
- 任务执行后立即更新为:4/4(根据错误码 12000050 更新)
- Token 卡片显示:"今日已达上限"
测试场景4:多 Token 并发
- 选择多个 Token 执行批量任务
- 观察每个 Token 卡片的发车显示
- 预期结果:
- 每个 Token 的发车次数独立更新
- 不会互相干扰
- 所有 Token 都显示正确的发车次数
🔗 相关修复
本次修复建立在以下修复的基础上:
- v3.10.0 - 同步服务器发车次数(失败)
- v3.10.1 - 修复服务器
sendCount不可靠 - v3.10.2 - 修复发车显示不及时(本次)
📋 更新日志
版本: v3.10.2
日期: 2025-10-08
类型: 问题修复
修改内容:
- ✅ 将
dailyCarSendCount从computed改为ref - ✅ 添加
refreshCarSendCount()手动刷新函数 - ✅ 监听
props.progress.result.sendCar变化,自动刷新 - ✅ 监听
props.progress.status变化,兜底刷新 - ✅ 在
onMounted时刷新,确保初始显示准确 - ✅ 添加必要的导入:
watch、onMounted
影响范围:
src/components/TaskProgressCard.vue
解决问题:
- 发车次数显示不及时
- 任务执行后显示不更新
- 需要刷新页面才能看到最新数据
用户体验提升:
- ✅ 发车次数实时更新
- ✅ 任务完成后自动刷新
- ✅ 无需手动刷新页面
- ✅ 初始显示准确