diff --git a/app/command/admin/SysGateway.php b/app/command/admin/SysGateway.php
index 34dc311..6397190 100644
--- a/app/command/admin/SysGateway.php
+++ b/app/command/admin/SysGateway.php
@@ -2,7 +2,7 @@
namespace app\command\admin;
-use app\event\AdminGatewayEvents;
+use app\event\SysGatewayEvent;
use GatewayWorker\Register;
use think\console\Command;
use think\console\Input;
@@ -52,7 +52,7 @@ class SysGateway extends Command
$worker->name = 'AdminBusinessWorker';
$worker->count = 4;
$worker->registerAddress = '127.0.0.1:1236';
- $worker->eventHandler = AdminGatewayEvents::class;
+ $worker->eventHandler = SysGatewayEvent::class;
// 运行所有服务
Worker::runAll();
diff --git a/app/entity/gateway/el/ElNotification.php b/app/entity/gateway/el/ElNotification.php
new file mode 100644
index 0000000..779e970
--- /dev/null
+++ b/app/entity/gateway/el/ElNotification.php
@@ -0,0 +1,45 @@
+title = $title;
+ $this->message = $message;
+ $this->dangerouslyUseHTMLString = $dangerouslyUseHTMLString;
+ $this->type = $type;
+ $this->icon = $icon;
+ $this->duration = $duration;
+ $this->position = $position;
+ if (!empty($_attr)) {
+ foreach ($_attr as $key => $value) {
+ $this->$key = $value;
+ }
+ }
+ }
+
+ public function toArray(): array
+ {
+ return get_object_vars($this);
+ }
+}
\ No newline at end of file
diff --git a/app/entity/gateway/ws/OutMessage.php b/app/entity/gateway/ws/OutMessage.php
new file mode 100644
index 0000000..26b2849
--- /dev/null
+++ b/app/entity/gateway/ws/OutMessage.php
@@ -0,0 +1,35 @@
+type = $type->value;
+ $this->event = $event->value;
+
+ if($data instanceof ElNotification) {
+ $this->data = $data->toArray();
+ }else{
+ $this->data = (array)$data;
+ }
+ }
+
+ public function toJson(): string
+ {
+ return json_encode([
+ 'type' => $this->type,
+ 'event' => $this->event,
+ 'data' => $this->data,
+ ], JSON_UNESCAPED_UNICODE);
+ }
+}
\ No newline at end of file
diff --git a/app/entity/gateway/ws/PutMessage.php b/app/entity/gateway/ws/PutMessage.php
new file mode 100644
index 0000000..c9daf3c
--- /dev/null
+++ b/app/entity/gateway/ws/PutMessage.php
@@ -0,0 +1,59 @@
+wsClientId = $ws_client_id;
+ $this->type = WsTypeEnum::from($type);
+ $this->event = WsEventEnum::from($event);
+ $this->data = $data;
+ }
+
+ public function get($name, $default = null)
+ {
+ return $this->data[$name] ?? $default;
+ }
+
+ public function login(int $user_id, string $user_type, array $user_client = []): bool
+ {
+ if (empty($user_id) || empty($user_type) || count($user_client) == 0) {
+ return false;
+ }
+ $this->userId = $user_id;
+ $this->userType = $user_type;
+ $this->userClient = $user_client;
+
+ return true;
+ }
+ public function getClientId(): string
+ {
+ return $this->userClient['id'] ?? '';
+ }
+ public function getClientName()
+ {
+ return $this->userClient['name'] ?? '';
+ }
+
+ public function getClientVersion()
+ {
+ return $this->userClient['version'] ?? '';
+ }
+}
\ No newline at end of file
diff --git a/app/enum/gateway/WsEventEnum.php b/app/enum/gateway/WsEventEnum.php
new file mode 100644
index 0000000..e6627e8
--- /dev/null
+++ b/app/enum/gateway/WsEventEnum.php
@@ -0,0 +1,17 @@
+ [
- 'sysUser' => SysUserSubscribe::class
+ 'sysUser' => SysUserSubscribe::class,
+ /*
+ * 网关事件订阅类
+ */
+ 'gateway' => GatewaySubscribe::class,
],
];
diff --git a/app/event/AdminGatewayEvents.php b/app/event/AdminGatewayEvents.php
deleted file mode 100644
index a22d86d..0000000
--- a/app/event/AdminGatewayEvents.php
+++ /dev/null
@@ -1,122 +0,0 @@
- '',
- 'event'=> '',
- ], $message_data);
-
-
- // 根据类型执行不同的业务
- switch ($message_data['type']) {
- // 客户端回应服务端的心跳
- case 'pong':
- return;
- case 'system':
- switch ($message_data['event']) {
- // 客户端登录 message格式: {type:login, name:xx, room_id:1} ,添加到客户端,广播给所有客户端xx进入聊天室
- case 'login':
- // 判断是否有房间号
- if (!isset($message_data['room_id'])) {
- throw new \Exception("\$message_data['room_id'] not set. client_ip:{$_SERVER['REMOTE_ADDR']} \$message:$message");
- }
-
- // 把房间号昵称放到session中
- $room_id = $message_data['room_id'];
- $client_name = htmlspecialchars($message_data['client_name']);
- $_SESSION['room_id'] = $room_id;
- $_SESSION['client_name'] = $client_name;
-
- // 获取房间内所有用户列表
- $clients_list = Gateway::getClientSessionsByGroup($room_id);
- foreach ($clients_list as $tmp_client_id => $item) {
- $clients_list[$tmp_client_id] = $item['client_name'];
- }
- $clients_list[$client_id] = $client_name;
-
- // 转播给当前房间的所有客户端,xx进入聊天室 message {type:login, client_id:xx, name:xx}
- $new_message = array('type' => $message_data['type'], 'client_id' => $client_id, 'client_name' => htmlspecialchars($client_name), 'time' => date('Y-m-d H:i:s'));
- Gateway::sendToGroup($room_id, json_encode($new_message));
- Gateway::joinGroup($client_id, $room_id);
-
- // 给当前用户发送用户列表
- $new_message['client_list'] = $clients_list;
- Gateway::sendToCurrentClient(json_encode($new_message));
- return;
-
- // 客户端发言 message: {type:say, to_client_id:xx, content:xx}
- case 'say':
- // 非法请求
- if (!isset($_SESSION['room_id'])) {
- throw new \Exception("\$_SESSION['room_id'] not set. client_ip:{$_SERVER['REMOTE_ADDR']}");
- }
- $room_id = $_SESSION['room_id'];
- $client_name = $_SESSION['client_name'];
-
- // 私聊
- if ($message_data['to_client_id'] != 'all') {
- $new_message = array(
- 'type' => 'say',
- 'from_client_id' => $client_id,
- 'from_client_name' => $client_name,
- 'to_client_id' => $message_data['to_client_id'],
- 'content' => "对你说: " . nl2br(htmlspecialchars($message_data['content'])),
- 'time' => date('Y-m-d H:i:s'),
- );
- Gateway::sendToClient($message_data['to_client_id'], json_encode($new_message));
- $new_message['content'] = "你对" . htmlspecialchars($message_data['to_client_name']) . "说: " . nl2br(htmlspecialchars($message_data['content']));
- Gateway::sendToCurrentClient(json_encode($new_message));
- return;
- }
-
- $new_message = array(
- 'type' => 'say',
- 'from_client_id' => $client_id,
- 'from_client_name' => $client_name,
- 'to_client_id' => 'all',
- 'content' => nl2br(htmlspecialchars($message_data['content'])),
- 'time' => date('Y-m-d H:i:s'),
- );
- Gateway::sendToGroup($room_id, json_encode($new_message));
- return;
- }
- return;
- }
- }
-
- public static function onClose(string $client_id)
- {
- var_dump(['client_id' => $client_id, 'r'=>'CLOSET']);
-// // 从房间的客户端列表中删除
-// if (isset($_SESSION['room_id'])) {
-// $room_id = $_SESSION['room_id'];
-// $new_message = array('type' => 'logout', 'from_client_id' => $client_id, 'from_client_name' => $_SESSION['client_name'], 'time' => date('Y-m-d H:i:s'));
-// Gateway::sendToGroup($room_id, json_encode($new_message));
-// }
- }
-
-}
diff --git a/app/event/SysGatewayEvent.php b/app/event/SysGatewayEvent.php
new file mode 100644
index 0000000..55963c3
--- /dev/null
+++ b/app/event/SysGatewayEvent.php
@@ -0,0 +1,164 @@
+type == WsTypeEnum::System && $put->event == WsEventEnum::Login) {
+ self::authEvent($put);
+ return;
+ }
+ $isLogin = $put->login($_SESSION['user_id'] ?? 0,
+ $_SESSION['user_type'] ?? '',
+ $_SESSION['client'] ?? []
+ );
+ if (!$isLogin) {
+ echo "用户未登录\r\n";
+ // 未登录
+ return;
+ }
+
+
+ // 3. 调度: 根据类型执行不同的业务
+ switch ($put->type) {
+ // 客户端回应服务端的心跳
+ case WsTypeEnum::Pong:
+ break;
+ // 系统类型组操作
+ case WsTypeEnum::System:
+ switch ($put->event) {
+ case WsEventEnum::Lock_Client:
+ /**
+ * 触发后续其他事件
+ */
+ Event::trigger("gateway.lockClient", [$put]);
+ break;
+ }
+ return;
+ }
+ }
+
+ public static function onClose(string $client_id)
+ {
+ echo "客户端:{$client_id},关闭了\r\n";
+ // 客户端离线的相关逻辑操作
+ if (isset($_SESSION['group_list']) && is_array($_SESSION['group_list'])) {
+ foreach ($_SESSION['group_list'] as $group) {
+ /*
+ * 客户端退出了某个房间
+ */
+ GatewayClientService::sendToGroup($group, new OutMessage(
+ WsTypeEnum::System,
+ WsEventEnum::Client_quit_room,
+ ));
+ }
+ }
+ /**
+ * 触发后续其他事件
+ */
+ Event::trigger("gateway.clientClose", [$client_id]);
+ }
+
+ private static function authEvent(PutMessage $put): void
+ {
+ $token = $put->get('token', '');
+ $clientVersion = $put->get('clientVersion', '');
+ $clientName = $put->get('clientName', '');
+ $clientId = $put->get('clientId', '');
+
+ try {
+ $token = str_replace('Bearer ', '', $token);
+ $loginSrv = new LoginService();
+ $auth = $loginSrv->checkUserAccessToken($token);
+ } catch (ValidateException $e) {
+ // 校验失败
+ var_dump('E1.登录凭证校验失败: '.$e->getMessage());
+ return;
+ }
+ /**
+ * 加入同角色房间
+ */
+ $sysUser = SysUser::find($auth->userId);
+ if ($sysUser) {
+ var_dump('E1.用户数据不存在');
+ return;
+ }
+
+ // 登录
+ $put->login($auth->userId, $auth->userType->value, [
+ 'id' => $clientId,
+ 'name' => $clientName,
+ 'version' => $clientVersion
+ ]);
+ /**
+ * 记录登录凭证信息到$SESSION中
+ */
+ $_SESSION['user_id'] = $put->userId;
+ $_SESSION['user_type'] = $put->userType;
+ $_SESSION['client'] = [
+ 'id' => $put->getClientId(),
+ 'name' => $put->getClientName(),
+ 'version' => $put->getClientVersion()
+ ];
+ /**
+ * 推送登录成功的消息到客户端
+ */
+ GatewayClientService::sendToClient($put->wsClientId, new OutMessage(
+ WsTypeEnum::System,
+ WsEventEnum::Login_SUCCESS,
+ ['userId' => $auth->userId]
+ ));
+ /**
+ *
+ */
+ GatewayClientService::bindUid($put->wsClientId, $auth->userId);
+ /**
+ * 加入已登录的用户公共大厅
+ */
+ GatewayClientService::joinGroup($put->wsClientId, 'PUBLIC_ROOM');
+ /**
+ * 加入同角色的房间
+ */
+ $sysUser->roles->each(function (SysRole $role) use ($put) {
+ GatewayClientService::joinGroup($put->wsClientId, "ROLE_{$role['id']}");
+ });
+ /**
+ * 触发后续其他事件
+ */
+ Event::trigger("gateway.clientLogin", [$put, $sysUser]);
+ }
+}
diff --git a/app/service/GatewayClientService.php b/app/service/GatewayClientService.php
new file mode 100644
index 0000000..94c5e60
--- /dev/null
+++ b/app/service/GatewayClientService.php
@@ -0,0 +1,52 @@
+toJson());
+ }
+
+ /**
+ * 客户端加入某个组
+ * @param string $clientId
+ * @param string $group
+ * @return void
+ */
+ public static function joinGroup(string $clientId, string $group)
+ {
+ Gateway::joinGroup($clientId, $group);
+ $group_list = $_SESSION['group_list'] ?? [];
+ $group_list[] = $group;
+ $_SESSION['group_list'] = $group_list;
+ }
+
+ /**
+ * 将client_id与uid 绑定
+ * @param string $clientId
+ * @param int $uid
+ * @return void
+ */
+ public static function bindUid(string $clientId, int $uid)
+ {
+ Gateway::bindUid($clientId, $uid);
+ }
+
+ public static function sendToGroup($group, OutMessage $message, $exclude_client_id = null, $raw = false)
+ {
+ Gateway::sendToGroup($group, $message->toJson(), $exclude_client_id, $raw);
+ }
+}
\ No newline at end of file
diff --git a/app/subscribe/GatewaySubscribe.php b/app/subscribe/GatewaySubscribe.php
new file mode 100644
index 0000000..c6028ae
--- /dev/null
+++ b/app/subscribe/GatewaySubscribe.php
@@ -0,0 +1,110 @@
+ $put->getClientId(),
+ 'client_name'=> $put->getClientName(),
+ 'user_id' => $put->userId,
+ ])->find();
+ /*
+ * 判断客户端是否锁定状态
+ */
+ if($client && $client['is_lock']) {
+ // 通知客户端锁定屏幕
+ GatewayClientService::sendToClient($put->wsClientId,new OutMessage(
+ WsTypeEnum::System,
+ WsEventEnum::Lock_Client,
+ ));
+ }
+ /*
+ * 客户端登录通知
+ */
+ $ip = $_SERVER['REMOTE_ADDR'] ?? '';
+ GatewayClientService::sendToClient($put->wsClientId, new OutMessage(
+ WsTypeEnum::System,
+ WsEventEnum::Notification,
+ new ElNotification(title: '登录成功,欢迎您', message: "当前登录Ip: $ip"),
+ ));
+ }
+
+ /**
+ * Ws客户端锁定
+ * @param PutMessage $put
+ * @return void
+ * @throws DataNotFoundException
+ * @throws DbException
+ * @throws ModelNotFoundException
+ */
+ public function onLockClient(PutMessage $put): void
+ {
+ $client = SysUserClient::where([
+ 'client_id' => $put->getClientId(),
+ 'client_name'=> $put->getClientName(),
+ 'user_id' => $put->userId,
+ ])->find();
+ if($client) {
+ // 加密传递的锁屏密码
+ $lock_password = password_hash($put->get('password',''), PASSWORD_DEFAULT);
+ // 保存锁屏信息
+ $client->save([
+ 'is_lock'=>1,
+ 'lock_password'=>$lock_password,
+ 'lock_time'=>date('Y-m-d H:i:s')
+ ]);
+ // 保存锁屏日志
+ SysUserClientLog::create([
+ 'event' => "{$put->type->value}.{$put->event->value}",
+ 'message'=> "A. 锁定客户端",
+ 'data' => json_encode(['inputPass'=> $lock_password]),
+ 'create_time' => date('Y-m-d H:i:s'),
+ 'client_data_id' => $client['id']
+ ]);
+ // 通知客户端锁定屏幕
+ GatewayClientService::sendToClient($put->wsClientId,new OutMessage(
+ WsTypeEnum::System,
+ WsEventEnum::Lock_Client,
+ ));
+ }
+
+ }
+
+
+ /**
+ * Ws客户端连接被关闭
+ * @return void
+ */
+ public function onClientClose()
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/z_ele/.env.development b/z_ele/.env.development
index e11ec0a..9d0086f 100644
--- a/z_ele/.env.development
+++ b/z_ele/.env.development
@@ -1,6 +1,7 @@
# 开发环境接口地址
#VITE_API_URL=https://v2.eleadmin.com/api
VITE_API_URL=http://a.tcp.run/adminapi
+VITE_LICENSE=dk9mcwJyetRWQlxWRiojIiwiIzVHbQ5Wa6ICdjVmaiV3ciQWaiwCN3YDNW9ERolFcMJiOpNnclZnIsIyViQjLxIiOi42bQf0NW==
# 禁请求加密
VITE_SKIP_REQUEST_ENCRYPTION=0
# 数据加密key
diff --git a/z_ele/src/main.ts b/z_ele/src/main.ts
index 645efd0..29fafa0 100644
--- a/z_ele/src/main.ts
+++ b/z_ele/src/main.ts
@@ -8,8 +8,8 @@ import i18n from './i18n';
import installer from './as-needed';
import { iconsInstaller } from '@/components/IconSelect/util';
import { WsConfig, WsPlugin } from '@/plugins/websocket';
-import "@/plugins/notification"
-import "@/plugins/service-worker"
+import '@/plugins/notification';
+import '@/plugins/service-worker';
import 'element-plus/theme-chalk/display.css';
import 'ele-admin-plus/es/style/nprogress.scss';
import './styles/themes/rounded.scss';
@@ -21,7 +21,7 @@ const app = createApp(App);
// WebSocket配置
const websocketConfig: Partial = {
- url: 'ws://139.155.146.146:19980', // 你的WebSocket服务器地址
+ url: 'ws://139.155.146.146:19981', // 你的WebSocket服务器地址
reconnectAttempts: 10,
reconnectDelay: 5000,
autoConnect: true // 应用启动时自动连接