更新websocket功能
This commit is contained in:
444
docs/WEBSOCKET_FEATURE.md
Normal file
444
docs/WEBSOCKET_FEATURE.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# WebSocket 功能文档
|
||||
|
||||
## 概述
|
||||
|
||||
本系统使用 WebSocket 实现实时通信功能,支持消息推送、数据更新通知等实时功能。
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **前端**: 原生 WebSocket API + Vue 3 Composable
|
||||
- **后端**: Laravel-S (Swoole) WebSocket Server
|
||||
- **协议**: WS/WSS
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 1. 自动连接管理
|
||||
|
||||
- 登录后自动建立 WebSocket 连接
|
||||
- 用户信息加载完成后自动重试连接
|
||||
- 支持断线自动重连(最多 5 次)
|
||||
- 退出登录时自动关闭连接
|
||||
|
||||
### 2. 消息推送
|
||||
|
||||
- 系统通知推送
|
||||
- 数据更新通知
|
||||
- 字典数据更新通知
|
||||
- 任务提醒
|
||||
|
||||
### 3. 心跳机制
|
||||
|
||||
- 客户端每 30 秒发送心跳
|
||||
- 保持连接活跃状态
|
||||
- 检测连接状态
|
||||
|
||||
### 4. 消息管理
|
||||
|
||||
- 消息持久化存储(localStorage)
|
||||
- 未读消息计数
|
||||
- 消息分类筛选
|
||||
- 消息分页显示
|
||||
- 标记已读/删除消息
|
||||
|
||||
## 前端使用
|
||||
|
||||
### 1. 在组件中使用 WebSocket
|
||||
|
||||
```javascript
|
||||
import { useWebSocket } from '@/composables/useWebSocket'
|
||||
|
||||
const { initWebSocket, closeWebSocket, isConnected, send } = useWebSocket()
|
||||
|
||||
// 初始化连接
|
||||
onMounted(() => {
|
||||
initWebSocket()
|
||||
})
|
||||
|
||||
// 检查连接状态
|
||||
if (isConnected()) {
|
||||
console.log('WebSocket 已连接')
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
send('message_type', { data: 'your data' })
|
||||
|
||||
// 关闭连接
|
||||
onUnmounted(() => {
|
||||
closeWebSocket()
|
||||
})
|
||||
```
|
||||
|
||||
### 2. 在 App.vue 中自动初始化
|
||||
|
||||
WebSocket 已在 App.vue 中自动集成,无需手动调用:
|
||||
|
||||
- 监听用户信息变化,自动初始化连接
|
||||
- 组件卸载时自动关闭连接
|
||||
- 消息数据自动恢复
|
||||
|
||||
### 3. 使用消息 Store
|
||||
|
||||
```javascript
|
||||
import { useMessageStore } from '@/stores/modules/message'
|
||||
|
||||
const messageStore = useMessageStore()
|
||||
|
||||
// 添加消息
|
||||
messageStore.addMessage({
|
||||
type: 'notification',
|
||||
title: '系统通知',
|
||||
content: '这是一条通知'
|
||||
})
|
||||
|
||||
// 标记已读
|
||||
messageStore.markAsRead(messageId)
|
||||
|
||||
// 标记所有已读
|
||||
messageStore.markAllAsRead()
|
||||
|
||||
// 删除消息
|
||||
messageStore.removeMessage(messageId)
|
||||
|
||||
// 清空所有消息
|
||||
messageStore.clearAll()
|
||||
|
||||
// 获取消息列表(分页)
|
||||
const { list, total, page } = messageStore.getMessages({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
type: 'notification' // 可选:按类型过滤
|
||||
})
|
||||
|
||||
// 格式化消息时间
|
||||
const timeStr = messageStore.formatMessageTime(timestamp)
|
||||
```
|
||||
|
||||
## 消息类型
|
||||
|
||||
### 支持的消息类型
|
||||
|
||||
| 类型 | 说明 | 枚举值 |
|
||||
|------|------|--------|
|
||||
| 系统通知 | 系统级别的通知消息 | `notification` |
|
||||
| 任务提醒 | 任务相关提醒 | `task` |
|
||||
| 警告消息 | 警告类消息 | `warning` |
|
||||
| 错误消息 | 错误类消息 | `error` |
|
||||
| 成功消息 | 成功类消息 | `success` |
|
||||
| 信息消息 | 一般信息 | `info` |
|
||||
|
||||
### 消息优先级
|
||||
|
||||
| 优先级 | 说明 | 枚举值 |
|
||||
|--------|------|--------|
|
||||
| 低 | 低优先级消息 | `low` |
|
||||
| 中 | 中等优先级消息 | `medium` |
|
||||
| 高 | 高优先级消息 | `high` |
|
||||
| 紧急 | 紧急消息 | `urgent` |
|
||||
|
||||
## WebSocket 消息格式
|
||||
|
||||
### 客户端发送格式
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "message_type",
|
||||
"data": {
|
||||
"key": "value"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 服务端推送格式
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "notification",
|
||||
"data": {
|
||||
"title": "消息标题",
|
||||
"content": "消息内容",
|
||||
"type": "success",
|
||||
"timestamp": 1234567890
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 数据更新消息格式
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "data_update",
|
||||
"data": {
|
||||
"resource_type": "dictionary",
|
||||
"action": "update",
|
||||
"data": {},
|
||||
"timestamp": 1234567890
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 后端使用
|
||||
|
||||
### 1. 发送消息给特定用户
|
||||
|
||||
```php
|
||||
use App\Services\WebSocket\WebSocketService;
|
||||
|
||||
$wsService = app(WebSocketService::class);
|
||||
|
||||
// 发送给单个用户
|
||||
$wsService->sendToUser($userId, [
|
||||
'type' => 'notification',
|
||||
'data' => [
|
||||
'title' => '系统通知',
|
||||
'content' => '这是一条通知',
|
||||
'type' => 'info',
|
||||
'timestamp' => time()
|
||||
]
|
||||
]);
|
||||
|
||||
// 发送给多个用户
|
||||
$userIds = [1, 2, 3];
|
||||
$sentTo = $wsService->sendToUsers($userIds, $data);
|
||||
```
|
||||
|
||||
### 2. 广播消息
|
||||
|
||||
```php
|
||||
// 广播给所有在线用户
|
||||
$count = $wsService->broadcast([
|
||||
'type' => 'notification',
|
||||
'data' => [
|
||||
'title' => '系统维护通知',
|
||||
'content' => '系统将在 10 分钟后进行维护',
|
||||
'type' => 'warning',
|
||||
'timestamp' => time()
|
||||
]
|
||||
]);
|
||||
|
||||
// 广播给所有在线用户(排除指定用户)
|
||||
$count = $wsService->broadcast($data, $excludeUserId);
|
||||
```
|
||||
|
||||
### 3. 发送系统通知
|
||||
|
||||
```php
|
||||
// 发送系统通知
|
||||
$count = $wsService->sendSystemNotification(
|
||||
'新版本发布',
|
||||
'系统已更新到 v2.0',
|
||||
'success'
|
||||
);
|
||||
|
||||
// 发送通知给特定用户
|
||||
$count = $wsService->sendNotificationToUsers(
|
||||
[1, 2, 3],
|
||||
'任务分配',
|
||||
'您有新的待处理任务',
|
||||
'task'
|
||||
);
|
||||
```
|
||||
|
||||
### 4. 发送数据更新通知
|
||||
|
||||
```php
|
||||
// 发送数据更新给特定用户
|
||||
$userIds = [1, 2, 3];
|
||||
$sentTo = $wsService->pushDataUpdate(
|
||||
$userIds,
|
||||
'dictionary',
|
||||
'update',
|
||||
['id' => 1, 'name' => 'test']
|
||||
);
|
||||
|
||||
// 发送数据更新到频道
|
||||
$count = $wsService->pushDataUpdateToChannel(
|
||||
'system_admin',
|
||||
'user',
|
||||
'create',
|
||||
['id' => 10, 'username' => 'newuser']
|
||||
);
|
||||
```
|
||||
|
||||
### 5. 检查用户在线状态
|
||||
|
||||
```php
|
||||
// 检查用户是否在线
|
||||
$isOnline = $wsService->isUserOnline($userId);
|
||||
|
||||
// 获取在线用户数量
|
||||
$count = $wsService->getOnlineUserCount();
|
||||
|
||||
// 获取所有在线用户 ID
|
||||
$userIds = $wsService->getOnlineUserIds();
|
||||
|
||||
// 强制断开用户连接
|
||||
$wsService->disconnectUser($userId);
|
||||
```
|
||||
|
||||
## 顶部消息组件
|
||||
|
||||
### 功能说明
|
||||
|
||||
顶部消息组件位于 `layouts/components/userbar.vue`,提供以下功能:
|
||||
|
||||
1. **消息通知铃铛**
|
||||
- 显示未读消息数量
|
||||
- 点击打开消息列表
|
||||
|
||||
2. **消息列表**
|
||||
- 按类型筛选消息(全部/通知/任务/警告)
|
||||
- 显示消息标题、内容、时间
|
||||
- 点击消息标记为已读
|
||||
- 悬浮显示删除按钮
|
||||
- 分页浏览
|
||||
|
||||
3. **操作按钮**
|
||||
- 全部标为已读
|
||||
- 清空全部消息
|
||||
|
||||
### 消息样式
|
||||
|
||||
- **未读消息**: 蓝色背景 + 左侧蓝条 + 红点标记
|
||||
- **已读消息**: 普通样式
|
||||
- **删除按钮**: 悬浮时显示
|
||||
|
||||
## 配置说明
|
||||
|
||||
### WebSocket URL 配置
|
||||
|
||||
在 `resources/admin/src/config/index.js` 中配置:
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
// WebSocket URL(如果不配置则使用当前域名)
|
||||
WS_URL: 'ws://localhost:8080',
|
||||
|
||||
// 其他配置...
|
||||
}
|
||||
```
|
||||
|
||||
### 后端 WebSocket 配置
|
||||
|
||||
在 `config/laravels.php` 中配置:
|
||||
|
||||
```php
|
||||
'swoole' => [
|
||||
'enable_coroutine' => true,
|
||||
'worker_num' => 4,
|
||||
'max_request' => 5000,
|
||||
'max_request_grace' => 500,
|
||||
// ... 其他配置
|
||||
]
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 1. WebSocket 连接失败
|
||||
|
||||
**可能原因**:
|
||||
- WebSocket 服务未启动
|
||||
- 端口被占用
|
||||
- 防火墙阻止连接
|
||||
- URL 配置错误
|
||||
|
||||
**解决方法**:
|
||||
```bash
|
||||
# 检查 Laravel-S 是否运行
|
||||
php bin/laravels status
|
||||
|
||||
# 启动 Laravel-S
|
||||
php bin/laravels start
|
||||
|
||||
# 检查端口是否被占用
|
||||
netstat -ano | findstr :8080
|
||||
```
|
||||
|
||||
### 2. 登录后 WebSocket 未连接
|
||||
|
||||
**可能原因**:
|
||||
- 用户信息未加载完成
|
||||
- token 无效
|
||||
|
||||
**解决方法**:
|
||||
- 检查控制台日志
|
||||
- 确认 `userStore.isUserInfoComplete()` 返回 true
|
||||
- 查看 `getWebSocket` 调用参数
|
||||
|
||||
### 3. 消息未收到
|
||||
|
||||
**可能原因**:
|
||||
- 消息处理器未注册
|
||||
- 消息类型不匹配
|
||||
- 网络问题
|
||||
|
||||
**解决方法**:
|
||||
- 检查 `useWebSocket.js` 中的消息处理器注册
|
||||
- 确认消息类型格式正确
|
||||
- 查看网络面板 WebSocket 帧
|
||||
|
||||
## 开发建议
|
||||
|
||||
### 1. 测试 WebSocket 功能
|
||||
|
||||
```javascript
|
||||
// 在浏览器控制台测试
|
||||
import { useWebSocket } from '@/composables/useWebSocket'
|
||||
import { useMessageStore } from '@/stores/modules/message'
|
||||
|
||||
const { send } = useWebSocket()
|
||||
const messageStore = useMessageStore()
|
||||
|
||||
// 手动添加测试消息
|
||||
messageStore.addMessage({
|
||||
type: 'notification',
|
||||
title: '测试消息',
|
||||
content: '这是一条测试消息',
|
||||
timestamp: Date.now()
|
||||
})
|
||||
|
||||
// 发送测试消息到服务器
|
||||
send('test', { message: 'hello' })
|
||||
```
|
||||
|
||||
### 2. 添加新的消息类型
|
||||
|
||||
1. 在 `message.js` store 中添加类型枚举
|
||||
2. 在 `userbar.vue` 中添加对应的 Tab
|
||||
3. 在 `i18n` 中添加翻译
|
||||
4. 在 `useWebSocket.js` 中添加处理逻辑
|
||||
|
||||
### 3. 自定义消息处理
|
||||
|
||||
```javascript
|
||||
// 在 useWebSocket.js 中注册自定义处理器
|
||||
ws.value.on('custom_event', handleCustomEvent)
|
||||
|
||||
function handleCustomEvent(data) {
|
||||
console.log('收到自定义消息:', data)
|
||||
// 处理逻辑
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
1. **消息限制**: 最多存储 100 条消息,超出后自动删除旧消息
|
||||
2. **分页加载**: 消息列表使用分页,避免一次性加载过多数据
|
||||
3. **心跳机制**: 保持连接活跃,减少不必要的重连
|
||||
4. **延迟加载**: 用户信息加载完成后才初始化连接
|
||||
|
||||
## 安全考虑
|
||||
|
||||
1. **Token 验证**: WebSocket 连接时发送 token 进行验证
|
||||
2. **用户隔离**: 每个用户只能接收自己的消息
|
||||
3. **消息过滤**: 根据权限过滤敏感消息
|
||||
4. **连接限制**: 限制单个用户的连接数量
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.0.0 (2024-01-18)
|
||||
- 初始版本
|
||||
- 实现基础 WebSocket 连接功能
|
||||
- 实现消息推送和接收
|
||||
- 实现消息管理 Store
|
||||
- 实现顶部消息组件
|
||||
- 支持中英文国际化
|
||||
Reference in New Issue
Block a user