# 前端多设备登录处理方案

## 📋 后端机制概述

根据后端实现，采用 **"后登录踢掉先登录"** 的策略：
- 每次登录生成新的 UUID token 并存储到 Redis
- 新 token 会覆盖旧 token
- 每次请求验证时对比 Session token 和 Redis token
- 如果不一致，后端返回错误：`"账号在其他设备登录，当前会话已失效"`

---

## 🎯 前端处理方案

### 1. **API 响应拦截器处理** ✅

已在 `src/api/index.js` 中实现：

```javascript
// 防止重复提示的标志
let isKickedOut = false

// 响应拦截器
api.interceptors.response.use(
  response => {
    const data = response.data
    
    if (data && data.success === false) {
      const message = data.message || ''
      
      // 🔍 专门检测"其他设备登录"的情况
      if (message.includes('其他设备登录') || message.includes('当前会话已失效')) {
        if (!isKickedOut) {
          isKickedOut = true
          
          // 📢 显示友好提示
          ElMessage.warning({
            message: '您的账号已在其他设备登录，请重新登录',
            duration: 3000,
            showClose: true
          })
          
          // 🚪 清除状态并跳转
          if (window.location.pathname.startsWith('/cpzsadmin')) {
            // 后台管理
            userStore.adminLogout()
            setTimeout(() => {
              window.location.href = '/cpzsadmin/login'
              isKickedOut = false
            }, 1500)
          } else {
            // 前台用户
            userStore.logout()
            setTimeout(() => {
              isKickedOut = false
            }, 3000)
          }
        }
      }
    }
    return data
  }
)
```

### 2. **关键处理要点**

#### ✅ 错误检测
```javascript
// 匹配后端返回的错误消息
if (message.includes('其他设备登录') || message.includes('当前会话已失效')) {
  // 处理被踢出逻辑
}
```

#### ✅ 防止重复提示
```javascript
let isKickedOut = false  // 全局标志位

if (!isKickedOut) {
  isKickedOut = true
  // 显示提示
  
  // 延时后重置标志
  setTimeout(() => {
    isKickedOut = false
  }, 3000)
}
```

#### ✅ 友好提示
```javascript
ElMessage.warning({
  message: '您的账号已在其他设备登录，请重新登录',
  duration: 3000,
  showClose: true
})
```

#### ✅ 清除状态
```javascript
// 清除 localStorage/sessionStorage 中的用户信息
userStore.logout()  // 或 userStore.adminLogout()
```

#### ✅ 自动跳转
```javascript
// 延时跳转，让用户看到提示信息
setTimeout(() => {
  window.location.href = '/cpzsadmin/login'  // 或前台登录页
}, 1500)
```

---

## 🔄 完整流程

```
用户A在设备1登录
  ├─ ✅ 正常使用
  │
用户A在设备2登录
  ├─ 🔄 后端生成新token，覆盖Redis
  │
设备1发起请求
  ├─ 🔍 后端验证：Session token ≠ Redis token
  ├─ ❌ 返回错误："账号在其他设备登录，当前会话已失效"
  │
前端响应拦截器捕获
  ├─ 📢 显示提示："您的账号已在其他设备登录"
  ├─ 🗑️ 清除本地登录状态
  ├─ 🚪 跳转到登录页
  └─ ✅ 用户重新登录
```

---

## 🛡️ 安全性保障

### 1. **即时生效**
- 新登录立即使旧会话失效
- 无需等待定时任务或轮询

### 2. **状态同步**
- Redis 作为唯一的真实状态源
- 前端 Session 只是临时凭证

### 3. **自动清理**
- Token 24小时自动过期
- Session 失效自动清除

### 4. **用户体验**
- 明确的提示信息
- 自动跳转登录页
- 防止重复弹窗

---

## 📝 测试场景

### 测试步骤：
1. ✅ 在设备A（浏览器1）登录账号
2. ✅ 在设备B（浏览器2）用同一账号登录
3. ✅ 在设备A刷新页面或发起任何API请求
4. ✅ 验证：
   - 是否显示"账号在其他设备登录"提示
   - 是否自动清除登录状态
   - 是否自动跳转到登录页
   - 是否只提示一次（不重复弹窗）

---

## 🎨 优化建议

### 1. **更友好的提示**
可以在提示中添加更多信息：
```javascript
ElMessage.warning({
  message: '您的账号于 [时间] 在 [设备/IP] 登录，当前会话已失效',
  duration: 5000,
  showClose: true
})
```

### 2. **弹窗确认**
对于重要操作，可以使用弹窗代替消息提示：
```javascript
ElMessageBox.alert(
  '您的账号已在其他设备登录，为保障账号安全，请重新登录',
  '账号安全提醒',
  {
    confirmButtonText: '重新登录',
    type: 'warning',
    callback: () => {
      // 跳转登录页
    }
  }
)
```

### 3. **记录日志**
在前端记录被踢出的日志，便于问题排查：
```javascript
console.warn('[安全] 检测到账号在其他设备登录', {
  time: new Date().toISOString(),
  path: window.location.pathname,
  userId: currentUser.id
})
```

---

## 🔧 相关文件

- `src/api/index.js` - API 拦截器配置
- `src/store/user.js` - 用户状态管理
- `src/router/index.js` - 路由守卫（可选增强）

---

## ✅ 实现完成

前端已完整实现多设备登录的处理机制，确保：
- ✅ 准确捕获被踢出的情况
- ✅ 友好的用户提示
- ✅ 自动清除状态
- ✅ 防止重复提示
- ✅ 自动跳转登录页
