Просмотр исходного кода

增加在线用户管理页面

zuohuaijun 3 лет назад
Родитель
Сommit
221130e699
39 измененных файлов с 618 добавлено и 869 удалено
  1. 1 1
      Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj
  2. 78 101
      Admin.NET/Admin.NET.Core/Admin.NET.Core.xml
  3. 12 0
      Admin.NET/Admin.NET.Core/Entity/EntityBase.cs
  4. 0 107
      Admin.NET/Admin.NET.Core/Entity/SysMenu - vben.cs
  5. 19 25
      Admin.NET/Admin.NET.Core/Entity/SysOnlineUser.cs
  6. 1 1
      Admin.NET/Admin.NET.Core/EventBus/LogEventSubscriber.cs
  7. 1 1
      Admin.NET/Admin.NET.Core/EventBus/RedisEventSourceStorer.cs
  8. 0 154
      Admin.NET/Admin.NET.Core/Hub/ChatHub.cs
  9. 0 6
      Admin.NET/Admin.NET.Core/Hub/Dto/ChatHubPrefix.cs
  10. 0 5
      Admin.NET/Admin.NET.Core/Hub/Dto/ForceExistUserRequest.cs
  11. 0 10
      Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserChanged.cs
  12. 1 1
      Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserHubInput.cs
  13. 10 0
      Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserHubOutput.cs
  14. 6 8
      Admin.NET/Admin.NET.Core/Hub/IOnlineUserHub.cs
  15. 140 0
      Admin.NET/Admin.NET.Core/Hub/OnlineUserHub.cs
  16. 5 5
      Admin.NET/Admin.NET.Core/Job/OnlineUserJob.cs
  17. 0 138
      Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData - vben.cs
  18. 1 5
      Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs
  19. 4 4
      Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs
  20. 0 116
      Admin.NET/Admin.NET.Core/Service/Menu/Dto/MenuOutput - vben.cs
  21. 4 4
      Admin.NET/Admin.NET.Core/Service/Message/Dto/MessageInput.cs
  22. 0 39
      Admin.NET/Admin.NET.Core/Service/Message/ISysMessageService.cs
  23. 6 7
      Admin.NET/Admin.NET.Core/Service/Message/SysMessageService.cs
  24. 10 11
      Admin.NET/Admin.NET.Core/Service/Notice/SysNoticeService.cs
  25. 14 0
      Admin.NET/Admin.NET.Core/Service/OnlineUser/Dto/OnlineUserInput.cs
  26. 0 12
      Admin.NET/Admin.NET.Core/Service/OnlineUser/ISysOnlineUserService.cs
  27. 23 21
      Admin.NET/Admin.NET.Core/Service/OnlineUser/SysOnlineUserService.cs
  28. 1 0
      Admin.NET/Admin.NET.Core/Util/DateTimeUtil.cs
  29. 1 1
      Web/.env.development
  30. 1 1
      Web/.env.production
  31. 1 0
      Web/package.json
  32. 12 12
      Web/src/api-services/apis/sys-auth-api.ts
  33. 8 8
      Web/src/api-services/apis/sys-message-api.ts
  34. 35 19
      Web/src/api-services/apis/sys-online-user-api.ts
  35. 6 6
      Web/src/api-services/models/message-input.ts
  36. 17 17
      Web/src/api-services/models/sys-online-user.ts
  37. 31 22
      Web/src/layout/navBars/breadcrumb/user.vue
  38. 6 1
      Web/src/utils/axios-utils.ts
  39. 163 0
      Web/src/views/system/onlineUser/index.vue

+ 1 - 1
Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj

@@ -34,7 +34,7 @@
     <PackageReference Include="NEST" Version="7.17.5" />
     <PackageReference Include="NETCore.MailKit" Version="2.1.0" />
     <PackageReference Include="NewLife.Redis" Version="5.0.2022.901" />
-    <PackageReference Include="OnceMi.AspNetCore.OSS" Version="1.1.8" />
+    <PackageReference Include="OnceMi.AspNetCore.OSS" Version="1.1.9" />
     <PackageReference Include="SKIT.FlurlHttpClient.Wechat.Api" Version="2.18.0" />
     <PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="2.13.1" />
     <PackageReference Include="SqlSugarCore" Version="5.1.3.27" />

+ 78 - 101
Admin.NET/Admin.NET.Core/Admin.NET.Core.xml

@@ -307,6 +307,16 @@
             租户Id
             </summary>
         </member>
+        <member name="T:Admin.NET.Core.EntityTenantId">
+            <summary>
+            租户基类实体Id
+            </summary>
+        </member>
+        <member name="P:Admin.NET.Core.EntityTenantId.TenantId">
+            <summary>
+            租户Id
+            </summary>
+        </member>
         <member name="T:Admin.NET.Core.SysCodeGen">
             <summary>
             代码生成表
@@ -1097,39 +1107,34 @@
             用户Id
             </summary>
         </member>
-        <member name="P:Admin.NET.Core.SysOnlineUser.Account">
+        <member name="P:Admin.NET.Core.SysOnlineUser.UserName">
             <summary>
             账号
             </summary>
         </member>
-        <member name="P:Admin.NET.Core.SysOnlineUser.Name">
+        <member name="P:Admin.NET.Core.SysOnlineUser.RealName">
             <summary>
-            姓名
-            </summary>
-        </member>
-        <member name="P:Admin.NET.Core.SysOnlineUser.LastTime">
-            <summary>
-            最后连接时间
+            真实姓名
             </summary>
         </member>
-        <member name="P:Admin.NET.Core.SysOnlineUser.LastLoginIp">
+        <member name="P:Admin.NET.Core.SysOnlineUser.Time">
             <summary>
-            最后登录IP
+            连接时间
             </summary>
         </member>
-        <member name="P:Admin.NET.Core.SysOnlineUser.LastLoginBrowser">
+        <member name="P:Admin.NET.Core.SysOnlineUser.Ip">
             <summary>
-            最后登录浏览器
+            连接IP
             </summary>
         </member>
-        <member name="P:Admin.NET.Core.SysOnlineUser.LastLoginOs">
+        <member name="P:Admin.NET.Core.SysOnlineUser.Browser">
             <summary>
-            最后登录所用系统
+            浏览器
             </summary>
         </member>
-        <member name="P:Admin.NET.Core.SysOnlineUser.TenantId">
+        <member name="P:Admin.NET.Core.SysOnlineUser.Os">
             <summary>
-            租户Id
+            操作系统
             </summary>
         </member>
         <member name="T:Admin.NET.Core.SysOrg">
@@ -3157,89 +3162,85 @@
             结果筛选器
             </summary>
         </member>
-        <member name="T:Admin.NET.Core.ChatHub">
-            <summary>
-            聊天集线器
-            </summary>
-        </member>
-        <member name="M:Admin.NET.Core.ChatHub.OnConnectedAsync">
+        <member name="M:Admin.NET.Core.IOnlineUserHub.ForceOffline(System.Object)">
             <summary>
-            连接
+            强制下线
             </summary>
+            <param name="context"></param>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.ChatHub.OnDisconnectedAsync(System.Exception)">
+        <member name="M:Admin.NET.Core.IOnlineUserHub.ReceiveMessage(System.Object)">
             <summary>
-            断开
+            接收消息
             </summary>
-            <param name="exception"></param>
+            <param name="context"></param>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.ChatHub.ForceExistUser(Admin.NET.Core.ForceExistUserRequest)">
+        <member name="M:Admin.NET.Core.IOnlineUserHub.OnlineUserChange(Admin.NET.Core.OnlineUserHubOutput)">
             <summary>
-            强制下线
+            在线用户变动
             </summary>
-            <param name="request"></param>
+            <param name="context"></param>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.ChatHub.ClientsSendMessage(Admin.NET.Core.MessageInput)">
+        <member name="M:Admin.NET.Core.IOnlineUserHub.AppendNotice(Admin.NET.Core.SysNotice)">
             <summary>
-            前端调用发送方法(发送信息给某个人)
+            组合消息
             </summary>
-            <param name="message"></param>
+            <param name="notice"></param>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.ChatHub.ClientsSendMessagetoAll(Admin.NET.Core.MessageInput)">
+        <member name="T:Admin.NET.Core.OnlineUserHub">
             <summary>
-            前端调用发送方法(发送信息给所有人)
+            在线用户集线器
             </summary>
-            <param name="message"></param>
-            <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.ChatHub.ClientsSendMessagetoOther(Admin.NET.Core.MessageInput)">
+        <member name="M:Admin.NET.Core.OnlineUserHub.OnConnectedAsync">
             <summary>
-            前端调用发送方法(发送消息给除了发送人的其他人)
+            连接
             </summary>
-            <param name="message"></param>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.ChatHub.ClientsSendMessagetoUsers(Admin.NET.Core.MessageInput)">
+        <member name="M:Admin.NET.Core.OnlineUserHub.OnDisconnectedAsync(System.Exception)">
             <summary>
-            前端调用发送方法(发送消息给某些人)
+            断开
             </summary>
-            <param name="message"></param>
+            <param name="exception"></param>
             <returns></returns>
         </member>
-        <member name="T:Admin.NET.Core.IChatClient">
+        <member name="M:Admin.NET.Core.OnlineUserHub.ForceOffline(Admin.NET.Core.OnlineUserHubInput)">
             <summary>
-            聊天客户端接口定义
+            强制下线
             </summary>
+            <param name="input"></param>
+            <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.IChatClient.ForceExist(System.String)">
+        <member name="M:Admin.NET.Core.OnlineUserHub.ClientsSendMessage(Admin.NET.Core.MessageInput)">
             <summary>
-            强制下线
+            前端调用发送方法(发送信息给某个人)
             </summary>
+            <param name="message"></param>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.IChatClient.ReceiveMessage(System.Object)">
+        <member name="M:Admin.NET.Core.OnlineUserHub.ClientsSendMessagetoAll(Admin.NET.Core.MessageInput)">
             <summary>
-            发送信息
+            前端调用发送方法(发送信息给所有人)
             </summary>
-            <param name="context"></param>
+            <param name="message"></param>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.IChatClient.OnlineUserChanged(Admin.NET.Core.OnlineUserChangedDto)">
+        <member name="M:Admin.NET.Core.OnlineUserHub.ClientsSendMessagetoOther(Admin.NET.Core.MessageInput)">
             <summary>
-            在线用户变动
+            前端调用发送方法(发送消息给除了发送人的其他人)
             </summary>
-            <param name="context"></param>
+            <param name="message"></param>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.IChatClient.AppendNotice(Admin.NET.Core.SysNotice)">
+        <member name="M:Admin.NET.Core.OnlineUserHub.ClientsSendMessagetoUsers(Admin.NET.Core.MessageInput)">
             <summary>
-            组合信息
+            前端调用发送方法(发送消息给某些人)
             </summary>
-            <param name="notice"></param>
+            <param name="message"></param>
             <returns></returns>
         </member>
         <member name="T:Admin.NET.Core.LogJob">
@@ -3256,12 +3257,12 @@
         </member>
         <member name="T:Admin.NET.Core.Job.OnlineUserJob">
             <summary>
-            任务调度
+            在线用户任务调度
             </summary>
         </member>
         <member name="M:Admin.NET.Core.Job.OnlineUserJob.ClearOnlineUser(Furion.TaskScheduler.SpareTimer,System.Int64)">
             <summary>
-            清理在线用户定时器---服务启动时自动清空在线用户,防止存在僵尸用户(掉线用户会自动重连)
+            服务重启清空在线用户(防止僵尸用户,掉线用户会自动重连)
             </summary>
         </member>
         <member name="T:Admin.NET.Core.DatabaseLoggingWriter">
@@ -3788,7 +3789,7 @@
             登录系统
             </summary>
             <param name="input"></param>
-            <remarks>用户名/密码:vben/123456</remarks>
+            <remarks>用户名/密码:superadmin/123456</remarks>
             <returns></returns>
         </member>
         <member name="M:Admin.NET.Core.Service.SysAuthService.GetUserInfo">
@@ -5400,41 +5401,6 @@
             </summary>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.Service.ISysMessageService.SendMessageToAllUser(Admin.NET.Core.MessageInput)">
-            <summary>
-            发送消息给所有人
-            </summary>
-            <param name="input"></param>
-            <returns></returns>
-        </member>
-        <member name="M:Admin.NET.Core.Service.ISysMessageService.SendMessageToUser(Admin.NET.Core.MessageInput)">
-            <summary>
-            发送消息给某个人
-            </summary>
-            <param name="input"></param>
-            <returns></returns>
-        </member>
-        <member name="M:Admin.NET.Core.Service.ISysMessageService.SendMessageToUsers(Admin.NET.Core.MessageInput)">
-            <summary>
-            发送消息给某些人
-            </summary>
-            <param name="input"></param>
-            <returns></returns>
-        </member>
-        <member name="M:Admin.NET.Core.Service.ISysMessageService.SendMessageToOtherUser(Admin.NET.Core.MessageInput)">
-            <summary>
-            发送消息给除了发送人的其他人
-            </summary>
-            <param name="input"></param>
-            <returns></returns>
-        </member>
-        <member name="M:Admin.NET.Core.Service.ISysMessageService.SendEmail(System.String)">
-            <summary>
-            发送邮件
-            </summary>
-            <param name="message"></param>
-            <returns></returns>
-        </member>
         <member name="T:Admin.NET.Core.Service.SysMessageService">
             <summary>
             系统消息发送服务
@@ -5761,25 +5727,35 @@
             <param name="status"></param>
             <returns></returns>
         </member>
+        <member name="P:Admin.NET.Core.Service.PageOnlineUserInput.UserName">
+            <summary>
+            账号名称
+            </summary>
+        </member>
+        <member name="P:Admin.NET.Core.Service.PageOnlineUserInput.RealName">
+            <summary>
+            真实姓名
+            </summary>
+        </member>
         <member name="T:Admin.NET.Core.Service.SysOnlineUserService">
             <summary>
             系统在线用户服务
             </summary>
         </member>
-        <member name="M:Admin.NET.Core.Service.SysOnlineUserService.List(Admin.NET.Core.BasePageInput)">
+        <member name="M:Admin.NET.Core.Service.SysOnlineUserService.GetOnlineUserPage(Admin.NET.Core.Service.PageOnlineUserInput)">
             <summary>
-            获取在线用户信息
+            获取在线用户分页列表
             </summary>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.Service.SysOnlineUserService.ForceExist(Admin.NET.Core.SysOnlineUser)">
+        <member name="M:Admin.NET.Core.Service.SysOnlineUserService.ForceOffline(Admin.NET.Core.SysOnlineUser)">
             <summary>
             强制下线
             </summary>
             <param name="user"></param>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.Service.SysOnlineUserService.PushNotice(Admin.NET.Core.SysNotice,System.Collections.Generic.List{System.Int64})">
+        <member name="M:Admin.NET.Core.Service.SysOnlineUserService.AppendNotice(Admin.NET.Core.SysNotice,System.Collections.Generic.List{System.Int64})">
             <summary>
             发送消息
             </summary>
@@ -6944,14 +6920,14 @@
             消息标题
             </summary>
         </member>
-        <member name="P:Admin.NET.Core.MessageInput.Message">
+        <member name="P:Admin.NET.Core.MessageInput.MessageType">
             <summary>
-            消息内容
+            消息类型
             </summary>
         </member>
-        <member name="P:Admin.NET.Core.MessageInput.MessageType">
+        <member name="P:Admin.NET.Core.MessageInput.Message">
             <summary>
-            消息类型
+            消息内容
             </summary>
         </member>
         <member name="T:Admin.NET.Core.UserManager">
@@ -7428,6 +7404,7 @@
             获取开始时间
             </summary>
             <param name="dateTime"></param>
+            <param name="days"></param>
             <returns></returns>
         </member>
         <member name="M:Admin.NET.Core.DateTimeUtil.ToLocalTimeDateBySeconds(System.Int64)">

+ 12 - 0
Admin.NET/Admin.NET.Core/Entity/EntityBase.cs

@@ -64,6 +64,18 @@ public abstract class DataEntityBase : EntityBase
 /// 租户基类实体
 /// </summary>
 public abstract class EntityTenant : EntityBase
+{
+    /// <summary>
+    /// 租户Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "租户Id")]
+    public virtual long? TenantId { get; set; }
+}
+
+/// <summary>
+/// 租户基类实体Id
+/// </summary>
+public abstract class EntityTenantId : EntityBaseId
 {
     /// <summary>
     /// 租户Id

+ 0 - 107
Admin.NET/Admin.NET.Core/Entity/SysMenu - vben.cs

@@ -1,107 +0,0 @@
-//namespace Admin.NET.Core;
-
-///// <summary>
-///// 系统菜单表
-///// </summary>
-//[SugarTable("sys_menu", "系统菜单表")]
-//public class SysMenu : EntityBase
-//{
-//    /// <summary>
-//    /// 父Id
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "父Id")]
-//    public long Pid { get; set; }
-
-//    /// <summary>
-//    /// 菜单类型(1目录 2菜单 3按钮)
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "菜单类型")]
-//    public MenuTypeEnum Type { get; set; }
-
-//    /// <summary>
-//    /// 名称
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "名称", Length = 64)]
-//    [MaxLength(64)]
-//    public string Name { get; set; }
-
-//    /// <summary>
-//    /// 路由地址
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "路由地址", Length = 128)]
-//    [MaxLength(128)]
-//    public string Path { get; set; }
-
-//    /// <summary>
-//    /// 组件路径
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "组件路径", Length = 128)]
-//    [MaxLength(128)]
-//    public string Component { get; set; }
-
-//    /// <summary>
-//    /// 权限标识
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "权限标识", Length = 128)]
-//    [MaxLength(128)]
-//    public string Permission { get; set; }
-
-//    /// <summary>
-//    /// 重定向
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "重定向", Length = 128)]
-//    [MaxLength(128)]
-//    public string Redirect { get; set; }
-
-//    /// <summary>
-//    /// 内嵌地址
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "内嵌地址", Length = 128)]
-//    [MaxLength(128)]
-//    public string FrameSrc { get; set; }
-
-//    /// <summary>
-//    /// 标题
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "标题", Length = 64)]
-//    [Required, MaxLength(64)]
-//    public virtual string Title { get; set; }
-
-//    /// <summary>
-//    /// 图标
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "图标", Length = 128)]
-//    [MaxLength(128)]
-//    public string Icon { get; set; }
-
-//    /// <summary>
-//    /// 隐藏菜单
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "隐藏菜单")]
-//    public bool HideMenu { get; set; } = false;
-
-//    /// <summary>
-//    /// 忽略缓存
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "忽略缓存")]
-//    public bool IgnoreKeepAlive { get; set; } = false;
-
-//    /// <summary>
-//    /// 当前激活的菜单-用于配置详情页时左侧激活的菜单路径
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "当前激活菜单", Length = 128)]
-//    [MaxLength(128)]
-//    public string CurrentActiveMenu { get; set; }
-
-//    /// <summary>
-//    /// 排序
-//    /// </summary>
-//    [SugarColumn(ColumnDescription = "排序")]
-//    public int Order { get; set; }
-
-//    /// <summary>
-//    /// 菜单子项
-//    /// </summary>
-//    [SugarColumn(IsIgnore = true)]
-//    public List<SysMenu> Children { get; set; } = new List<SysMenu>();
-//}

+ 19 - 25
Admin.NET/Admin.NET.Core/Entity/SysOnlineUser.cs

@@ -4,7 +4,7 @@
 /// 系统在线用户表
 /// </summary>
 [SugarTable("sys_online_user", "系统在线用户表")]
-public class SysOnlineUser : EntityBaseId
+public class SysOnlineUser : EntityTenantId
 {
     /// <summary>
     /// 连接Id
@@ -23,45 +23,39 @@ public class SysOnlineUser : EntityBaseId
     /// </summary>
     [SugarColumn(ColumnDescription = "账号", Length = 32)]
     [Required, MaxLength(32)]
-    public virtual string Account { get; set; }
+    public virtual string UserName { get; set; }
 
     /// <summary>
-    /// 姓名
+    /// 真实姓名
     /// </summary>
-    [SugarColumn(ColumnDescription = "姓名", Length = 32)]
+    [SugarColumn(ColumnDescription = "真实姓名", Length = 32)]
     [MaxLength(32)]
-    public string Name { get; set; }
+    public string RealName { get; set; }
 
     /// <summary>
-    /// 最后连接时间
+    /// 连接时间
     /// </summary>
-    [SugarColumn(ColumnDescription = "最后连接时间")]
-    public DateTime LastTime { get; set; }
+    [SugarColumn(ColumnDescription = "连接时间")]
+    public DateTime Time { get; set; }
 
     /// <summary>
-    /// 最后登录IP
+    /// 连接IP
     /// </summary>
-    [SugarColumn(ColumnDescription = "最后登录IP", Length = 16)]
+    [SugarColumn(ColumnDescription = "连接IP", Length = 16)]
     [MaxLength(16)]
-    public string LastLoginIp { get; set; }
+    public string Ip { get; set; }
 
     /// <summary>
-    /// 最后登录浏览器
+    /// 浏览器
     /// </summary>
-    [SugarColumn(ColumnDescription = "最后登录浏览器", Length = 32)]
-    [MaxLength(32)]
-    public string LastLoginBrowser { get; set; }
-
-    /// <summary>
-    /// 最后登录所用系统
-    /// </summary>
-    [SugarColumn(ColumnDescription = "最后登录系统", Length = 32)]
-    [MaxLength(32)]
-    public string LastLoginOs { get; set; }
+    [SugarColumn(ColumnDescription = "浏览器", Length = 128)]
+    [MaxLength(128)]
+    public string Browser { get; set; }
 
     /// <summary>
-    /// 租户Id
+    /// 操作系统
     /// </summary>
-    [SugarColumn(ColumnDescription = "租户Id")]
-    public long TenantId { get; set; }
+    [SugarColumn(ColumnDescription = "操作系统", Length = 128)]
+    [MaxLength(128)]
+    public string Os { get; set; }
 }

+ 1 - 1
Admin.NET/Admin.NET.Core/EventBus/LogEventSubscriber.cs

@@ -38,7 +38,7 @@ public class LogEventSubscriber : IEventSubscriber, ISingleton
         await _rep.InsertAsync((SysLogEx)context.Source.Payload);
 
         // 发送邮件
-        await scope.ServiceProvider.GetRequiredService<ISysMessageService>().SendEmail(JSON.Serialize(context.Source.Payload));
+        await scope.ServiceProvider.GetRequiredService<SysMessageService>().SendEmail(JSON.Serialize(context.Source.Payload));
     }
 
     /// <summary>

+ 1 - 1
Admin.NET/Admin.NET.Core/EventBus/RedisEventSourceStorer.cs

@@ -12,7 +12,7 @@ public class RedisEventSourceStorer : IEventSourceStorer
 
     private readonly FullRedis _redis;
 
-    private readonly string _topic = "eventbus";
+    // private readonly string _topic = "eventbus";
 
     public RedisEventSourceStorer(ICache redis, int capacity = 10000)
     {

+ 0 - 154
Admin.NET/Admin.NET.Core/Hub/ChatHub.cs

@@ -1,154 +0,0 @@
-using Furion.InstantMessaging;
-using Microsoft.AspNetCore.SignalR;
-
-namespace Admin.NET.Core;
-
-/// <summary>
-/// 聊天集线器
-/// </summary>
-[MapHub("/hubs/chathub")]
-public class ChatHub : Hub<IChatClient>
-{
-    private readonly SysCacheService _sysCache;
-    private readonly ISysMessageService _sysMessageService;
-    private readonly SqlSugarRepository<SysOnlineUser> _sysOnlineUerRep;
-    private readonly IHubContext<ChatHub, IChatClient> _chatHubContext;
-
-    public ChatHub(SysCacheService sysCache,
-        ISysMessageService sysMessageService,
-        SqlSugarRepository<SysOnlineUser> sysOnlineUerRep,
-        IHubContext<ChatHub, IChatClient> chatHubContext)
-    {
-        _sysCache = sysCache;
-        _sysMessageService = sysMessageService;
-        _sysOnlineUerRep = sysOnlineUerRep;
-        _chatHubContext = chatHubContext;
-    }
-
-    /// <summary>
-    /// 连接
-    /// </summary>
-    /// <returns></returns>
-    public override async Task OnConnectedAsync()
-    {
-        var token = Context.GetHttpContext().Request.Query["access_token"];
-        var claims = JWTEncryption.ReadJwtToken(token)?.Claims;
-
-        var client = Parser.GetDefault().Parse(Context.GetHttpContext().Request.Headers["User-Agent"]);
-        var loginBrowser = client.UA.Family + client.UA.Major;
-        var loginOs = client.OS.Family + client.OS.Major;
-
-        var userId = claims.FirstOrDefault(e => e.Type == ClaimConst.UserId)?.Value;
-        var account = claims.FirstOrDefault(e => e.Type == ClaimConst.UserName)?.Value;
-        var name = claims.FirstOrDefault(e => e.Type == ClaimConst.RealName)?.Value;
-        var tenantId = claims.FirstOrDefault(e => e.Type == ClaimConst.TenantId)?.Value;
-        var user = new SysOnlineUser
-        {
-            ConnectionId = Context.ConnectionId,
-            UserId = long.Parse(userId),
-            LastTime = DateTime.Now,
-            LastLoginIp = App.HttpContext.GetRemoteIpAddressToIPv4(),
-            LastLoginBrowser = loginBrowser,
-            LastLoginOs = loginOs,
-            Account = account,
-            Name = name,
-            TenantId = Convert.ToInt64(tenantId),
-        };
-        await _sysOnlineUerRep.AsInsertable(user).ExecuteCommandAsync();
-        //加入分组  以租户ID分组 方便后续通知
-        await _chatHubContext.Groups.AddToGroupAsync(Context.ConnectionId, $"{ChatHubPrefix.GROUP_ONLINE}{tenantId}");
-
-        var list = await _sysOnlineUerRep.AsQueryable().Filter("", true).Where(x => x.TenantId == user.TenantId).ToListAsync();
-        await _chatHubContext.Clients.Groups($"{ChatHubPrefix.GROUP_ONLINE}{user.TenantId}").OnlineUserChanged(new OnlineUserChangedDto
-        {
-            Name = user.Name,
-            Offline = false,
-            List = list
-        });
-
-        //onlineUsers.Add();
-        //await _cache.SetAsync($"{CacheConst.KeyOnlineUser}{ Context.ConnectionId}", user);
-        //await _sendMessageService.SendMessageToUserByConnectionId("asdasd但凡生得分", "下线吧", MessageTypeEnum.Offline, Context.ConnectionId);
-    }
-
-    /// <summary>
-    /// 断开
-    /// </summary>
-    /// <param name="exception"></param>
-    /// <returns></returns>
-    public override async Task OnDisconnectedAsync(Exception exception)
-    {
-        if (!string.IsNullOrEmpty(Context.ConnectionId))
-        {
-            var user = await _sysOnlineUerRep.AsQueryable().Filter("", true).FirstAsync(x => x.ConnectionId == Context.ConnectionId);
-            if (user == null) return;
-
-            await _sysOnlineUerRep.DeleteAsync(x => x.Id == user.Id);
-            //通知当前组用户变动
-            var list = await _sysOnlineUerRep.AsQueryable().Filter("", true).Where(x => x.TenantId == user.TenantId).ToListAsync();
-            await _chatHubContext.Clients.Groups($"{ChatHubPrefix.GROUP_ONLINE}{user.TenantId}").OnlineUserChanged(new OnlineUserChangedDto
-            {
-                Name = user.Name,
-                Offline = true,
-                List = list
-            });
-
-            //var onlineUsers = await _cache.GetAsync<List<SysOnlineUser>>(CacheConst.KeyOnlineUser);
-            //if (onlineUsers == null) return;
-
-            //onlineUsers.RemoveAll(u => u.ConnectionId == Context.ConnectionId);
-            //await _cache.RemoveAsync($"{CacheConst.KeyOnlineUser}{ Context.ConnectionId}");
-        }
-    }
-
-    /// <summary>
-    /// 强制下线
-    /// </summary>
-    /// <param name="request"></param>
-    /// <returns></returns>
-    public async Task ForceExistUser(ForceExistUserRequest request)
-    {
-        await _chatHubContext.Clients.Client(request.ConnectionId).ForceExist("强制下线");
-    }
-
-    /// <summary>
-    /// 前端调用发送方法(发送信息给某个人)
-    /// </summary>
-    /// <param name="message"></param>
-    /// <returns></returns>
-    public async Task ClientsSendMessage(MessageInput message)
-    {
-        await _sysMessageService.SendMessageToUser(message);
-    }
-
-    /// <summary>
-    /// 前端调用发送方法(发送信息给所有人)
-    /// </summary>
-    /// <param name="message"></param>
-    /// <returns></returns>
-    public async Task ClientsSendMessagetoAll(MessageInput message)
-    {
-        await _sysMessageService.SendMessageToAllUser(message);
-    }
-
-    /// <summary>
-    /// 前端调用发送方法(发送消息给除了发送人的其他人)
-    /// </summary>
-    /// <param name="message"></param>
-    /// <returns></returns>
-    public async Task ClientsSendMessagetoOther(MessageInput message)
-    {
-        // _message.userId为发送人ID
-        await _sysMessageService.SendMessageToOtherUser(message);
-    }
-
-    /// <summary>
-    /// 前端调用发送方法(发送消息给某些人)
-    /// </summary>
-    /// <param name="message"></param>
-    /// <returns></returns>
-    public async Task ClientsSendMessagetoUsers(MessageInput message)
-    {
-        await _sysMessageService.SendMessageToUsers(message);
-    }
-}

+ 0 - 6
Admin.NET/Admin.NET.Core/Hub/Dto/ChatHubPrefix.cs

@@ -1,6 +0,0 @@
-namespace Admin.NET.Core;
-
-public class ChatHubPrefix
-{
-    public const string GROUP_ONLINE = "GROUP_ONLINE_";
-}

+ 0 - 5
Admin.NET/Admin.NET.Core/Hub/Dto/ForceExistUserRequest.cs

@@ -1,5 +0,0 @@
-namespace Admin.NET.Core;
-
-public class ForceExistUserRequest : ChatHubRequest
-{
-}

+ 0 - 10
Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserChanged.cs

@@ -1,10 +0,0 @@
-namespace Admin.NET.Core;
-
-public class OnlineUserChangedDto
-{
-    public string Name { get; set; }
-
-    public bool Offline { get; set; }
-
-    public List<SysOnlineUser> List { get; set; }
-}

+ 1 - 1
Admin.NET/Admin.NET.Core/Hub/Dto/ChatHubRequest.cs → Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserHubInput.cs

@@ -1,6 +1,6 @@
 namespace Admin.NET.Core;
 
-public class ChatHubRequest
+public class OnlineUserHubInput
 {
     public string ConnectionId { get; set; }
 }

+ 10 - 0
Admin.NET/Admin.NET.Core/Hub/Dto/OnlineUserHubOutput.cs

@@ -0,0 +1,10 @@
+namespace Admin.NET.Core;
+
+public class OnlineUserHubOutput
+{
+    public string RealName { get; set; }
+
+    public bool Online { get; set; }
+
+    public List<SysOnlineUser> UserList { get; set; }
+}

+ 6 - 8
Admin.NET/Admin.NET.Core/Hub/IChatClient.cs → Admin.NET/Admin.NET.Core/Hub/IOnlineUserHub.cs

@@ -1,18 +1,16 @@
 namespace Admin.NET.Core;
 
-/// <summary>
-/// 聊天客户端接口定义
-/// </summary>
-public interface IChatClient
+public interface IOnlineUserHub
 {
     /// <summary>
     /// 强制下线
     /// </summary>
+    /// <param name="context"></param>
     /// <returns></returns>
-    Task ForceExist(string str);
+    Task ForceOffline(object context);
 
     /// <summary>
-    /// 发送信
+    /// 接收消
     /// </summary>
     /// <param name="context"></param>
     /// <returns></returns>
@@ -23,10 +21,10 @@ public interface IChatClient
     /// </summary>
     /// <param name="context"></param>
     /// <returns></returns>
-    Task OnlineUserChanged(OnlineUserChangedDto context);
+    Task OnlineUserChange(OnlineUserHubOutput context);
 
     /// <summary>
-    /// 组合
+    /// 组合
     /// </summary>
     /// <param name="notice"></param>
     /// <returns></returns>

+ 140 - 0
Admin.NET/Admin.NET.Core/Hub/OnlineUserHub.cs

@@ -0,0 +1,140 @@
+using Furion.InstantMessaging;
+using Microsoft.AspNetCore.SignalR;
+
+namespace Admin.NET.Core;
+
+/// <summary>
+/// 在线用户集线器
+/// </summary>
+[MapHub("/hubs/onlineUser")]
+public class OnlineUserHub : Hub<IOnlineUserHub>
+{
+    private readonly SqlSugarRepository<SysOnlineUser> _sysOnlineUerRep;
+    private readonly SysCacheService _sysCache;
+    private readonly SysMessageService _sysMessageService;    
+    private readonly IHubContext<OnlineUserHub, IOnlineUserHub> _onlineUserHubContext;
+
+    private const string GROUP_ONLINE = "GROUP_ONLINE_"; // 租户分组前缀
+
+    public OnlineUserHub(SqlSugarRepository<SysOnlineUser> sysOnlineUerRep, 
+        SysCacheService sysCache,
+        SysMessageService sysMessageService,        
+        IHubContext<OnlineUserHub, IOnlineUserHub> onlineUserHubContext)
+    {
+        _sysOnlineUerRep = sysOnlineUerRep;
+        _sysCache = sysCache;
+        _sysMessageService = sysMessageService;        
+        _onlineUserHubContext = onlineUserHubContext;
+    }
+
+    /// <summary>
+    /// 连接
+    /// </summary>
+    /// <returns></returns>
+    public override async Task OnConnectedAsync()
+    {
+        var token = Context.GetHttpContext().Request.Query["access_token"];
+        var claims = JWTEncryption.ReadJwtToken(token)?.Claims;
+        var client = Parser.GetDefault().Parse(Context.GetHttpContext().Request.Headers["User-Agent"]);
+        var user = new SysOnlineUser
+        {
+            ConnectionId = Context.ConnectionId,
+            UserId = long.Parse(claims.FirstOrDefault(u => u.Type == ClaimConst.UserId)?.Value),
+            UserName = claims.FirstOrDefault(u => u.Type == ClaimConst.UserName)?.Value,
+            RealName = claims.FirstOrDefault(u => u.Type == ClaimConst.RealName)?.Value,
+            Time = DateTime.Now,
+            Ip = App.HttpContext.GetRemoteIpAddressToIPv4(),
+            Browser = client.UA.Family + client.UA.Major,
+            Os = client.OS.Family + client.OS.Major,
+            TenantId = Convert.ToInt64(claims.FirstOrDefault(u => u.Type == ClaimConst.TenantId)?.Value),
+        };
+        await _sysOnlineUerRep.InsertAsync(user);
+
+        // 以租户Id分组方便区分
+        await _onlineUserHubContext.Groups.AddToGroupAsync(Context.ConnectionId, $"{GROUP_ONLINE}{user.TenantId}");
+
+        var userList = await _sysOnlineUerRep.AsQueryable().Filter("", true)
+            .Where(u => u.TenantId == user.TenantId).Take(10).ToListAsync();
+        await _onlineUserHubContext.Clients.Groups($"{GROUP_ONLINE}{user.TenantId}").OnlineUserChange(new OnlineUserHubOutput
+        {
+            RealName = user.RealName,
+            Online = true,
+            UserList = userList
+        });
+    }
+
+    /// <summary>
+    /// 断开
+    /// </summary>
+    /// <param name="exception"></param>
+    /// <returns></returns>
+    public override async Task OnDisconnectedAsync(Exception exception)
+    {
+        if (string.IsNullOrEmpty(Context.ConnectionId)) return;
+
+        var user = await _sysOnlineUerRep.AsQueryable().Filter("", true).FirstAsync(u => u.ConnectionId == Context.ConnectionId);
+        if (user == null) return;
+
+        await _sysOnlineUerRep.DeleteAsync(u => u.Id == user.Id);
+
+        // 通知当前组用户变动
+        var userList = await _sysOnlineUerRep.AsQueryable().Filter("", true)
+            .Where(u => u.TenantId == user.TenantId).Take(10).ToListAsync();
+        await _onlineUserHubContext.Clients.Groups($"{GROUP_ONLINE}{user.TenantId}").OnlineUserChange(new OnlineUserHubOutput
+        {
+            RealName = user.RealName,
+            Online = false,
+            UserList = userList
+        });
+    }
+
+    /// <summary>
+    /// 强制下线
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    public async Task ForceOffline(OnlineUserHubInput input)
+    {
+        await _onlineUserHubContext.Clients.Client(input.ConnectionId).ForceOffline("强制下线");
+    }
+
+    /// <summary>
+    /// 前端调用发送方法(发送信息给某个人)
+    /// </summary>
+    /// <param name="message"></param>
+    /// <returns></returns>
+    public async Task ClientsSendMessage(MessageInput message)
+    {
+        await _sysMessageService.SendMessageToUser(message);
+    }
+
+    /// <summary>
+    /// 前端调用发送方法(发送信息给所有人)
+    /// </summary>
+    /// <param name="message"></param>
+    /// <returns></returns>
+    public async Task ClientsSendMessagetoAll(MessageInput message)
+    {
+        await _sysMessageService.SendMessageToAllUser(message);
+    }
+
+    /// <summary>
+    /// 前端调用发送方法(发送消息给除了发送人的其他人)
+    /// </summary>
+    /// <param name="message"></param>
+    /// <returns></returns>
+    public async Task ClientsSendMessagetoOther(MessageInput message)
+    {
+        await _sysMessageService.SendMessageToOtherUser(message);
+    }
+
+    /// <summary>
+    /// 前端调用发送方法(发送消息给某些人)
+    /// </summary>
+    /// <param name="message"></param>
+    /// <returns></returns>
+    public async Task ClientsSendMessagetoUsers(MessageInput message)
+    {
+        await _sysMessageService.SendMessageToUsers(message);
+    }
+}

+ 5 - 5
Admin.NET/Admin.NET.Core/Job/OnlineUserJob.cs

@@ -1,14 +1,14 @@
 namespace Admin.NET.Core.Job;
 
 /// <summary>
-/// 任务调度
+/// 在线用户任务调度
 /// </summary>
 public class OnlineUserJob : ISpareTimeWorker
 {
     /// <summary>
-    /// 清理在线用户定时器---服务启动时自动清空在线用户,防止存在僵尸用户(掉线用户会自动重连)
+    /// 服务重启清空在线用户(防止僵尸用户,掉线用户会自动重连)
     /// </summary>
-    [SpareTime(1000, "清空在线用户", Description = "服务启动时运行", DoOnce = true, StartNow = true, ExecuteType = SpareTimeExecuteTypes.Serial)]
+    [SpareTime(1000, "服务重启清空在线用户", Description = "服务重启清空在线用户", DoOnce = true, StartNow = true, ExecuteType = SpareTimeExecuteTypes.Serial)]
     public void ClearOnlineUser(SpareTimer timer, long count)
     {
         Scoped.CreateAsync(async (_, scope) =>
@@ -17,8 +17,8 @@ public class OnlineUserJob : ISpareTimeWorker
             var rep = services.GetService<SqlSugarRepository<SysOnlineUser>>();
             await rep.AsDeleteable().ExecuteCommandAsync();
 
-            Console.ForegroundColor = ConsoleColor.Blue;
-            Console.WriteLine("【" + DateTime.Now + "——清空在线用户\r\n服务重启触发清空在线用户");
+            Console.ForegroundColor = ConsoleColor.Red;
+            Console.WriteLine("【" + DateTime.Now + "】服务重启清空在线用户");
         });
     }
 }

+ 0 - 138
Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData - vben.cs

@@ -1,138 +0,0 @@
-//namespace Admin.NET.Core;
-
-///// <summary>
-///// 系统菜单表种子数据
-///// </summary>
-//public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
-//{
-//    /// <summary>
-//    /// 种子数据
-//    /// </summary>
-//    /// <returns></returns>
-//    public IEnumerable<SysMenu> HasData()
-//    {
-//        return new[]
-//        {
-//            new SysMenu{ Id=252885263002100, Pid=0, Title="数据面板", Path="/dashboard", Name="Dashboard", Component="LAYOUT", Redirect="/dashboard/analysis", Icon="ant-design:home-outlined", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=10 },
-//            new SysMenu{ Id=252885263002110, Pid=252885263002100, Title="分析页", Path="analysis", Name="Analysis", Component="/dashboard/analysis/index", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002111, Pid=252885263002100, Title="工作台", Path="workbench", Name="Workbench", Component="/dashboard/workbench/index", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=101 },
-
-//            new SysMenu{ Id=252885263002200, Pid=0, Title="系统管理", Path="/sys", Name="sys", Component="LAYOUT", Redirect="", Icon="ant-design:setting-outlined", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002210, Pid=252885263002200, Title="账号管理", Path="user", Name="UserManagement", Component="/sys/admin/user/index", Icon="ant-design:user-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002211, Pid=252885263002210, Title="账号查询", Permission="sysUser:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002212, Pid=252885263002210, Title="账号编辑", Permission="sysUser:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002213, Pid=252885263002210, Title="账号增加", Permission="sysUser:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002214, Pid=252885263002210, Title="账号删除", Permission="sysUser:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002215, Pid=252885263002210, Title="授权角色", Permission="sysUser:grantRole", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002216, Pid=252885263002210, Title="授权数据", Permission="sysUser:grantData", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002217, Pid=252885263002210, Title="重置密码", Permission="sysUser:resetPwd", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002218, Pid=252885263002210, Title="设置状态", Permission="sysUser:setStatus", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002220, Pid=252885263002200, Title="角色管理", Path="role", Name="RoleManagement", Component="/sys/admin/role/index", Icon="ant-design:bulb-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=110 },
-//            new SysMenu{ Id=252885263002221, Pid=252885263002220, Title="角色查询", Permission="sysRole:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002222, Pid=252885263002220, Title="角色编辑", Permission="sysRole:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002223, Pid=252885263002220, Title="角色增加", Permission="sysRole:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002224, Pid=252885263002220, Title="角色删除", Permission="sysRole:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002225, Pid=252885263002220, Title="授权菜单", Permission="sysRole:grantMenu", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002226, Pid=252885263002220, Title="授权数据", Permission="sysRole:grantData", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002227, Pid=252885263002220, Title="设置状态", Permission="sysRole:setStatus", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002230, Pid=252885263002200, Title="菜单管理", Path="menu", Name="MenuManagement", Component="/sys/admin/menu/index", Icon="ant-design:menu-fold-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=120 },
-//            new SysMenu{ Id=252885263002231, Pid=252885263002230, Title="菜单查询", Permission="sysMenu:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002232, Pid=252885263002230, Title="菜单编辑", Permission="sysMenu:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002233, Pid=252885263002230, Title="菜单增加", Permission="sysMenu:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002234, Pid=252885263002230, Title="菜单删除", Permission="sysMenu:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002240, Pid=252885263002200, Title="机构管理", Path="org", Name="OrgManagement", Component="/sys/admin/org/index", Icon="ant-design:gold-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=130 },
-//            new SysMenu{ Id=252885263002241, Pid=252885263002240, Title="机构查询", Permission="sysOrg:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002242, Pid=252885263002240, Title="机构编辑", Permission="sysOrg:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002243, Pid=252885263002240, Title="机构增加", Permission="sysOrg:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002244, Pid=252885263002240, Title="机构删除", Permission="sysOrg:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002250, Pid=252885263002200, Title="职位管理", Path="pos", Name="PosManagement", Component="/sys/admin/pos/index",Icon="ant-design:tool-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=140 },
-//            new SysMenu{ Id=252885263002251, Pid=252885263002250, Title="职位查询", Permission="sysPos:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002252, Pid=252885263002250, Title="职位编辑", Permission="sysPos:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002253, Pid=252885263002250, Title="职位增加", Permission="sysPos:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002254, Pid=252885263002250, Title="职位删除", Permission="sysPos:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002260, Pid=252885263002200, Title="修改密码", Path="password", Name="PasswordManagement", Component="/sys/admin/password/index",Icon="ant-design:eye-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=150 },
-
-//            //平台管理
-//            new SysMenu{ Id=252885263002300, Pid=0, Title="平台管理", Path="/platform", Name="platform", Component="LAYOUT", Redirect="", Icon="ant-design:ant-design-outlined", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=200 },
-
-//            new SysMenu{ Id=252885263002310, Pid=252885263002300, Title="租户管理", Path="tenant", Name="TenantManagement", Component="/sys/admin/tenant/index", Icon="ant-design:cluster-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002311, Pid=252885263002310, Title="租户查询", Permission="sysTenant:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002312, Pid=252885263002310, Title="租户编辑", Permission="sysTenant:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002313, Pid=252885263002310, Title="租户增加", Permission="sysTenant:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002314, Pid=252885263002310, Title="租户删除", Permission="sysTenant:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002315, Pid=252885263002310, Title="授权菜单", Permission="sysTenant:grantMenu", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002316, Pid=252885263002310, Title="重置密码", Permission="sysTenant:resetPwd", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002320, Pid=252885263002300, Title="系统配置", Path="config", Name="ConfigManagement", Component="/sys/admin/config/index", Icon="ant-design:deployment-unit-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=110 },
-//            new SysMenu{ Id=252885263002321, Pid=252885263002320, Title="配置查询", Permission="sysConfig:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002322, Pid=252885263002320, Title="配置编辑", Permission="sysConfig:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002323, Pid=252885263002320, Title="配置增加", Permission="sysConfig:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002324, Pid=252885263002320, Title="配置删除", Permission="sysConfig:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002330, Pid=252885263002300, Title="字典管理", Path="dict", Name="DictManagement", Component="/sys/admin/dict/index", Icon="ant-design:book-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=120 },
-//            new SysMenu{ Id=252885263002331, Pid=252885263002330, Title="字典查询", Permission="sysDict:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002332, Pid=252885263002330, Title="字典编辑", Permission="sysDict:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002333, Pid=252885263002330, Title="字典增加", Permission="sysDict:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002334, Pid=252885263002330, Title="字典删除", Permission="sysDict:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002340, Pid=252885263002300, Title="任务调度", Path="timer", Name="TimerManagement", Component="/sys/admin/timer/index", Icon="ant-design:clock-circle-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=130 },
-//            new SysMenu{ Id=252885263002341, Pid=252885263002340, Title="任务查询", Permission="sysTimer:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002342, Pid=252885263002340, Title="任务编辑", Permission="sysTimer:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002343, Pid=252885263002340, Title="任务增加", Permission="sysTimer:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002344, Pid=252885263002340, Title="任务删除", Permission="sysTimer:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002345, Pid=252885263002340, Title="设置状态", Permission="sysTimer:setStatus", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002350, Pid=252885263002300, Title="在线用户", Path="online", Name="OnlineManagement", Component="/sys/admin/online/index", Icon="ant-design:user-switch-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=140 },
-//            new SysMenu{ Id=252885263002351, Pid=252885263002350, Title="用户查询", Permission="online:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002352, Pid=252885263002350, Title="用户删除", Permission="online:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002353, Pid=252885263002350, Title="强制下线", Permission="online:ForceExistUser", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002360, Pid=252885263002300, Title="系统监控", Path="server", Name="ServerManagement", Component="/sys/admin/server/index", Icon="ant-design:alert-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=150 },
-
-//            new SysMenu{ Id=252885263002370, Pid=252885263002300, Title="缓存管理", Path="cache", Name="CacheManagement", Component="/sys/admin/cache/index", Icon="ant-design:thunderbolt-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=160 },
-//            new SysMenu{ Id=252885263002371, Pid=252885263002370, Title="缓存查询", Permission="cache:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002372, Pid=252885263002370, Title="缓存删除", Permission="cache:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002380, Pid=252885263002300, Title="数据资源", Path="dataResource", Name="DataResourceManagement", Component="/sys/admin/dataResource/index", Icon="ant-design:funnel-plot-filled", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-05-30 00:00:00"), Order=170 },
-//            new SysMenu{ Id=252885263002381, Pid=252885263002380, Title="资源查询", Permission="sysDataResource:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-05-30 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002382, Pid=252885263002380, Title="资源编辑", Permission="sysDataResource:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-05-30 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002383, Pid=252885263002380, Title="资源增加", Permission="sysDataResource:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-05-30 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002384, Pid=252885263002380, Title="资源删除", Permission="sysDataResource:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-05-30 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002390, Pid=252885263002300, Title="文件管理", Path="file", Name="FileManagement", Component="/sys/admin/file/index", Icon="ant-design:file-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=180 },
-//            new SysMenu{ Id=252885263002391, Pid=252885263002390, Title="文件查询", Permission="sysFile:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002392, Pid=252885263002390, Title="文件上传", Permission="sysFile:upload", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002393, Pid=252885263002390, Title="文件下载", Permission="sysFile:download", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002394, Pid=252885263002390, Title="文件删除", Permission="sysFile:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002500, Pid=0, Title="日志管理", Path="/log", Name="log", Component="LAYOUT", Redirect="", Icon="ant-design:carry-out-outlined", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=300 },
-//            new SysMenu{ Id=252885263002510, Pid=252885263002500, Title="访问日志", Path="vislog", Name="VislogManagement", Component="/sys/admin/log/vislog/index", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002511, Pid=252885263002510, Title="日志查询", Permission="sysVislog:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002512, Pid=252885263002510, Title="日志清空", Permission="sysVislog:clear", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002520, Pid=252885263002500, Title="操作日志", Path="oplog", Name="OplogManagement", Component="/sys/admin/log/oplog/index", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=110 },
-//            new SysMenu{ Id=252885263002521, Pid=252885263002520, Title="日志查询", Permission="sysOplog:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002522, Pid=252885263002520, Title="日志清空", Permission="sysOplog:clear", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002530, Pid=252885263002500, Title="异常日志", Path="exlog", Name="ExlogManagement", Component="/sys/admin/log/exlog/index", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=120 },
-//            new SysMenu{ Id=252885263002531, Pid=252885263002530, Title="日志查询", Permission="sysExlog:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002532, Pid=252885263002530, Title="日志清空", Permission="sysExlog:clear", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002540, Pid=252885263002500, Title="差异日志", Path="difflog", Name="DifflogManagement", Component="/sys/admin/log/difflog/index", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=130 },
-//            new SysMenu{ Id=252885263002541, Pid=252885263002540, Title="日志查询", Permission="sysDifflog:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002542, Pid=252885263002540, Title="日志清空", Permission="sysDifflog:clear", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
-//            new SysMenu{ Id=252885263002600, Pid=0, Title="开发工具", Path="/develop", Name="develop", Component="LAYOUT", Redirect="", Icon="ant-design:bug-outlined", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=400 },
-//            new SysMenu{ Id=252885263002610, Pid=252885263002600, Title="接口文档", Path="api", Name="Api", FrameSrc="https://localhost:44326/api/", Component="IFrame", Icon="ant-design:api-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002612, Pid=252885263002600, Title="代码生成", Path="code", Name="CodeManagement", Component="/sys/admin/code/index", Icon="ant-design:bug-outlined", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=102 },
-//            new SysMenu{ Id=252885263002613, Pid=252885263002600, Title="库表管理", Path="database", Name="DbManagement", Component="/sys/admin/database/index",Icon="ant-design:database-filled", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=103 },
-
-//            new SysMenu{ Id=252885263002700, Pid=0, Title="帮助文档", Path="/doc", Name="doc", Component="LAYOUT", Redirect="", Icon="ant-design:read-outlined", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=500 },
-//            new SysMenu{ Id=252885263002710, Pid=252885263002700, Title="后台教程", Path="https://dotnetchina.gitee.io/furion/", Name="Furion", Component="IFrame", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-//            new SysMenu{ Id=252885263002711, Pid=252885263002700, Title="前端教程", Path="https://vvbin.cn/doc-next/", Name="Vben", Component="IFrame", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=101 },
-//        };
-//    }
-//}

+ 1 - 5
Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs

@@ -28,6 +28,7 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
             new SysMenu{ Id=252885263002216, Pid=252885263002210, Title="授权数据", Permission="sysUser:grantData", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
             new SysMenu{ Id=252885263002217, Pid=252885263002210, Title="重置密码", Permission="sysUser:resetPwd", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
             new SysMenu{ Id=252885263002218, Pid=252885263002210, Title="设置状态", Permission="sysUser:setStatus", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
+            new SysMenu{ Id=252885263002219, Pid=252885263002210, Title="强制下线", Permission="sysUser:forceOffline", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
 
             new SysMenu{ Id=252885263002220, Pid=252885263002200, Title="角色管理", Path="/system/role", Name="sysRole", Component="/system/role/index", Icon="ele-UserFilled", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=110 },
             new SysMenu{ Id=252885263002221, Pid=252885263002220, Title="角色查询", Permission="sysRole:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
@@ -87,11 +88,6 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
             new SysMenu{ Id=252885263002344, Pid=252885263002340, Title="任务删除", Permission="sysTimer:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
             new SysMenu{ Id=252885263002345, Pid=252885263002340, Title="设置状态", Permission="sysTimer:setStatus", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
 
-            new SysMenu{ Id=252885263002350, Pid=252885263002300, Title="在线用户", Path="/platform/online", Name="sysOnline", Component="/system/online/index", Icon="ele-Sunny", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=140 },
-            new SysMenu{ Id=252885263002351, Pid=252885263002350, Title="用户查询", Permission="online:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-            new SysMenu{ Id=252885263002352, Pid=252885263002350, Title="用户删除", Permission="online:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-            new SysMenu{ Id=252885263002353, Pid=252885263002350, Title="强制下线", Permission="online:ForceExistUser", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=100 },
-
             new SysMenu{ Id=252885263002360, Pid=252885263002300, Title="系统监控", Path="/platform/server", Name="sysServer", Component="/system/server/index", Icon="ele-Monitor", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=150 },
 
             new SysMenu{ Id=252885263002370, Pid=252885263002300, Title="缓存管理", Path="/platform/cache", Name="sysCache", Component="/system/cache/index", Icon="ele-Loading", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), Order=160 },

+ 4 - 4
Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs

@@ -18,7 +18,7 @@ public class SysAuthService : IDynamicApiController, ITransient
     private readonly SysUserService _sysUserService;
     private readonly SysUserRoleService _sysUserRoleService;
     private readonly SysMenuService _sysMenuService;
-    private readonly ISysOnlineUserService _sysOnlineUserService;
+    private readonly SysOnlineUserService _sysOnlineUserService;
     private readonly IMemoryCache _cache;
     private readonly ICaptcha _captcha;
 
@@ -30,7 +30,7 @@ public class SysAuthService : IDynamicApiController, ITransient
         SysUserService sysUserService,
         SysUserRoleService sysUserRoleService,
         SysMenuService sysMenuService,
-        ISysOnlineUserService sysOnlineUserService,
+        SysOnlineUserService sysOnlineUserService,
         IMemoryCache cache,
         ICaptcha captcha)
     {
@@ -51,7 +51,7 @@ public class SysAuthService : IDynamicApiController, ITransient
     /// 登录系统
     /// </summary>
     /// <param name="input"></param>
-    /// <remarks>用户名/密码:vben/123456</remarks>
+    /// <remarks>用户名/密码:superadmin/123456</remarks>
     /// <returns></returns>
     [HttpPost("/login")]
     [AllowAnonymous]
@@ -173,7 +173,7 @@ public class SysAuthService : IDynamicApiController, ITransient
     /// <summary>
     /// 退出系统
     /// </summary>
-    [HttpGet("/logout")]
+    [HttpPost("/logout")]
     public async void Logout()
     {
         var user = _userManager.User;

+ 0 - 116
Admin.NET/Admin.NET.Core/Service/Menu/Dto/MenuOutput - vben.cs

@@ -1,116 +0,0 @@
-//namespace Admin.NET.Core.Service;
-
-///// <summary>
-///// 系统菜单返回结果
-///// </summary>
-//public class MenuOutput
-//{
-//    /// <summary>
-//    /// Id
-//    /// </summary>
-//    public long Id { get; set; }
-
-//    /// <summary>
-//    /// 父Id
-//    /// </summary>
-//    public long Pid { get; set; }
-
-//    /// <summary>
-//    /// 菜单类型(0目录 1菜单 2按钮)
-//    /// </summary>
-//    public MenuTypeEnum Type { get; set; }
-
-//    /// <summary>
-//    /// 名称
-//    /// </summary>
-//    public string Name { get; set; }
-
-//    /// <summary>
-//    /// 路由地址
-//    /// </summary>
-//    public string Path { get; set; }
-
-//    /// <summary>
-//    /// 组件路径
-//    /// </summary>
-//    public string Component { get; set; }
-
-//    /// <summary>
-//    /// 权限标识
-//    /// </summary>
-//    public string Permission { get; set; }
-
-//    /// <summary>
-//    /// 重定向
-//    /// </summary>
-//    public string Redirect { get; set; }
-
-//    /// <summary>
-//    /// 菜单Meta
-//    /// </summary>
-//    public SysMenuMeta Meta { get; set; }
-
-//    /// <summary>
-//    /// 菜单子项
-//    /// </summary>
-//    public List<MenuOutput> Children { get; set; }
-//}
-
-///// <summary>
-///// 菜单Meta配置
-///// </summary>
-//public class SysMenuMeta
-//{
-//    /// <summary>
-//    /// 标题
-//    /// </summary>
-//    public string Title { get; set; }
-
-//    /// <summary>
-//    /// 图标
-//    /// </summary>
-//    public string Icon { get; set; }
-
-//    /// <summary>
-//    /// 内嵌地址
-//    /// </summary>
-//    public string FrameSrc { get; set; }
-
-//    /// <summary>
-//    /// 排序
-//    /// </summary>
-//    public int OrderNo { get; set; }
-
-//    /// <summary>
-//    /// 是否显示
-//    /// </summary>
-//    public bool HideMenu { get; set; }
-
-//    /// <summary>
-//    /// 是否忽略KeepAlive缓存
-//    /// </summary>
-//    public bool IgnoreKeepAlive { get; set; }
-
-//    /// <summary>
-//    /// 当前激活的菜单-用于配置详情页时左侧激活的菜单路径
-//    /// </summary>
-//    public string CurrentActiveMenu { get; set; }
-//}
-
-///// <summary>
-///// 配置菜单对象映射
-///// </summary>
-//public class SysMenuMapper : IRegister
-//{
-//    public void Register(TypeAdapterConfig config)
-//    {
-//        config.ForType<SysMenu, MenuOutput>()
-//            .Map(t => t.Meta.Title, o => o.Title)
-//            .Map(t => t.Meta.Icon, o => o.Icon)
-//            .Map(t => t.Meta.FrameSrc, o => o.FrameSrc)
-//            .Map(t => t.Meta.OrderNo, o => o.Order)
-//            .Map(t => t.Meta.HideMenu, o => o.HideMenu)
-//            .Map(t => t.Meta.IgnoreKeepAlive, o => o.IgnoreKeepAlive)
-//            .Map(t => t.Meta.CurrentActiveMenu, o => o.CurrentActiveMenu);
-//    }
-//}

+ 4 - 4
Admin.NET/Admin.NET.Core/Service/Message/Dto/MessageInput.cs

@@ -18,12 +18,12 @@ public class MessageInput
     public string Title { get; set; }
 
     /// <summary>
-    /// 消息内容
+    /// 消息类型
     /// </summary>
-    public string Message { get; set; }
+    public MessageTypeEnum MessageType { get; set; }
 
     /// <summary>
-    /// 消息类型
+    /// 消息内容
     /// </summary>
-    public MessageTypeEnum MessageType { get; set; }
+    public string Message { get; set; }
 }

+ 0 - 39
Admin.NET/Admin.NET.Core/Service/Message/ISysMessageService.cs

@@ -1,39 +0,0 @@
-namespace Admin.NET.Core.Service;
-
-public interface ISysMessageService
-{
-    /// <summary>
-    /// 发送消息给所有人
-    /// </summary>
-    /// <param name="input"></param>
-    /// <returns></returns>
-    Task SendMessageToAllUser(MessageInput input);
-
-    /// <summary>
-    /// 发送消息给某个人
-    /// </summary>
-    /// <param name="input"></param>
-    /// <returns></returns>
-    Task SendMessageToUser(MessageInput input);
-
-    /// <summary>
-    /// 发送消息给某些人
-    /// </summary>
-    /// <param name="input"></param>
-    /// <returns></returns>
-    Task SendMessageToUsers(MessageInput input);
-
-    /// <summary>
-    /// 发送消息给除了发送人的其他人
-    /// </summary>
-    /// <param name="input"></param>
-    /// <returns></returns>
-    Task SendMessageToOtherUser(MessageInput input);
-
-    /// <summary>
-    /// 发送邮件
-    /// </summary>
-    /// <param name="message"></param>
-    /// <returns></returns>
-    Task SendEmail(string message);
-}

+ 6 - 7
Admin.NET/Admin.NET.Core/Service/Message/SysMessageService.cs

@@ -7,23 +7,22 @@ namespace Admin.NET.Core.Service;
 /// 系统消息发送服务
 /// </summary>
 [ApiDescriptionSettings(Order = 101)]
-public class SysMessageService : ISysMessageService, IDynamicApiController, ITransient
+public class SysMessageService : IDynamicApiController, ITransient
 {
     private readonly SysCacheService _sysCacheService;
-    private readonly IHubContext<ChatHub, IChatClient> _chatHubContext;
-
     private readonly EmailOptions _emailOptions;
     private readonly IEmailService _emailService;
+    private readonly IHubContext<OnlineUserHub, IOnlineUserHub> _chatHubContext;
 
     public SysMessageService(SysCacheService sysCacheService,
-        IHubContext<ChatHub, IChatClient> chatHubContext,
         IOptions<EmailOptions> emailOptions,
-        IEmailService emailService)
+        IEmailService emailService,
+        IHubContext<OnlineUserHub, IOnlineUserHub> chatHubContext)
     {
         _sysCacheService = sysCacheService;
-        _chatHubContext = chatHubContext;
         _emailOptions = emailOptions.Value;
         _emailService = emailService;
+        _chatHubContext = chatHubContext;
     }
 
     /// <summary>
@@ -97,7 +96,7 @@ public class SysMessageService : ISysMessageService, IDynamicApiController, ITra
     /// </summary>
     /// <param name="message"></param>
     /// <returns></returns>
-    [HttpPost("/email/send")]
+    [HttpPost("/sysEmail/send")]
     public async Task SendEmail(string message)
     {
         //// 设置发送人邮件地址和名称

+ 10 - 11
Admin.NET/Admin.NET.Core/Service/Notice/SysNoticeService.cs

@@ -6,24 +6,23 @@
 [ApiDescriptionSettings(Order = 100)]
 public class SysNoticeService : ISysNoticeService, IDynamicApiController, ITransient
 {
+    private readonly SqlSugarRepository<SysUser> _sysUserRep;
     private readonly SqlSugarRepository<SysNotice> _sysNoticeRep;
-    private readonly ISysOnlineUserService _sysOnlineUserService;
 
+    private readonly SysOnlineUserService _sysOnlineUserService;
     private readonly ISysNoticeUserService _sysNoticeUserService;
-    private readonly SqlSugarRepository<SysUser> _sysUserRep;
-
     private readonly IUserManager _userManager;
 
-    public SysNoticeService(SqlSugarRepository<SysNotice> sysNoticeRep,
+    public SysNoticeService(SqlSugarRepository<SysUser> sysUserRep,
+        SqlSugarRepository<SysNotice> sysNoticeRep,
+        SysOnlineUserService sysOnlineUserService,
         ISysNoticeUserService sysNoticeUserService,
-        ISysOnlineUserService sysOnlineUserService,
-        SqlSugarRepository<SysUser> sysUserRep,
         IUserManager userManager)
     {
+        _sysUserRep = sysUserRep;
         _sysNoticeRep = sysNoticeRep;
-        _sysNoticeUserService = sysNoticeUserService;
         _sysOnlineUserService = sysOnlineUserService;
-        _sysUserRep = sysUserRep;
+        _sysNoticeUserService = sysNoticeUserService;
         _userManager = userManager;
     }
 
@@ -67,7 +66,7 @@ public class SysNoticeService : ISysNoticeService, IDynamicApiController, ITrans
         await _sysNoticeUserService.Add(newItem.Id, noticeUserIdList, noticeUserStatus);
         if (newItem.Status == NoticeStatusEnum.PUBLIC)
         {
-            await _sysOnlineUserService.PushNotice(newItem, noticeUserIdList);
+            await _sysOnlineUserService.AppendNotice(newItem, noticeUserIdList);
         }
     }
 
@@ -115,7 +114,7 @@ public class SysNoticeService : ISysNoticeService, IDynamicApiController, ITrans
         await _sysNoticeUserService.Update(input.Id, noticeUserIdList, noticeUserStatus);
         if (notice.Status == NoticeStatusEnum.PUBLIC)
         {
-            await _sysOnlineUserService.PushNotice(notice, noticeUserIdList);
+            await _sysOnlineUserService.AppendNotice(notice, noticeUserIdList);
         }
     }
 
@@ -185,7 +184,7 @@ public class SysNoticeService : ISysNoticeService, IDynamicApiController, ITrans
         {
             // 获取通知到的用户
             var noticeUserList = await _sysNoticeUserService.GetNoticeUserListByNoticeId(input.Id);
-            await _sysOnlineUserService.PushNotice(notice, noticeUserList.Select(m => m.UserId).ToList());
+            await _sysOnlineUserService.AppendNotice(notice, noticeUserList.Select(m => m.UserId).ToList());
         }
     }
 

+ 14 - 0
Admin.NET/Admin.NET.Core/Service/OnlineUser/Dto/OnlineUserInput.cs

@@ -0,0 +1,14 @@
+namespace Admin.NET.Core.Service;
+
+public class PageOnlineUserInput : BasePageInput
+{
+    /// <summary>
+    /// 账号名称
+    /// </summary>
+    public string UserName { get; set; }
+
+    /// <summary>
+    /// 真实姓名
+    /// </summary>
+    public string RealName { get; set; }
+}

+ 0 - 12
Admin.NET/Admin.NET.Core/Service/OnlineUser/ISysOnlineUserService.cs

@@ -1,12 +0,0 @@
-namespace Admin.NET.Core.Service;
-
-public interface ISysOnlineUserService
-{
-    Task<dynamic> List(BasePageInput input);
-
-    Task ForceExist(SysOnlineUser user);
-
-    Task PushNotice(SysNotice notice, List<long> userIds);
-
-    Task SignleLogin(long userId);
-}

+ 23 - 21
Admin.NET/Admin.NET.Core/Service/OnlineUser/SysOnlineUserService.cs

@@ -6,29 +6,32 @@ namespace Admin.NET.Core.Service;
 /// 系统在线用户服务
 /// </summary>
 [ApiDescriptionSettings(Order = 100)]
-public class SysOnlineUserService : ISysOnlineUserService, IDynamicApiController, ITransient
+public class SysOnlineUserService : IDynamicApiController, ITransient
 {
-    private readonly SqlSugarRepository<SysOnlineUser> _sysOnlineUerRep;
-    private readonly IHubContext<ChatHub, IChatClient> _chatHubContext;
+    private readonly SqlSugarRepository<SysOnlineUser> _sysOnlineUerRep;    
     private readonly SysConfigService _sysConfigService;
+    private readonly IHubContext<OnlineUserHub, IOnlineUserHub> _onlineUserHubContext;
 
     public SysOnlineUserService(SqlSugarRepository<SysOnlineUser> sysOnlineUerRep,
-        IHubContext<ChatHub, IChatClient> chatHubContext,
-        SysConfigService sysConfigService)
+        SysConfigService sysConfigService,
+        IHubContext<OnlineUserHub, IOnlineUserHub> onlineUserHubContext)
     {
         _sysOnlineUerRep = sysOnlineUerRep;
-        _chatHubContext = chatHubContext;
         _sysConfigService = sysConfigService;
+        _onlineUserHubContext = onlineUserHubContext;
     }
 
     /// <summary>
-    /// 获取在线用户信息
+    /// 获取在线用户分页列表
     /// </summary>
     /// <returns></returns>
     [HttpGet("/sysOnlineUser/page")]
-    public async Task<dynamic> List([FromQuery] BasePageInput input)
+    public async Task<dynamic> GetOnlineUserPage([FromQuery] PageOnlineUserInput input)
     {
-        return await _sysOnlineUerRep.AsQueryable().ToPagedListAsync(input.Page, input.PageSize);
+        return await _sysOnlineUerRep.AsQueryable()
+            .WhereIF(!string.IsNullOrWhiteSpace(input.UserName), u => u.UserName.Contains(input.UserName))
+            .WhereIF(!string.IsNullOrWhiteSpace(input.RealName), u => u.RealName.Contains(input.RealName))
+            .ToPagedListAsync(input.Page, input.PageSize);
     }
 
     /// <summary>
@@ -36,11 +39,11 @@ public class SysOnlineUserService : ISysOnlineUserService, IDynamicApiController
     /// </summary>
     /// <param name="user"></param>
     /// <returns></returns>
-    [HttpPost("/sysOnlineUser/forceExist")]
+    [HttpPost("/sysOnlineUser/forceOffline")]
     [NonValidation]
-    public async Task ForceExist(SysOnlineUser user)
+    public async Task ForceOffline(SysOnlineUser user)
     {
-        await _chatHubContext.Clients.Client(user.ConnectionId).ForceExist("00000000");
+        await _onlineUserHubContext.Clients.Client(user.ConnectionId).ForceOffline("强制下线");
         await _sysOnlineUerRep.DeleteAsync(user);
     }
 
@@ -51,15 +54,14 @@ public class SysOnlineUserService : ISysOnlineUserService, IDynamicApiController
     /// <param name="userIds"></param>
     /// <returns></returns>
     [NonAction]
-    public async Task PushNotice(SysNotice notice, List<long> userIds)
+    public async Task AppendNotice(SysNotice notice, List<long> userIds)
     {
         var userList = await _sysOnlineUerRep.GetListAsync(m => userIds.Contains(m.UserId));
-        if (userList.Any())
+        if (!userList.Any()) return;
+
+        foreach (var item in userList)
         {
-            foreach (var item in userList)
-            {
-                await _chatHubContext.Clients.Client(item.ConnectionId).AppendNotice(notice);
-            }
+            await _onlineUserHubContext.Clients.Client(item.ConnectionId).AppendNotice(notice);
         }
     }
 
@@ -72,10 +74,10 @@ public class SysOnlineUserService : ISysOnlineUserService, IDynamicApiController
     {
         if (await _sysConfigService.GetConfigValue<bool>(CommonConst.SysSingleLogin))
         {
-            var loginUser = await _sysOnlineUerRep.GetFirstAsync(u => u.UserId == userId);
-            if (loginUser == null) return;
+            var user = await _sysOnlineUerRep.GetFirstAsync(u => u.UserId == userId);
+            if (user == null) return;
 
-            await ForceExist(loginUser);
+            await ForceOffline(user);
         }
     }
 }

+ 1 - 0
Admin.NET/Admin.NET.Core/Util/DateTimeUtil.cs

@@ -6,6 +6,7 @@ public class DateTimeUtil
     /// 获取开始时间
     /// </summary>
     /// <param name="dateTime"></param>
+    /// <param name="days"></param>
     /// <returns></returns>
     public static DateTime GetBeginTime(DateTime? dateTime, int days = 0)
     {

+ 1 - 1
Web/.env.development

@@ -1,5 +1,5 @@
 # 本地环境
 ENV = 'development'
 
-# 本地环境接口地址 // 'https://localhost:5005'
+# 本地环境接口地址
 VITE_API_URL = 'https://localhost:44326'

+ 1 - 1
Web/.env.production

@@ -2,4 +2,4 @@
 ENV = 'production'
 
 # 线上环境接口地址
-VITE_API_URL = 'https://*:5005'
+VITE_API_URL = 'https://localhost:5005'

+ 1 - 0
Web/package.json

@@ -12,6 +12,7 @@
 	"dependencies": {
 		"@element-plus/icons-vue": "^2.0.6",
 		"@wangeditor/editor": "^5.1.11",
+		"@microsoft/signalr": "^6.0.10",
 		"axios": "^0.27.2",
 		"countup.js": "^2.3.2",
 		"cropperjs": "^1.5.12",

+ 12 - 12
Web/src/api-services/apis/sys-auth-api.ts

@@ -145,7 +145,7 @@ export const SysAuthApiAxiosParamCreator = function (configuration?: Configurati
             };
         },
         /**
-         * 用户名/密码:vben/123456
+         * 用户名/密码:superadmin/123456
          * @summary 登录系统
          * @param {LoginInput} body 
          * @param {*} [options] Override http request option.
@@ -195,7 +195,7 @@ export const SysAuthApiAxiosParamCreator = function (configuration?: Configurati
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        logoutGet: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+        logoutPost: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
             const localVarPath = `/logout`;
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
@@ -203,7 +203,7 @@ export const SysAuthApiAxiosParamCreator = function (configuration?: Configurati
             if (configuration) {
                 baseOptions = configuration.baseOptions;
             }
-            const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
+            const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
             const localVarHeaderParameter = {} as any;
             const localVarQueryParameter = {} as any;
 
@@ -361,7 +361,7 @@ export const SysAuthApiFp = function(configuration?: Configuration) {
             };
         },
         /**
-         * 用户名/密码:vben/123456
+         * 用户名/密码:superadmin/123456
          * @summary 登录系统
          * @param {LoginInput} body 
          * @param {*} [options] Override http request option.
@@ -380,8 +380,8 @@ export const SysAuthApiFp = function(configuration?: Configuration) {
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async logoutGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
-            const localVarAxiosArgs = await SysAuthApiAxiosParamCreator(configuration).logoutGet(options);
+        async logoutPost(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysAuthApiAxiosParamCreator(configuration).logoutPost(options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
                 return axios.request(axiosRequestArgs);
@@ -453,7 +453,7 @@ export const SysAuthApiFactory = function (configuration?: Configuration, basePa
             return SysAuthApiFp(configuration).getUserInfoGet(options).then((request) => request(axios, basePath));
         },
         /**
-         * 用户名/密码:vben/123456
+         * 用户名/密码:superadmin/123456
          * @summary 登录系统
          * @param {LoginInput} body 
          * @param {*} [options] Override http request option.
@@ -468,8 +468,8 @@ export const SysAuthApiFactory = function (configuration?: Configuration, basePa
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async logoutGet(options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
-            return SysAuthApiFp(configuration).logoutGet(options).then((request) => request(axios, basePath));
+        async logoutPost(options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysAuthApiFp(configuration).logoutPost(options).then((request) => request(axios, basePath));
         },
         /**
          * 
@@ -533,7 +533,7 @@ export class SysAuthApi extends BaseAPI {
         return SysAuthApiFp(this.configuration).getUserInfoGet(options).then((request) => request(this.axios, this.basePath));
     }
     /**
-     * 用户名/密码:vben/123456
+     * 用户名/密码:superadmin/123456
      * @summary 登录系统
      * @param {LoginInput} body 
      * @param {*} [options] Override http request option.
@@ -550,8 +550,8 @@ export class SysAuthApi extends BaseAPI {
      * @throws {RequiredError}
      * @memberof SysAuthApi
      */
-    public async logoutGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
-        return SysAuthApiFp(this.configuration).logoutGet(options).then((request) => request(this.axios, this.basePath));
+    public async logoutPost(options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysAuthApiFp(this.configuration).logoutPost(options).then((request) => request(this.axios, this.basePath));
     }
     /**
      * 

+ 8 - 8
Web/src/api-services/apis/sys-message-api.ts

@@ -30,8 +30,8 @@ export const SysMessageApiAxiosParamCreator = function (configuration?: Configur
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        emailSendPost: async (message?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
-            const localVarPath = `/email/send`;
+        sysEmailSendPost: async (message?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/sysEmail/send`;
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
             let baseOptions;
@@ -244,8 +244,8 @@ export const SysMessageApiFp = function(configuration?: Configuration) {
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async emailSendPost(message?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
-            const localVarAxiosArgs = await SysMessageApiAxiosParamCreator(configuration).emailSendPost(message, options);
+        async sysEmailSendPost(message?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysMessageApiAxiosParamCreator(configuration).sysEmailSendPost(message, options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
                 return axios.request(axiosRequestArgs);
@@ -323,8 +323,8 @@ export const SysMessageApiFactory = function (configuration?: Configuration, bas
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async emailSendPost(message?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
-            return SysMessageApiFp(configuration).emailSendPost(message, options).then((request) => request(axios, basePath));
+        async sysEmailSendPost(message?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysMessageApiFp(configuration).sysEmailSendPost(message, options).then((request) => request(axios, basePath));
         },
         /**
          * 
@@ -384,8 +384,8 @@ export class SysMessageApi extends BaseAPI {
      * @throws {RequiredError}
      * @memberof SysMessageApi
      */
-    public async emailSendPost(message?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
-        return SysMessageApiFp(this.configuration).emailSendPost(message, options).then((request) => request(this.axios, this.basePath));
+    public async sysEmailSendPost(message?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysMessageApiFp(this.configuration).sysEmailSendPost(message, options).then((request) => request(this.axios, this.basePath));
     }
     /**
      * 

+ 35 - 19
Web/src/api-services/apis/sys-online-user-api.ts

@@ -31,8 +31,8 @@ export const SysOnlineUserApiAxiosParamCreator = function (configuration?: Confi
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        sysOnlineUserForceExistPost: async (body?: SysOnlineUser, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
-            const localVarPath = `/sysOnlineUser/forceExist`;
+        sysOnlineUserForceOfflinePost: async (body?: SysOnlineUser, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/sysOnlineUser/forceOffline`;
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
             let baseOptions;
@@ -67,7 +67,9 @@ export const SysOnlineUserApiAxiosParamCreator = function (configuration?: Confi
         },
         /**
          * 
-         * @summary 获取在线用户信息
+         * @summary 获取在线用户分页列表
+         * @param {string} [userName] 账号名称
+         * @param {string} [realName] 真实姓名
          * @param {number} [page] 当前页码
          * @param {number} [pageSize] 页码容量
          * @param {string} [field] 排序字段
@@ -76,7 +78,7 @@ export const SysOnlineUserApiAxiosParamCreator = function (configuration?: Confi
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        sysOnlineUserPageGet: async (page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+        sysOnlineUserPageGet: async (userName?: string, realName?: string, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
             const localVarPath = `/sysOnlineUser/page`;
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
@@ -90,6 +92,14 @@ export const SysOnlineUserApiAxiosParamCreator = function (configuration?: Confi
 
             // authentication Bearer required
 
+            if (userName !== undefined) {
+                localVarQueryParameter['UserName'] = userName;
+            }
+
+            if (realName !== undefined) {
+                localVarQueryParameter['RealName'] = realName;
+            }
+
             if (page !== undefined) {
                 localVarQueryParameter['Page'] = page;
             }
@@ -142,8 +152,8 @@ export const SysOnlineUserApiFp = function(configuration?: Configuration) {
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async sysOnlineUserForceExistPost(body?: SysOnlineUser, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
-            const localVarAxiosArgs = await SysOnlineUserApiAxiosParamCreator(configuration).sysOnlineUserForceExistPost(body, options);
+        async sysOnlineUserForceOfflinePost(body?: SysOnlineUser, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysOnlineUserApiAxiosParamCreator(configuration).sysOnlineUserForceOfflinePost(body, options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
                 return axios.request(axiosRequestArgs);
@@ -151,7 +161,9 @@ export const SysOnlineUserApiFp = function(configuration?: Configuration) {
         },
         /**
          * 
-         * @summary 获取在线用户信息
+         * @summary 获取在线用户分页列表
+         * @param {string} [userName] 账号名称
+         * @param {string} [realName] 真实姓名
          * @param {number} [page] 当前页码
          * @param {number} [pageSize] 页码容量
          * @param {string} [field] 排序字段
@@ -160,8 +172,8 @@ export const SysOnlineUserApiFp = function(configuration?: Configuration) {
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async sysOnlineUserPageGet(page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultObject>>> {
-            const localVarAxiosArgs = await SysOnlineUserApiAxiosParamCreator(configuration).sysOnlineUserPageGet(page, pageSize, field, order, descStr, options);
+        async sysOnlineUserPageGet(userName?: string, realName?: string, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultObject>>> {
+            const localVarAxiosArgs = await SysOnlineUserApiAxiosParamCreator(configuration).sysOnlineUserPageGet(userName, realName, page, pageSize, field, order, descStr, options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
                 return axios.request(axiosRequestArgs);
@@ -183,12 +195,14 @@ export const SysOnlineUserApiFactory = function (configuration?: Configuration,
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async sysOnlineUserForceExistPost(body?: SysOnlineUser, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
-            return SysOnlineUserApiFp(configuration).sysOnlineUserForceExistPost(body, options).then((request) => request(axios, basePath));
+        async sysOnlineUserForceOfflinePost(body?: SysOnlineUser, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysOnlineUserApiFp(configuration).sysOnlineUserForceOfflinePost(body, options).then((request) => request(axios, basePath));
         },
         /**
          * 
-         * @summary 获取在线用户信息
+         * @summary 获取在线用户分页列表
+         * @param {string} [userName] 账号名称
+         * @param {string} [realName] 真实姓名
          * @param {number} [page] 当前页码
          * @param {number} [pageSize] 页码容量
          * @param {string} [field] 排序字段
@@ -197,8 +211,8 @@ export const SysOnlineUserApiFactory = function (configuration?: Configuration,
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async sysOnlineUserPageGet(page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultObject>> {
-            return SysOnlineUserApiFp(configuration).sysOnlineUserPageGet(page, pageSize, field, order, descStr, options).then((request) => request(axios, basePath));
+        async sysOnlineUserPageGet(userName?: string, realName?: string, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultObject>> {
+            return SysOnlineUserApiFp(configuration).sysOnlineUserPageGet(userName, realName, page, pageSize, field, order, descStr, options).then((request) => request(axios, basePath));
         },
     };
 };
@@ -218,12 +232,14 @@ export class SysOnlineUserApi extends BaseAPI {
      * @throws {RequiredError}
      * @memberof SysOnlineUserApi
      */
-    public async sysOnlineUserForceExistPost(body?: SysOnlineUser, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
-        return SysOnlineUserApiFp(this.configuration).sysOnlineUserForceExistPost(body, options).then((request) => request(this.axios, this.basePath));
+    public async sysOnlineUserForceOfflinePost(body?: SysOnlineUser, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysOnlineUserApiFp(this.configuration).sysOnlineUserForceOfflinePost(body, options).then((request) => request(this.axios, this.basePath));
     }
     /**
      * 
-     * @summary 获取在线用户信息
+     * @summary 获取在线用户分页列表
+     * @param {string} [userName] 账号名称
+     * @param {string} [realName] 真实姓名
      * @param {number} [page] 当前页码
      * @param {number} [pageSize] 页码容量
      * @param {string} [field] 排序字段
@@ -233,7 +249,7 @@ export class SysOnlineUserApi extends BaseAPI {
      * @throws {RequiredError}
      * @memberof SysOnlineUserApi
      */
-    public async sysOnlineUserPageGet(page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultObject>> {
-        return SysOnlineUserApiFp(this.configuration).sysOnlineUserPageGet(page, pageSize, field, order, descStr, options).then((request) => request(this.axios, this.basePath));
+    public async sysOnlineUserPageGet(userName?: string, realName?: string, page?: number, pageSize?: number, field?: string, order?: string, descStr?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultObject>> {
+        return SysOnlineUserApiFp(this.configuration).sysOnlineUserPageGet(userName, realName, page, pageSize, field, order, descStr, options).then((request) => request(this.axios, this.basePath));
     }
 }

+ 6 - 6
Web/src/api-services/models/message-input.ts

@@ -36,16 +36,16 @@ export interface MessageInput {
      * @memberof MessageInput
      */
     title?: string | null;
-    /**
-     * 消息内容
-     * @type {string}
-     * @memberof MessageInput
-     */
-    message?: string | null;
     /**
      * 
      * @type {MessageTypeEnum}
      * @memberof MessageInput
      */
     messageType?: MessageTypeEnum;
+    /**
+     * 消息内容
+     * @type {string}
+     * @memberof MessageInput
+     */
+    message?: string | null;
 }

+ 17 - 17
Web/src/api-services/models/sys-online-user.ts

@@ -23,6 +23,12 @@ export interface SysOnlineUser {
      * @memberof SysOnlineUser
      */
     id?: number;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof SysOnlineUser
+     */
+    tenantId?: number | null;
     /**
      * 连接Id
      * @type {string}
@@ -40,41 +46,35 @@ export interface SysOnlineUser {
      * @type {string}
      * @memberof SysOnlineUser
      */
-    account: string;
+    userName: string;
     /**
-     * 姓名
+     * 真实姓名
      * @type {string}
      * @memberof SysOnlineUser
      */
-    name?: string | null;
+    realName?: string | null;
     /**
-     * 最后连接时间
+     * 连接时间
      * @type {Date}
      * @memberof SysOnlineUser
      */
-    lastTime?: Date;
+    time?: Date;
     /**
-     * 最后登录IP
+     * 连接IP
      * @type {string}
      * @memberof SysOnlineUser
      */
-    lastLoginIp?: string | null;
+    ip?: string | null;
     /**
-     * 最后登录浏览器
+     * 浏览器
      * @type {string}
      * @memberof SysOnlineUser
      */
-    lastLoginBrowser?: string | null;
+    browser?: string | null;
     /**
-     * 最后登录所用系统
+     * 操作系统
      * @type {string}
      * @memberof SysOnlineUser
      */
-    lastLoginOs?: string | null;
-    /**
-     * 租户Id
-     * @type {number}
-     * @memberof SysOnlineUser
-     */
-    tenantId?: number;
+    os?: string | null;
 }

+ 31 - 22
Web/src/layout/navBars/breadcrumb/user.vue

@@ -6,19 +6,15 @@
 			</div>
 			<template #dropdown>
 				<el-dropdown-menu>
-					<el-dropdown-item command="large" :disabled="disabledSize === 'large'">{{
-					$t('message.user.dropdownLarge') }}</el-dropdown-item>
-					<el-dropdown-item command="default" :disabled="disabledSize === 'default'">{{
-					$t('message.user.dropdownDefault') }}</el-dropdown-item>
-					<el-dropdown-item command="small" :disabled="disabledSize === 'small'">{{
-					$t('message.user.dropdownSmall') }}</el-dropdown-item>
+					<el-dropdown-item command="large" :disabled="disabledSize === 'large'">{{ $t('message.user.dropdownLarge') }}</el-dropdown-item>
+					<el-dropdown-item command="default" :disabled="disabledSize === 'default'">{{ $t('message.user.dropdownDefault') }}</el-dropdown-item>
+					<el-dropdown-item command="small" :disabled="disabledSize === 'small'">{{ $t('message.user.dropdownSmall') }}</el-dropdown-item>
 				</el-dropdown-menu>
 			</template>
 		</el-dropdown>
 		<el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange">
 			<div class="layout-navbars-breadcrumb-user-icon">
-				<i class="iconfont" :class="disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'"
-					:title="$t('message.user.title1')"></i>
+				<i class="iconfont" :class="disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'" :title="$t('message.user.title1')"></i>
 			</div>
 			<template #dropdown>
 				<el-dropdown-menu>
@@ -50,9 +46,13 @@
 				</template>
 			</el-popover>
 		</div>
-		<div class="layout-navbars-breadcrumb-user-icon mr10" @click="onScreenfullClick">
-			<i class="iconfont" :title="isScreenfull ? $t('message.user.title6') : $t('message.user.title5')"
-				:class="!isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'"></i>
+		<div class="layout-navbars-breadcrumb-user-icon" @click="onScreenfullClick">
+			<i class="iconfont" :title="isScreenfull ? $t('message.user.title6') : $t('message.user.title5')" :class="!isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'"></i>
+		</div>
+		<div class="layout-navbars-breadcrumb-user-icon mr10" @click="onOnlineUserClick">
+			<el-icon title="在线用户">
+				<ele-User />
+			</el-icon>
 		</div>
 		<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick">
 			<span class="layout-navbars-breadcrumb-user-link">
@@ -74,6 +74,7 @@
 			</template>
 		</el-dropdown>
 		<Search ref="searchRef" />
+		<OnlineUser ref="onlineUserRef" />
 	</div>
 </template>
 
@@ -91,9 +92,13 @@ import { Session, Local } from '/@/utils/storage';
 import UserNews from '/@/layout/navBars/breadcrumb/userNews.vue';
 import Search from '/@/layout/navBars/breadcrumb/search.vue';
 
+import OnlineUser from '/@/views/system/onlineUser/index.vue';
+import { getAPI } from '/@/utils/axios-utils';
+import { SysAuthApi } from '/@/api-services/api';
+
 export default defineComponent({
 	name: 'layoutBreadcrumbUser',
-	components: { UserNews, Search },
+	components: { UserNews, Search, OnlineUser },
 	setup() {
 		const { t } = useI18n();
 		const { proxy } = <any>getCurrentInstance();
@@ -103,6 +108,7 @@ export default defineComponent({
 		const { userInfos } = storeToRefs(stores);
 		const { themeConfig } = storeToRefs(storesThemeConfig);
 		const searchRef = ref();
+		const onlineUserRef = ref();
 		const state = reactive({
 			isScreenfull: false,
 			disabledI18n: 'zh-cn',
@@ -146,30 +152,27 @@ export default defineComponent({
 					confirmButtonText: t('message.user.logOutConfirm'),
 					cancelButtonText: t('message.user.logOutCancel'),
 					buttonSize: 'default',
-					beforeClose: (action, instance, done) => {
+					beforeClose: async (action, instance, done) => {
 						if (action === 'confirm') {
 							instance.confirmButtonLoading = true;
 							instance.confirmButtonText = t('message.user.logOutExit');
-							setTimeout(() => {
-								done();
-								setTimeout(() => {
-									instance.confirmButtonLoading = false;
-								}, 300);
-							}, 500);
+							await getAPI(SysAuthApi).logoutPost();
+							instance.confirmButtonLoading = false;
+							done();
 						} else {
 							done();
 						}
 					},
 				})
 					.then(async () => {
-						// 清除缓存/token
+						// 清除缓存 token 
 						Session.clear();
 						// 使用 reload 时,不需要调用 resetRoute() 重置路由
 						window.location.reload();
 					})
-					.catch(() => { });
+					.catch(() => {});
 			} else if (path === 'wareHouse') {
-				window.open('https://gitee.com/lyt-top/vue-next-admin');
+				window.open('https://gitee.com/zuohuaijun/Admin.NET');
 			} else {
 				router.push(path);
 			}
@@ -178,6 +181,10 @@ export default defineComponent({
 		const onSearchClick = () => {
 			searchRef.value.openSearch();
 		};
+		// 在线用户列表
+		const onOnlineUserClick = () => {
+			onlineUserRef.value.openDrawer();
+		};
 		// 组件大小改变
 		const onComponentSizeChange = (size: string) => {
 			Local.remove('themeConfig');
@@ -243,9 +250,11 @@ export default defineComponent({
 			onHandleCommandClick,
 			onScreenfullClick,
 			onSearchClick,
+			onOnlineUserClick,
 			onComponentSizeChange,
 			onLanguageChange,
 			searchRef,
+			onlineUserRef,
 			layoutUserFlexNum,
 			...toRefs(state),
 		};

+ 6 - 1
Web/src/utils/axios-utils.ts

@@ -20,8 +20,13 @@ export const serveConfig = new Configuration({
 export const accessTokenKey = 'access-token';
 export const refreshAccessTokenKey = `x-${accessTokenKey}`;
 
+// 获取 token
+export const getToken = () => {
+	return Local.get(accessTokenKey);
+};
+
 // 清除 token
-const clearAccessTokens = () => {
+export const clearAccessTokens = () => {
 	Local.remove(accessTokenKey);
 	Local.remove(refreshAccessTokenKey);
 

+ 163 - 0
Web/src/views/system/onlineUser/index.vue

@@ -0,0 +1,163 @@
+<template>
+	<div class="sys-onlineUser-container">
+		<el-drawer v-model="state.isVisible" title="在线用户列表" size="45%">
+			<el-card shadow="hover" :body-style="{ paddingBottom: '0' }" style="margin: 8px">
+				<el-form :model="state.queryParams" ref="queryForm" :inline="true">
+					<el-form-item label="账号名称" prop="userName">
+						<el-input placeholder="账号名称" clearable @keyup.enter="handleQuery" v-model="state.queryParams.userName" />
+					</el-form-item>
+					<el-form-item label="真实姓名" prop="realName">
+						<el-input placeholder="账号名称" clearable @keyup.enter="handleQuery" v-model="state.queryParams.realName" />
+					</el-form-item>
+					<el-form-item>
+						<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
+						<el-button type="primary" icon="ele-Search" @click="handleQuery"> 查询 </el-button>
+					</el-form-item>
+				</el-form>
+			</el-card>
+
+			<el-card shadow="hover" style="margin: 8px">
+				<el-table :data="state.onlineUserList" style="width: 100%" v-loading="state.loading" border>
+					<el-table-column type="index" label="序号" width="55" align="center" />
+					<el-table-column prop="userName" label="账号" show-overflow-tooltip></el-table-column>
+					<el-table-column prop="realName" label="姓名" show-overflow-tooltip></el-table-column>
+					<el-table-column prop="time" label="登录时间" show-overflow-tooltip></el-table-column>
+					<el-table-column prop="ip" label="IP地址" show-overflow-tooltip> </el-table-column>
+					<el-table-column prop="browser" label="浏览器" show-overflow-tooltip></el-table-column>
+					<el-table-column prop="connectionId" label="连接Id" show-overflow-tooltip></el-table-column>
+					<el-table-column label="操作" width="70" fixed="right" align="center" show-overflow-tooltip>
+						<template #default="scope">
+							<el-button icon="ele-CircleClose" size="small" text type="danger" v-auth="'sysUser:forceOffline'" @click="forceOffline(scope.row.connectionId)"> 下线 </el-button>
+						</template>
+					</el-table-column>
+				</el-table>
+				<el-pagination
+					v-model:currentPage="state.tableParams.page"
+					v-model:page-size="state.tableParams.pageSize"
+					:total="state.tableParams.total"
+					:page-sizes="[10, 20, 50, 100]"
+					small
+					background
+					@size-change="handleSizeChange"
+					@current-change="handleCurrentChange"
+					layout="total, sizes, prev, pager, next, jumper"
+				/>
+			</el-card>
+		</el-drawer>
+	</div>
+</template>
+
+<script setup lang="ts">
+import { reactive } from 'vue';
+import { ElNotification } from 'element-plus';
+import * as SignalR from '@microsoft/signalr';
+
+import { getAPI, getToken, clearAccessTokens } from '/@/utils/axios-utils';
+import { SysOnlineUserApi, SysAuthApi } from '/@/api-services/api';
+
+const reciveMessage = (msg: any) => {
+	console.log('接收消息:', msg);
+};
+
+const state = reactive({
+	loading: false,
+	isVisible: false,
+	queryParams: {
+		userName: undefined,
+		realName: undefined,
+	},
+	tableParams: {
+		page: 1,
+		pageSize: 10,
+		total: 0 as any,
+	},
+	onlineUserList: [] as any, // 在线用户列表
+});
+
+const signalrUrl = `${import.meta.env.VITE_API_URL}/hubs/onlineUser`;
+// 初始化SignalR对象
+const connection = new SignalR.HubConnectionBuilder()
+	.configureLogging(SignalR.LogLevel.Information)
+	.withUrl(`${signalrUrl}?access_token=${getToken()}`)
+	.withAutomaticReconnect({
+		nextRetryDelayInMilliseconds: () => {
+			return 5000; // 每5秒重连一次
+		},
+	})
+	.build();
+
+connection.keepAliveIntervalInMilliseconds = 15000; // 心跳检测15s
+
+// 注册web端方法供后端调用
+connection.on('ReceiveMessage', reciveMessage);
+// 强制用户下线
+connection.on('ForceOffline', async (data: any) => {
+	console.log('强制下线', data);
+	await connection.stop();
+
+	await getAPI(SysAuthApi).logoutPost();
+	clearAccessTokens();
+});
+// 在线用户改变
+connection.on('OnlineUserChange', (data: any) => {
+	state.onlineUserList = data.userList;
+	ElNotification({
+		title: '提示',
+		message: `${data.online ? `【${data.realName}】上线了` : `【${data.realName}】离开了`}`,
+		type: 'info',
+		position: 'bottom-right',
+	});
+});
+
+// 第一次连接成功
+connection.start().then(() => {});
+
+// 连接断开
+connection.onclose(async () => {});
+
+// 掉线重连中
+connection.onreconnecting(() => {});
+
+// 重新连接成功
+connection.onreconnected(() => {});
+
+// 打开页面
+const openDrawer = () => {
+	state.isVisible = true;
+};
+// 查询操作
+const handleQuery = async () => {
+	state.loading = true;
+	var res = await getAPI(SysOnlineUserApi).sysOnlineUserPageGet(state.queryParams.userName, state.queryParams.realName, state.tableParams.page, state.tableParams.pageSize);
+	state.onlineUserList = res.data.result?.items;
+	state.tableParams.total = res.data.result?.total;
+	state.loading = false;
+};
+// 重置操作
+const resetQuery = () => {
+	state.queryParams.userName = undefined;
+	state.queryParams.realName = undefined;
+	handleQuery();
+};
+// 强制下线
+const forceOffline = async (connectionId: any) => {
+	await connection.send('ForceOffline', { connectionId }).catch(function (err) {
+		console.log(err);
+	});
+};
+// 改变页面容量
+const handleSizeChange = (val: number) => {
+	state.tableParams.pageSize = val;
+	handleQuery();
+};
+// 改变页码序号
+const handleCurrentChange = (val: number) => {
+	state.tableParams.page = val;
+	handleQuery();
+};
+
+// 导出
+defineExpose({ openDrawer });
+</script>
+
+<style lang="scss"></style>