更新
This commit is contained in:
@@ -1,684 +0,0 @@
|
||||
# WebSocket 功能文档
|
||||
|
||||
## 概述
|
||||
|
||||
本项目基于 Laravel-S 和 Swoole 实现了完整的 WebSocket 功能,支持实时通信、消息推送、广播等功能。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- ✅ 实时双向通信
|
||||
- ✅ 用户连接管理
|
||||
- ✅ 点对点消息发送
|
||||
- ✅ 群发消息/广播
|
||||
- ✅ 频道订阅/取消订阅
|
||||
- ✅ 心跳机制
|
||||
- ✅ 自动重连
|
||||
- ✅ 在线状态管理
|
||||
- ✅ 系统通知推送
|
||||
- ✅ 数据更新推送
|
||||
|
||||
## 架构设计
|
||||
|
||||
### 后端组件
|
||||
|
||||
#### 1. WebSocketHandler (`app/Services/WebSocket/WebSocketHandler.php`)
|
||||
|
||||
WebSocket 处理器,实现了 Swoole 的 `WebSocketHandlerInterface` 接口。
|
||||
|
||||
**主要方法:**
|
||||
- `onOpen()`: 处理连接建立事件
|
||||
- `onMessage()`: 处理消息接收事件
|
||||
- `onClose()`: 处理连接关闭事件
|
||||
|
||||
**支持的消息类型:**
|
||||
- `ping/pong`: 心跳检测
|
||||
- `heartbeat`: 心跳确认
|
||||
- `chat`: 私聊消息
|
||||
- `broadcast`: 广播消息
|
||||
- `subscribe/unsubscribe`: 频道订阅/取消订阅
|
||||
|
||||
#### 2. WebSocketService (`app/Services/WebSocket/WebSocketService.php`)
|
||||
|
||||
WebSocket 服务类,提供便捷的 WebSocket 操作方法。
|
||||
|
||||
**主要方法:**
|
||||
- `sendToUser($userId, $data)`: 发送消息给指定用户
|
||||
- `sendToUsers($userIds, $data)`: 发送消息给多个用户
|
||||
- `broadcast($data, $excludeUserId)`: 广播消息给所有用户
|
||||
- `sendToChannel($channel, $data)`: 发送消息给指定频道
|
||||
- `getOnlineUserCount()`: 获取在线用户数
|
||||
- `isUserOnline($userId)`: 检查用户是否在线
|
||||
- `sendSystemNotification()`: 发送系统通知
|
||||
- `pushDataUpdate()`: 推送数据更新
|
||||
|
||||
#### 3. WebSocketController (`app/Http/Controllers/System/WebSocket.php`)
|
||||
|
||||
WebSocket API 控制器,提供 HTTP 接口用于管理 WebSocket 连接。
|
||||
|
||||
### 前端组件
|
||||
|
||||
#### WebSocketClient (`resources/admin/src/utils/websocket.js`)
|
||||
|
||||
WebSocket 客户端封装类。
|
||||
|
||||
**功能:**
|
||||
- 自动连接和重连
|
||||
- 心跳机制
|
||||
- 消息类型路由
|
||||
- 事件监听
|
||||
- 连接状态管理
|
||||
|
||||
## 配置说明
|
||||
|
||||
### Laravel-S 配置 (`config/laravels.php`)
|
||||
|
||||
```php
|
||||
'websocket' => [
|
||||
'enable' => env('LARAVELS_WEBSOCKET', true),
|
||||
'handler' => \App\Services\WebSocket\WebSocketHandler::class,
|
||||
],
|
||||
|
||||
'swoole_tables' => [
|
||||
'wsTable' => [
|
||||
'size' => 102400,
|
||||
'column' => [
|
||||
['name' => 'value', 'type' => \Swoole\Table::TYPE_STRING, 'size' => 1024],
|
||||
['name' => 'expiry', 'type' => \Swoole\Table::TYPE_INT, 'size' => 4],
|
||||
],
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
### 环境变量
|
||||
|
||||
在 `.env` 文件中添加:
|
||||
|
||||
```env
|
||||
LARAVELS_WEBSOCKET=true
|
||||
```
|
||||
|
||||
## API 接口
|
||||
|
||||
### 1. 获取在线用户数
|
||||
|
||||
```
|
||||
GET /admin/websocket/online-count
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"online_count": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 获取在线用户列表
|
||||
|
||||
```
|
||||
GET /admin/websocket/online-users
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"user_ids": [1, 2, 3, 4, 5],
|
||||
"count": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 检查用户在线状态
|
||||
|
||||
```
|
||||
POST /admin/websocket/check-online
|
||||
```
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"user_id": 1
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"user_id": 1,
|
||||
"is_online": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 发送消息给指定用户
|
||||
|
||||
```
|
||||
POST /admin/websocket/send-to-user
|
||||
```
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"user_id": 1,
|
||||
"type": "notification",
|
||||
"data": {
|
||||
"title": "新消息",
|
||||
"message": "您有一条新消息"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 发送消息给多个用户
|
||||
|
||||
```
|
||||
POST /admin/websocket/send-to-users
|
||||
```
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"user_ids": [1, 2, 3],
|
||||
"type": "notification",
|
||||
"data": {
|
||||
"title": "系统通知",
|
||||
"message": "系统将在今晚进行维护"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 广播消息
|
||||
|
||||
```
|
||||
POST /admin/websocket/broadcast
|
||||
```
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"type": "notification",
|
||||
"data": {
|
||||
"title": "公告",
|
||||
"message": "欢迎使用新版本"
|
||||
},
|
||||
"exclude_user_id": 1 // 可选:排除某个用户
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 发送消息到频道
|
||||
|
||||
```
|
||||
POST /admin/websocket/send-to-channel
|
||||
```
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"channel": "orders",
|
||||
"type": "data_update",
|
||||
"data": {
|
||||
"order_id": 123,
|
||||
"status": "paid"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8. 发送系统通知
|
||||
|
||||
```
|
||||
POST /admin/websocket/send-notification
|
||||
```
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"title": "系统维护",
|
||||
"message": "系统将于今晚 23:00-24:00 进行维护",
|
||||
"type": "warning",
|
||||
"extra_data": {
|
||||
"start_time": "23:00",
|
||||
"end_time": "24:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 9. 发送通知给指定用户
|
||||
|
||||
```
|
||||
POST /admin/websocket/send-notification-to-users
|
||||
```
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"user_ids": [1, 2, 3],
|
||||
"title": "订单更新",
|
||||
"message": "您的订单已发货",
|
||||
"type": "success"
|
||||
}
|
||||
```
|
||||
|
||||
### 10. 推送数据更新
|
||||
|
||||
```
|
||||
POST /admin/websocket/push-data-update
|
||||
```
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"user_ids": [1, 2, 3],
|
||||
"resource_type": "order",
|
||||
"action": "update",
|
||||
"data": {
|
||||
"id": 123,
|
||||
"status": "shipped"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 11. 推送数据更新到频道
|
||||
|
||||
```
|
||||
POST /admin/websocket/push-data-update-channel
|
||||
```
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"channel": "orders",
|
||||
"resource_type": "order",
|
||||
"action": "create",
|
||||
"data": {
|
||||
"id": 124,
|
||||
"customer": "张三",
|
||||
"amount": 100.00
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 12. 断开用户连接
|
||||
|
||||
```
|
||||
POST /admin/websocket/disconnect-user
|
||||
```
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"user_id": 1
|
||||
}
|
||||
```
|
||||
|
||||
## 前端使用示例
|
||||
|
||||
### 1. 基本连接
|
||||
|
||||
```javascript
|
||||
import { getWebSocket, closeWebSocket } from '@/utils/websocket'
|
||||
import { useUserStore } from '@/stores/modules/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 连接 WebSocket
|
||||
const ws = getWebSocket(userStore.userInfo.id, userStore.token, {
|
||||
onOpen: (event) => {
|
||||
console.log('WebSocket 已连接')
|
||||
},
|
||||
onMessage: (message) => {
|
||||
console.log('收到消息:', message)
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('WebSocket 错误:', error)
|
||||
},
|
||||
onClose: (event) => {
|
||||
console.log('WebSocket 已关闭')
|
||||
}
|
||||
})
|
||||
|
||||
// 连接
|
||||
ws.connect()
|
||||
```
|
||||
|
||||
### 2. 监听特定消息类型
|
||||
|
||||
```javascript
|
||||
// 监听通知消息
|
||||
ws.on('notification', (data) => {
|
||||
message.success(data.title, data.message)
|
||||
})
|
||||
|
||||
// 监听数据更新
|
||||
ws.on('data_update', (data) => {
|
||||
console.log('数据更新:', data.resource_type, data.action)
|
||||
// 刷新数据
|
||||
loadData()
|
||||
})
|
||||
```
|
||||
|
||||
### 3. 发送消息
|
||||
|
||||
```javascript
|
||||
// 发送心跳
|
||||
ws.send('heartbeat', { timestamp: Date.now() })
|
||||
|
||||
// 发送私聊消息
|
||||
ws.send('chat', {
|
||||
to_user_id: 2,
|
||||
content: '你好,这是一条私聊消息'
|
||||
})
|
||||
|
||||
// 订阅频道
|
||||
ws.send('subscribe', { channel: 'orders' })
|
||||
|
||||
// 取消订阅
|
||||
ws.send('unsubscribe', { channel: 'orders' })
|
||||
```
|
||||
|
||||
### 4. 发送广播消息
|
||||
|
||||
```javascript
|
||||
ws.send('broadcast', {
|
||||
message: '这是一条广播消息'
|
||||
})
|
||||
```
|
||||
|
||||
### 5. 断开连接
|
||||
|
||||
```javascript
|
||||
// 断开连接
|
||||
ws.disconnect()
|
||||
|
||||
// 或使用全局方法
|
||||
closeWebSocket()
|
||||
```
|
||||
|
||||
### 6. 在 Vue 组件中使用
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<a-button @click="connectWebSocket">连接 WebSocket</a-button>
|
||||
<a-button @click="disconnectWebSocket">断开连接</a-button>
|
||||
<a-button @click="sendMessage">发送消息</a-button>
|
||||
<div>连接状态: {{ connectionStatus }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { getWebSocket } from '@/utils/websocket'
|
||||
import { useUserStore } from '@/stores/modules/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const ws = ref(null)
|
||||
const connectionStatus = ref('未连接')
|
||||
|
||||
const connectWebSocket = () => {
|
||||
ws.value = getWebSocket(userStore.userInfo.id, userStore.token, {
|
||||
onOpen: () => {
|
||||
connectionStatus.value = '已连接'
|
||||
},
|
||||
onMessage: (message) => {
|
||||
handleMessage(message)
|
||||
},
|
||||
onClose: () => {
|
||||
connectionStatus.value = '已断开'
|
||||
}
|
||||
})
|
||||
|
||||
ws.value.connect()
|
||||
}
|
||||
|
||||
const disconnectWebSocket = () => {
|
||||
if (ws.value) {
|
||||
ws.value.disconnect()
|
||||
connectionStatus.value = '已断开'
|
||||
}
|
||||
}
|
||||
|
||||
const sendMessage = () => {
|
||||
if (ws.value && ws.value.isConnected) {
|
||||
ws.value.send('chat', {
|
||||
to_user_id: 2,
|
||||
content: '测试消息'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleMessage = (message) => {
|
||||
switch (message.type) {
|
||||
case 'notification':
|
||||
message.success(message.data.title, message.data.message)
|
||||
break
|
||||
case 'data_update':
|
||||
// 处理数据更新
|
||||
break
|
||||
case 'chat':
|
||||
// 处理聊天消息
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
connectWebSocket()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
disconnectWebSocket()
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## 消息格式
|
||||
|
||||
### 服务端发送的消息格式
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "notification",
|
||||
"data": {
|
||||
"title": "标题",
|
||||
"message": "内容",
|
||||
"type": "info",
|
||||
"timestamp": 1641234567
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 客户端发送的消息格式
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "chat",
|
||||
"data": {
|
||||
"to_user_id": 2,
|
||||
"content": "消息内容"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 启动和停止
|
||||
|
||||
### 启动 Laravel-S 服务
|
||||
|
||||
```bash
|
||||
php bin/laravels start
|
||||
```
|
||||
|
||||
### 停止 Laravel-S 服务
|
||||
|
||||
```bash
|
||||
php bin/laravels stop
|
||||
```
|
||||
|
||||
### 重启 Laravel-S 服务
|
||||
|
||||
```bash
|
||||
php bin/laravels restart
|
||||
```
|
||||
|
||||
### 重载 Laravel-S 服务(平滑重启)
|
||||
|
||||
```bash
|
||||
php bin/laravels reload
|
||||
```
|
||||
|
||||
### 查看服务状态
|
||||
|
||||
```bash
|
||||
php bin/laravels status
|
||||
```
|
||||
|
||||
## WebSocket 连接地址
|
||||
|
||||
### 开发环境
|
||||
|
||||
```
|
||||
ws://localhost:5200/ws?user_id={user_id}&token={token}
|
||||
```
|
||||
|
||||
### 生产环境
|
||||
|
||||
```
|
||||
wss://yourdomain.com/ws?user_id={user_id}&token={token}
|
||||
```
|
||||
|
||||
## Nginx 配置示例
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name yourdomain.com;
|
||||
root /path/to/your/project/public;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# WebSocket 代理配置
|
||||
location /ws {
|
||||
proxy_pass http://127.0.0.1:5200;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 使用场景
|
||||
|
||||
### 1. 实时通知
|
||||
|
||||
```php
|
||||
// 发送系统通知
|
||||
$webSocketService->sendSystemNotification(
|
||||
'系统维护',
|
||||
'系统将于今晚进行维护',
|
||||
'warning'
|
||||
);
|
||||
```
|
||||
|
||||
### 2. 订单状态更新
|
||||
|
||||
```php
|
||||
// 推送订单状态更新给相关人员
|
||||
$webSocketService->pushDataUpdate(
|
||||
[$order->user_id],
|
||||
'order',
|
||||
'update',
|
||||
[
|
||||
'id' => $order->id,
|
||||
'status' => $order->status,
|
||||
'updated_at' => $order->updated_at
|
||||
]
|
||||
);
|
||||
```
|
||||
|
||||
### 3. 实时聊天
|
||||
|
||||
```javascript
|
||||
// 发送私聊消息
|
||||
ws.send('chat', {
|
||||
to_user_id: 2,
|
||||
content: '你好'
|
||||
})
|
||||
```
|
||||
|
||||
### 4. 数据监控
|
||||
|
||||
```php
|
||||
// 推送系统监控数据到特定频道
|
||||
$webSocketService->sendToChannel('system_monitor', 'monitor', [
|
||||
'cpu_usage' => 75,
|
||||
'memory_usage' => 80,
|
||||
'disk_usage' => 60
|
||||
]);
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **连接认证**: WebSocket 连接时需要提供 `user_id` 和 `token` 参数
|
||||
2. **心跳机制**: 客户端默认每 30 秒发送一次心跳
|
||||
3. **自动重连**: 连接断开后会自动尝试重连,最多重试 5 次
|
||||
4. **并发限制**: Swoole Table 最多支持 102,400 个连接
|
||||
5. **内存管理**: 注意内存泄漏问题,定期重启服务
|
||||
6. **安全性**: 生产环境建议使用 WSS (WebSocket Secure)
|
||||
7. **日志监控**: 查看日志文件 `storage/logs/swoole-YYYY-MM.log`
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 1. 无法连接 WebSocket
|
||||
|
||||
- 检查 Laravel-S 服务是否启动
|
||||
- 检查端口 5200 是否被占用
|
||||
- 检查防火墙设置
|
||||
- 查看日志文件
|
||||
|
||||
### 2. 连接频繁断开
|
||||
|
||||
- 检查网络稳定性
|
||||
- 调整心跳间隔
|
||||
- 检查服务器资源使用情况
|
||||
|
||||
### 3. 消息发送失败
|
||||
|
||||
- 检查用户是否在线
|
||||
- 检查消息格式是否正确
|
||||
- 查看错误日志
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [Laravel-S 文档](https://github.com/hhxsv5/laravel-s)
|
||||
- [Swoole 文档](https://www.swoole.com/)
|
||||
- [WebSocket API](https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket)
|
||||
|
||||
## 更新日志
|
||||
|
||||
### 2024-02-08
|
||||
|
||||
- ✅ 初始版本发布
|
||||
- ✅ 实现基础 WebSocket 功能
|
||||
- ✅ 实现消息推送功能
|
||||
- ✅ 实现频道订阅功能
|
||||
- ✅ 实现前端客户端封装
|
||||
- ✅ 实现管理 API 接口
|
||||
2207
docs/README_WEBSOCKET_NOTIFICATION.md
Normal file
2207
docs/README_WEBSOCKET_NOTIFICATION.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,444 +0,0 @@
|
||||
# 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