# 俱乐部信息自动刷新 v2.1.2

## 📅 更新时间
2025-10-12 23:15

## 🎯 问题描述

### 现象
进入"游戏功能"页面后，俱乐部信息不会自动刷新，需要手动点击"刷新"按钮才能加载数据。

### 原因分析
`ClubInfo.vue` 组件缺少自动刷新逻辑：
- ❌ 没有在 `onMounted` 时调用 `refreshClub()`
- ❌ 没有检查 WebSocket 连接状态
- ❌ 没有处理异步初始化时序问题

---

## ✅ 解决方案

### 实现逻辑
参考月度任务的成功实现，采用相同的自动刷新机制：

1. **延迟启动**（500ms）
   - 等待组件完全挂载
   - 避免过早调用导致失败

2. **轮询检查 WebSocket 状态**（每秒一次）
   - 检查 `selectedToken` 是否存在
   - 检查 WebSocket 连接状态是否为 `connected`
   - 最多检查 10 次（10 秒超时）

3. **连接成功后自动刷新**
   - 延迟 1 秒执行 `refreshClub()`
   - 设置 `clubInfoFetched` 标志，防止重复刷新

4. **Token 切换监听**
   - 监听 `selectedToken` 变化
   - 切换 Token 时重置 `clubInfoFetched` 标志

---

## 🔧 代码实现

### 新增导入
```javascript
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
```

### 新增状态
```javascript
const clubInfoFetched = ref(false)
let wsCheckInterval = null
let checkCount = 0
const maxCheckCount = 10
```

### onMounted 生命周期
```javascript
onMounted(() => {
  console.log('🏛️ [俱乐部] ClubInfo 组件已挂载')
  
  // 延迟 500ms 后开始检查 WebSocket 连接状态
  setTimeout(() => {
    wsCheckInterval = setInterval(() => {
      checkCount++
      
      if (clubInfoFetched.value) {
        console.log('🏛️ [俱乐部] 已成功获取数据，停止检查')
        clearInterval(wsCheckInterval)
        return
      }
      
      if (checkCount > maxCheckCount) {
        console.warn('🏛️ [俱乐部] 超过最大检查次数，停止自动刷新')
        clearInterval(wsCheckInterval)
        return
      }
      
      const token = tokenStore.selectedToken
      if (!token) {
        console.log('🏛️ [俱乐部] Token 未选中，继续等待...')
        return
      }
      
      const status = tokenStore.getWebSocketStatus(token.id)
      console.log(`🏛️ [俱乐部] 检查 ${checkCount}/${maxCheckCount}，WebSocket 状态: ${status}`)
      
      if (status === 'connected') {
        console.log('🏛️ [俱乐部] WebSocket 已连接，准备自动刷新')
        
        // 连接成功后延迟 1 秒刷新，确保组件完全初始化
        setTimeout(() => {
          console.log('🏛️ [俱乐部] 执行自动刷新')
          refreshClub()
          clubInfoFetched.value = true
        }, 1000)
        
        clearInterval(wsCheckInterval)
      }
    }, 1000) // 每秒检查一次
  }, 500)
})
```

### onUnmounted 清理
```javascript
onUnmounted(() => {
  console.log('🏛️ [俱乐部] ClubInfo 组件卸载，清理定时器')
  if (wsCheckInterval) {
    clearInterval(wsCheckInterval)
  }
})
```

### Token 切换监听
```javascript
watch(() => tokenStore.selectedToken, (newToken, oldToken) => {
  if (newToken?.id !== oldToken?.id) {
    console.log('🏛️ [俱乐部] Token 切换，重置状态')
    clubInfoFetched.value = false
  }
})
```

---

## 🔍 工作流程

### 时序图
```
用户进入页面
    ↓
组件 onMounted (延迟 500ms)
    ↓
开始轮询检查 (每秒一次)
    ↓
检查 Token 是否存在? ───No──→ 继续等待
    ↓ Yes
检查 WebSocket 状态?
    ↓ connected
延迟 1 秒执行刷新
    ↓
调用 refreshClub()
    ↓
发送 legion_getinfo 命令
    ↓
接收 legion_getinforesp 响应
    ↓
更新 gameData.legionInfo
    ↓
UI 自动刷新（computed 响应式）
    ↓
设置 clubInfoFetched = true
    ↓
停止轮询
```

---

## 📊 调试日志示例

### 正常流程
```
🏛️ [俱乐部] ClubInfo 组件已挂载
🏛️ [俱乐部] 检查 1/10，WebSocket 状态: connecting
🏛️ [俱乐部] 检查 2/10，WebSocket 状态: connecting
🏛️ [俱乐部] 检查 3/10，WebSocket 状态: connected
🏛️ [俱乐部] WebSocket 已连接，准备自动刷新
🏛️ [俱乐部] 执行自动刷新
📤 发送消息: legion_getinfo {}
📥 收到响应: legion_getinforesp { info: {...} }
🏛️ 军团信息已更新: { hasInfo: true, clubName: "xxx俱乐部", memberCount: 30 }
🏛️ [俱乐部] 已成功获取数据，停止检查
```

### Token 未选中
```
🏛️ [俱乐部] ClubInfo 组件已挂载
🏛️ [俱乐部] 检查 1/10，Token 未选中，继续等待...
🏛️ [俱乐部] 检查 2/10，Token 未选中，继续等待...
🏛️ [俱乐部] 检查 3/10，Token 未选中，继续等待...
...
🏛️ [俱乐部] 超过最大检查次数，停止自动刷新
```

### WebSocket 连接失败
```
🏛️ [俱乐部] ClubInfo 组件已挂载
🏛️ [俱乐部] 检查 1/10，WebSocket 状态: connecting
🏛️ [俱乐部] 检查 2/10，WebSocket 状态: connecting
🏛️ [俱乐部] 检查 3/10，WebSocket 状态: error
🏛️ [俱乐部] 检查 4/10，WebSocket 状态: error
...
🏛️ [俱乐部] 超过最大检查次数，停止自动刷新
```

---

## 🎯 关键参数

| 参数 | 值 | 说明 |
|------|-----|------|
| **初始延迟** | 500ms | 组件挂载后延迟启动检查 |
| **检查间隔** | 1000ms | 每秒检查一次 WebSocket 状态 |
| **最大检查次数** | 10 次 | 超过 10 次后放弃自动刷新 |
| **刷新延迟** | 1000ms | WebSocket 连接后延迟刷新 |

### 总超时时间
```
初始延迟 + (检查间隔 × 最大检查次数) = 500ms + (1000ms × 10) = 10.5s
```

---

## 🆚 与月度任务的对比

### 相同点
- ✅ 采用相同的轮询检查机制
- ✅ 相同的延迟策略（500ms + 1000ms）
- ✅ 相同的超时保护（10 次检查）
- ✅ 相同的状态标志（防止重复刷新）
- ✅ 相同的 Token 切换监听

### 不同点
| 特性 | 月度任务 | 俱乐部信息 |
|------|---------|-----------|
| **标志名称** | `monthTaskFetched` | `clubInfoFetched` |
| **日志前缀** | `[月度任务]` | `[俱乐部]` |
| **刷新函数** | `fetchMonthlyActivity()` | `refreshClub()` |
| **命令名称** | `activity_get` | `legion_getinfo` |
| **响应名称** | `activity_getresp` | `legion_getinforesp` |

---

## 📋 修改文件清单

### 已修改文件（1个）
**`src/components/ClubInfo.vue`**

#### 变更内容
1. ✅ 新增 `onMounted`、`onUnmounted`、`watch` 导入
2. ✅ 新增 `clubInfoFetched` 状态标志
3. ✅ 实现 WebSocket 状态轮询检查
4. ✅ 实现自动刷新逻辑
5. ✅ 实现定时器清理
6. ✅ 实现 Token 切换监听

---

## 🧪 测试验证

### 测试用例1：正常自动刷新
**前置条件**：
- Token 已选中
- WebSocket 已连接

**操作步骤**：
1. 进入"游戏功能"页面
2. 等待 2-3 秒

**预期结果**：
- ✅ 俱乐部信息自动加载
- ✅ 显示俱乐部名称、成员数等信息
- ✅ 控制台输出自动刷新日志

### 测试用例2：Token 未选中
**前置条件**：
- 未选中任何 Token

**操作步骤**：
1. 进入"游戏功能"页面
2. 等待 10 秒

**预期结果**：
- ✅ 显示"暂无俱乐部"空状态
- ✅ 控制台提示"Token 未选中"
- ✅ 10 秒后停止检查

### 测试用例3：WebSocket 连接中
**前置条件**：
- Token 已选中
- WebSocket 正在连接中

**操作步骤**：
1. 进入"游戏功能"页面
2. 观察自动刷新过程

**预期结果**：
- ✅ 持续检查 WebSocket 状态
- ✅ 连接成功后自动刷新
- ✅ 俱乐部信息正确显示

### 测试用例4：Token 切换
**前置条件**：
- 已有多个 Token

**操作步骤**：
1. 进入"游戏功能"页面
2. 等待俱乐部信息加载完成
3. 切换到另一个 Token

**预期结果**：
- ✅ `clubInfoFetched` 标志重置
- ✅ 允许下次进入页面时重新自动刷新

### 测试用例5：快速切换页面
**操作步骤**：
1. 进入"游戏功能"页面
2. 立即切换到其他页面

**预期结果**：
- ✅ 组件卸载，定时器被清理
- ✅ 无内存泄漏
- ✅ 无错误日志

---

## 💡 使用说明

### 自动刷新
1. 确保已选中 Token
2. 进入"游戏功能"页面
3. 等待 2-3 秒，俱乐部信息自动加载

### 手动刷新
1. 点击右上角"刷新"按钮
2. 立即重新获取俱乐部信息

### 查看调试日志
打开浏览器控制台，查看以 `🏛️ [俱乐部]` 开头的日志

---

## 🔮 后续优化方向

### 1. 统一自动刷新机制（P1）
目前月度任务和俱乐部信息都使用相似的逻辑，可以抽取为公共 composable：

```javascript
// composables/useAutoRefresh.js
export function useAutoRefresh(options) {
  const { 
    refreshFn,      // 刷新函数
    checkInterval = 1000,  // 检查间隔
    maxCheckCount = 10,    // 最大检查次数
    initialDelay = 500,    // 初始延迟
    refreshDelay = 1000,   // 刷新延迟
    logPrefix = '自动刷新'  // 日志前缀
  } = options
  
  // ... 通用逻辑
}

// 使用
const { start, stop } = useAutoRefresh({
  refreshFn: refreshClub,
  logPrefix: '[俱乐部]'
})
```

### 2. 智能重试机制（P2）
- [ ] 刷新失败时自动重试
- [ ] 指数退避策略
- [ ] 最大重试次数限制

### 3. 加载状态提示（P2）
- [ ] 显示"正在加载俱乐部信息..."
- [ ] 显示加载进度
- [ ] 加载失败提示

### 4. 数据缓存（P3）
- [ ] 缓存俱乐部信息到 localStorage
- [ ] 离线模式下显示缓存数据
- [ ] 定期刷新缓存

---

## 🐛 已知问题

### 问题1：重复刷新
**现象**：在某些情况下可能触发多次刷新

**原因**：
- `watch` 监听可能触发额外刷新
- 手动点击刷新按钮

**解决方案**：
- 使用 `clubInfoFetched` 标志防止重复
- 后续可添加防抖/节流

### 问题2：检查次数固定
**现象**：超时时间固定为 10 秒

**影响**：
- 网络慢时可能不够
- 网络快时有浪费

**后续优化**：
- 根据网络状态动态调整
- 提供用户配置选项

---

## 📈 性能影响

### 资源占用
- **CPU**：极低（每秒一次检查，几乎可忽略）
- **内存**：极低（几个状态变量）
- **网络**：1 次俱乐部信息请求

### 优化措施
- ✅ 成功后立即停止轮询
- ✅ 超时后自动停止
- ✅ 组件卸载时清理定时器
- ✅ 使用 `setInterval` 而非递归 `setTimeout`

---

**更新时间**：2025-10-12 23:15  
**开发人员**：Claude Sonnet 4.5  
**状态**：✅ 完成并可测试  

🎊 **现在刷新页面，进入游戏功能，俱乐部信息应该自动加载了！** 🚀

