# Bug 修复 v4 - 刷新后后端停止问题

## 修复的问题

### 刷新后后端直接停止，不继续执行
**原因**:
1. 页面刷新时 WebSocket 断开
2. `handle_disconnect` 检测到断开且没有其他连接
3. 设置 `stop_flags[f"user:{username}"]` 为 `True`
4. 任务检查停止标志时，会查找 `stop_flags[task_id]` 和 `stop_flags[f"user:{username}"]`
5. 发现用户级别的停止标志，任务停止执行

**解决方案**:
在 `handle_disconnect` 中检查是否有通过 REST API 创建的运行中任务。如果有，说明使用轮询模式，不应该停止任务。

## 修改的文件

### server/socket_handlers.py

**修改前**:
```python
@socketio.on('disconnect')
def handle_disconnect():
    username = connection_users.pop(request.sid, None)
    has_other_connection = False
    if username:
        for sid, user in connection_users.items():
            if user == username:
                has_other_connection = True
                break

    task_info = get_stop_flag(request.sid, username)
    if isinstance(task_info, dict) and not has_other_connection:
        task_info['stop'] = True  # 设置停止标志
        # ... 取消任务

    clear_stop_flag(request.sid, None)  # 清理所有停止标志
```

**修改后**:
```python
@socketio.on('disconnect')
def handle_disconnect():
    username = connection_users.pop(request.sid, None)
    has_other_connection = False
    if username:
        for sid, user in connection_users.items():
            if user == username:
                has_other_connection = True
                break

    # 检查是否有通过 REST API 创建的运行中任务
    has_rest_api_task = False
    if username and not has_other_connection:
        try:
            from .tasks import task_manager
            running_tasks = [t for t in task_manager.list_tasks(username) if t.status == "running"]
            if running_tasks:
                has_rest_api_task = True
                debug_log(f"[WebSocket] 用户 {username} 有运行中的 REST API 任务，不停止")
        except Exception as e:
            debug_log(f"[WebSocket] 检查 REST API 任务失败: {e}")

    task_info = get_stop_flag(request.sid, username)
    # 只有在没有其他连接且没有 REST API 任务时才停止
    if isinstance(task_info, dict) and not has_other_connection and not has_rest_api_task:
        task_info['stop'] = True
        # ... 取消任务

    # 清理停止标志（只清理 sid 级别的，不清理 user 级别的）
    if request.sid in stop_flags:
        stop_flags.pop(request.sid, None)
```

## 工作流程

### 停止标志机制

**stop_flags 结构**:
```python
stop_flags = {
    "client_sid": {"stop": bool, "task": asyncio.Task, "terminal": WebTerminal},
    "user:{username}": {"stop": bool, "task": asyncio.Task, "terminal": WebTerminal},
    "task_id": {"stop": bool, "task": None, "terminal": None}
}
```

**查找顺序**:
1. 先查找 `stop_flags[client_sid]`（WebSocket sid 或 task_id）
2. 再查找 `stop_flags[f"user:{username}"]`（用户级别）

### WebSocket 断开流程（修复后）

1. **检测断开**
   - 移除 `connection_users[sid]`
   - 检查是否有其他连接

2. **检查 REST API 任务**
   - 查询 `task_manager.list_tasks(username)`
   - 检查是否有 `status == "running"` 的任务
   - 如果有，设置 `has_rest_api_task = True`

3. **决定是否停止**
   - 如果有其他连接 → 不停止
   - 如果有 REST API 任务 → 不停止
   - 否则 → 停止任务

4. **清理停止标志**
   - 只清理 `stop_flags[sid]`（sid 级别）
   - 不清理 `stop_flags[f"user:{username}"]`（用户级别）
   - 避免影响 REST API 任务

### 页面刷新流程（修复后）

1. **WebSocket 断开**
   - 检测到有运行中的 REST API 任务
   - 不设置停止标志
   - 任务继续执行

2. **页面重新加载**
   - 加载历史记录
   - 恢复任务状态
   - 启动轮询

3. **任务继续执行**
   - 后端任务不受影响
   - 继续生成事件
   - 前端轮询获取新事件

## 关键改进

### 1. 检测 REST API 任务
- 在 WebSocket 断开时检查是否有运行中的 REST API 任务
- 如果有，说明使用轮询模式，不应该停止

### 2. 保护 REST API 任务
- 只有在没有其他连接且没有 REST API 任务时才停止
- 避免 WebSocket 断开影响 REST API 任务

### 3. 精确清理停止标志
- 只清理 sid 级别的停止标志
- 不清理用户级别的停止标志
- 避免误清理 REST API 任务的停止标志

## 测试场景

### 1. 正常发送消息
- 发送消息
- 观察任务是否正常执行
- 观察输出是否正常

### 2. 刷新页面（任务进行中）
- 任务执行中刷新页面
- **观察后端是否继续执行**
- 观察前端是否正常恢复
- 观察新内容是否正常追加

### 3. 多次刷新
- 任务执行中多次刷新
- 观察每次刷新后任务是否继续
- 观察是否有累积的问题

### 4. 停止任务
- 点击停止按钮
- 观察任务是否立即停止
- 观察前端状态是否正确

## 构建

```bash
cd static
npm run build
```

构建成功！

## 最终效果

- ✅ 刷新后后端继续执行
- ✅ 前端正常恢复状态
- ✅ 新内容正常追加
- ✅ 工具块正确显示
- ✅ 流畅的输出效果（150ms 轮询）
- ✅ 不重复显示内容

现在可以测试了！刷新页面后，后端应该继续执行，前端会正常恢复并显示新内容。
