diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Config/SwaggerDoc.xml b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Config/SwaggerDoc.xml
index 4555c42b..b9c3e71f 100644
--- a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Config/SwaggerDoc.xml
+++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Config/SwaggerDoc.xml
@@ -344,6 +344,26 @@
+
+
+ 在线管理
+
+
+
+
+ 动态条件获取当前在线用户
+
+
+
+
+
+
+
+ 强制退出用户
+
+
+
+
动态条件分页查询
diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/OnlineController.cs b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/OnlineController.cs
new file mode 100644
index 00000000..654d5249
--- /dev/null
+++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/OnlineController.cs
@@ -0,0 +1,84 @@
+using Hei.Captcha;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Yi.Framework.Common.Const;
+using Yi.Framework.Common.Enum;
+using Yi.Framework.Common.Helper;
+using Yi.Framework.Common.Models;
+using Yi.Framework.Core;
+using Yi.Framework.DTOModel;
+using Yi.Framework.Interface;
+using Yi.Framework.Model.Models;
+using Yi.Framework.Repository;
+using Yi.Framework.WebCore;
+using Yi.Framework.WebCore.AttributeExtend;
+using Yi.Framework.WebCore.AuthorizationPolicy;
+using Yi.Framework.WebCore.SignalRHub;
+
+namespace Yi.Framework.ApiMicroservice.Controllers
+{
+ ///
+ /// 在线管理
+ ///
+ [ApiController]
+ [Authorize]
+ [Route("api/[controller]/[action]")]
+ public class OnlineController : ControllerBase
+ {
+ private ILogger _logger;
+ private IHubContext _hub;
+ public OnlineController(ILogger logger, IHubContext hub)
+ {
+ _logger = logger;
+ _hub = hub;
+ }
+
+ ///
+ /// 动态条件获取当前在线用户
+ ///
+ ///
+ ///
+ ///
+ [HttpGet]
+ public Result PageList([FromQuery] OnlineUser online, [FromQuery] PageParModel page)
+ {
+ var data = MainHub.clientUsers;
+ IEnumerable dataWhere = data.AsEnumerable();
+
+ if (!string.IsNullOrEmpty(online.Ipaddr))
+ {
+ dataWhere = dataWhere.Where((u) => u.Ipaddr.Contains(online.Ipaddr));
+ }
+ if (!string.IsNullOrEmpty(online.UserName))
+ {
+ dataWhere = dataWhere.Where((u) => u.UserName.Contains(online.UserName));
+ }
+ return Result.Success().SetData(new PageModel>() { Total = data.Count, Data = dataWhere.ToList() });
+ }
+
+
+ ///
+ /// 强制退出用户
+ ///
+ ///
+ ///
+ [HttpDelete]
+ [Route("{connnectionId}")]
+ public async Task ForceOut(string connnectionId)
+ {
+ if (MainHub.clientUsers.Exists(u => u.ConnnectionId == connnectionId))
+ {
+ //前端接受到这个事件后,触发前端自动退出
+ await _hub.Clients.Client(connnectionId).SendAsync(HubTypeEnum.forceOut.ToString(),"你已被强制退出!");
+ return Result.Success();
+ }
+ return Result.Error("操作失败!未发现该连接!");
+ }
+ }
+}
diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/SignalrController.cs b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/SignalrController.cs
deleted file mode 100644
index 17235691..00000000
--- a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/SignalrController.cs
+++ /dev/null
@@ -1,211 +0,0 @@
-using Hei.Captcha;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Logging;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Yi.Framework.Common.Const;
-using Yi.Framework.Common.Enum;
-using Yi.Framework.Common.Helper;
-using Yi.Framework.Common.Models;
-using Yi.Framework.Core;
-using Yi.Framework.DTOModel;
-using Yi.Framework.Interface;
-using Yi.Framework.Model.Models;
-using Yi.Framework.Repository;
-using Yi.Framework.WebCore;
-using Yi.Framework.WebCore.AttributeExtend;
-using Yi.Framework.WebCore.AuthorizationPolicy;
-
-namespace Yi.Framework.ApiMicroservice.Controllers
-{
- ///
- /// 账户管理
- ///
- [ApiController]
- [Authorize]
- [Route("api/[controller]/[action]")]
- public class AccountController : ControllerBase
- {
- private IUserService _iUserService;
- private JwtInvoker _jwtInvoker;
- private ILogger _logger;
- private SecurityCodeHelper _securityCode;
- private IRepository _repository;
- public AccountController(ILogger logger, IUserService iUserService, JwtInvoker jwtInvoker, SecurityCodeHelper securityCode)
- {
- _iUserService = iUserService;
- _jwtInvoker = jwtInvoker;
- _logger = logger;
- _securityCode = securityCode;
- _repository = iUserService._repository;
- }
-
- ///
- /// 重置管理员CC的密码
- ///
- ///
- [HttpGet]
- [AllowAnonymous]
- public async Task RestCC()
- {
- var user = await _iUserService._repository.GetFirstAsync(u => u.UserName == "cc");
- user.Password = "123456";
- user.BuildPassword();
- await _iUserService._repository.UpdateIgnoreNullAsync(user);
- return Result.Success();
- }
-
- ///
- /// 没啥说,登录
- ///
- ///
- ///
- [AllowAnonymous]
- [HttpPost]
- public async Task Login(LoginDto loginDto)
- {
- //跳过,需要redis缓存获取uuid与code的关系,进行比较即可
- //先效验验证码和UUID
- //登录还需要进行登录日志的落库
-
- var loginInfo = HttpContext.GetLoginLogInfo();
- loginInfo.LoginUser = loginDto.UserName;
- loginInfo.LogMsg = "登录成功!";
- var loginLogRepository = _repository.ChangeRepository>();
- UserEntity user = new();
- if (await _iUserService.Login(loginDto.UserName, loginDto.Password, o => user = o))
- {
- var userRoleMenu = await _iUserService.GetUserAllInfo(user.Id);
- await loginLogRepository.InsertReturnSnowflakeIdAsync(loginInfo);
- return Result.Success(loginInfo.LogMsg).SetData(new { token = _jwtInvoker.GetAccessToken(userRoleMenu.User, userRoleMenu.Menus) });
- }
- loginInfo.LogMsg = "登录失败!用户名或者密码错误!";
- await loginLogRepository.InsertReturnSnowflakeIdAsync(loginInfo);
- return Result.Error(loginInfo.LogMsg);
- }
-
-
-
- ///
- /// 没啥说,注册
- ///
- ///
- ///
- [AllowAnonymous]
- [HttpPost]
- public async Task Register(RegisterDto registerDto)
- {
- UserEntity user = new();
- if (await _iUserService.Register(WebCore.Mapper.MapperHelper.Map(registerDto), o => user = o))
- {
- return Result.Success("注册成功!").SetData(user);
- }
- return Result.SuccessError("注册失败!用户名已存在!");
- }
-
- ///
- /// 没啥说,登出
- ///
- ///
- [HttpPost]
- [AllowAnonymous]
- public Result Logout()
- {
- return Result.Success("安全登出成功!");
- }
-
- ///
- /// 通过已登录的用户获取用户信息
- ///
- ///
- [HttpGet]
- //[Authorize]
- public async Task GetUserAllInfo()
- {
- //通过鉴权jwt获取到用户的id
- var userId = HttpContext.GetUserIdInfo();
- var data = await _iUserService.GetUserAllInfo(userId);
- //系统用户数据被重置,老前端访问重新授权
- if (data is null)
- {
- return Result.UnAuthorize();
- }
-
- data.Menus.Clear();
- return Result.Success().SetData(data);
- }
-
- ///
- /// 获取当前登录用户的前端路由
- ///
- ///
- [HttpGet]
- public async Task GetRouterInfo()
- {
- var userId = HttpContext.GetUserIdInfo();
- var data = await _iUserService.GetUserAllInfo(userId);
- var menus = data.Menus.ToList();
-
- //为超级管理员直接给全部路由
- if (SystemConst.Admin.Equals(data.User.UserName))
- {
- menus = await _iUserService._repository.ChangeRepository>().GetListAsync();
- }
- //将后端菜单转换成前端路由,组件级别需要过滤
- List routers = MenuEntity.RouterBuild(menus);
- return Result.Success().SetData(routers);
- }
-
- ///
- /// 更新已登录用户的用户信息
- ///
- ///
- ///
- [HttpPut]
- public async Task UpdateUserByHttp(UserEntity user)
- {
- //当然,密码是不能给他修改的
- user.Password = null;
- user.Salt = null;
-
- //修改需要赋值上主键哦
- user.Id = HttpContext.GetUserIdInfo();
- return Result.Success().SetStatus(await _iUserService._repository.UpdateIgnoreNullAsync(user));
- }
-
- ///
- /// 自己更新密码
- ///
- ///
- ///
- [HttpPut]
- public async Task UpdatePassword(UpdatePasswordDto dto)
- {
- long userId = HttpContext.GetUserIdInfo();
-
- if (await _iUserService.UpdatePassword(dto, userId))
- {
- return Result.Success();
- }
- return Result.Error("更新失败!");
- }
-
- ///
- /// 验证码
- ///
- ///
- [AllowAnonymous]
- [HttpGet]
- public Result CaptchaImage()
- {
- var uuid = Guid.NewGuid();
- var code = _securityCode.GetRandomEnDigitalText(4);
- //将uuid与code,Redis缓存中心化保存起来,登录根据uuid比对即可
- var imgbyte = _securityCode.GetEnDigitalCodeByte(code);
- return Result.Success().SetData(new { uuid = uuid, img = imgbyte });
- }
- }
-}
diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/yi-sqlsugar-dev.db b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/yi-sqlsugar-dev.db
index eb123d18..f24a8283 100644
Binary files a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/yi-sqlsugar-dev.db and b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/yi-sqlsugar-dev.db differ
diff --git a/Yi.Framework.Net6/Yi.Framework.Common/Enum/HubTypeEnum.cs b/Yi.Framework.Net6/Yi.Framework.Common/Enum/HubTypeEnum.cs
index d78a7844..e31558f2 100644
--- a/Yi.Framework.Net6/Yi.Framework.Common/Enum/HubTypeEnum.cs
+++ b/Yi.Framework.Net6/Yi.Framework.Common/Enum/HubTypeEnum.cs
@@ -8,7 +8,14 @@ namespace Yi.Framework.Common.Enum
{
public enum HubTypeEnum
{
+ ///
+ /// 在线总数
+ ///
onlineNum,
+ ///
+ /// 强制退出
+ ///
+ forceOut
}
}
diff --git a/Yi.Framework.Net6/Yi.Framework.Model/SeedData/MenuSeed.cs b/Yi.Framework.Net6/Yi.Framework.Model/SeedData/MenuSeed.cs
index 19c53633..dae1310f 100644
--- a/Yi.Framework.Net6/Yi.Framework.Model/SeedData/MenuSeed.cs
+++ b/Yi.Framework.Net6/Yi.Framework.Model/SeedData/MenuSeed.cs
@@ -45,6 +45,29 @@ namespace Yi.Framework.Model.SeedData
};
Entitys.Add(monitoring);
+
+ //在线用户
+ MenuEntity online = new MenuEntity()
+ {
+ Id = SnowFlakeSingle.Instance.NextId(),
+ MenuName = "在线用户",
+ PermissionCode = "monitor:online:list",
+ MenuType = MenuTypeEnum.Menu.GetHashCode(),
+ Router = "online",
+ IsShow = true,
+ IsLink = false,
+ IsCache = true,
+ Component = "monitor/online/index",
+ MenuIcon = "online",
+ OrderNum = 100,
+ ParentId = monitoring.Id,
+ IsDeleted = false
+ };
+ Entitys.Add(online);
+
+
+
+
//系统工具
MenuEntity tool = new MenuEntity()
{
diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/SignalRHub/MainHub.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/SignalRHub/MainHub.cs
index 0fac1551..d1baf01f 100644
--- a/Yi.Framework.Net6/Yi.Framework.WebCore/SignalRHub/MainHub.cs
+++ b/Yi.Framework.Net6/Yi.Framework.WebCore/SignalRHub/MainHub.cs
@@ -13,6 +13,9 @@ namespace Yi.Framework.WebCore.SignalRHub
{
public class MainHub : Hub
{
+ public static readonly List clientUsers = new();
+
+
private HttpContext _httpContext;
private ILogger _logger;
public MainHub(IHttpContextAccessor httpContextAccessor,ILogger logger)
@@ -21,7 +24,7 @@ namespace Yi.Framework.WebCore.SignalRHub
_logger = logger;
}
- private static readonly List clientUsers = new();
+
///
/// 成功连接
@@ -30,17 +33,19 @@ namespace Yi.Framework.WebCore.SignalRHub
public override Task OnConnectedAsync()
{
var name = _httpContext.GetUserNameInfo();
- var ip = _httpContext.GetClientIp();
- var ip_info = IpTool.Search(ip);
-
- var loginUser = _httpContext.GetUserEntityInfo(out _);
+ var loginUser = _httpContext.GetLoginLogInfo();
var user = clientUsers.Any(u => u.ConnnectionId == Context.ConnectionId);
//判断用户是否存在,否则添加集合
if (!user && Context.User.Identity.IsAuthenticated)
{
- OnlineUser users = new(Context.ConnectionId, name, loginUser.Id, ip)
+ OnlineUser users = new(Context.ConnectionId)
{
- Location = ip_info.City
+ Browser= loginUser.Browser,
+ LoginLocation = loginUser.LoginLocation,
+ Ipaddr= loginUser.LoginIp,
+ LoginTime=DateTime.Now,
+ Os=loginUser.Os,
+ UserName= name
};
clientUsers.Add(users);
_logger.LogInformation($"{DateTime.Now}:{name},{Context.ConnectionId}连接服务端success,当前已连接{clientUsers.Count}个");
@@ -67,7 +72,7 @@ namespace Yi.Framework.WebCore.SignalRHub
clientUsers.Remove(user);
Clients.All.SendAsync(HubTypeEnum.onlineNum.ToString(), clientUsers.Count);
//Clients.All.SendAsync(HubsConstant.OnlineUser, clientUsers);
- _logger.LogInformation($"用户{user?.Name}离开了,当前已连接{clientUsers.Count}个");
+ _logger.LogInformation($"用户{user?.UserName}离开了,当前已连接{clientUsers.Count}个");
}
return base.OnDisconnectedAsync(exception);
}
diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/SignalRHub/OnlineUser.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/SignalRHub/OnlineUser.cs
index d9ce0cc1..8b3259d2 100644
--- a/Yi.Framework.Net6/Yi.Framework.WebCore/SignalRHub/OnlineUser.cs
+++ b/Yi.Framework.Net6/Yi.Framework.WebCore/SignalRHub/OnlineUser.cs
@@ -6,26 +6,32 @@ namespace Yi.Framework.WebCore.SignalRHub
{
public class OnlineUser
{
+
+ public OnlineUser()
+ {
+
+ }
+ public OnlineUser(string connnectionId)
+ {
+ this.ConnnectionId = connnectionId;
+ }
+
///
/// 客户端连接Id
///
- public string ConnnectionId { get; set; }
+ public string ConnnectionId { get; }
///
/// 用户id
///
- public long? Userid { get; set; }
- public string Name { get; set; }
+ public long? UserId { get; set; }
+ public string UserName { get; set; }
public DateTime LoginTime { get; set; }
- public string UserIP { get; set; }
- public string Location { get; set; }
+ public string Ipaddr { get; set; }
+ public string LoginLocation { get; set; }
+
+ public string Os { get; set; }
+ public string Browser { get; set; }
+
- public OnlineUser(string clientid, string name, long? userid, string userip)
- {
- ConnnectionId = clientid;
- Name = name;
- LoginTime = DateTime.Now;
- Userid = userid;
- UserIP = userip;
- }
}
}
diff --git a/Yi.Vue3.X.RuoYi/src/App.vue b/Yi.Vue3.X.RuoYi/src/App.vue
index 70ffc223..584591d6 100644
--- a/Yi.Vue3.X.RuoYi/src/App.vue
+++ b/Yi.Vue3.X.RuoYi/src/App.vue
@@ -5,6 +5,11 @@
diff --git a/Yi.Vue3.X.RuoYi/src/api/monitor/online.js b/Yi.Vue3.X.RuoYi/src/api/monitor/online.js
index bd221378..434aadc4 100644
--- a/Yi.Vue3.X.RuoYi/src/api/monitor/online.js
+++ b/Yi.Vue3.X.RuoYi/src/api/monitor/online.js
@@ -3,7 +3,7 @@ import request from '@/utils/request'
// 查询在线用户列表
export function list(query) {
return request({
- url: '/monitor/online/list',
+ url: '/online/pageList',
method: 'get',
params: query
})
@@ -12,7 +12,7 @@ export function list(query) {
// 强退用户
export function forceLogout(tokenId) {
return request({
- url: '/monitor/online/' + tokenId,
+ url: '/online/ForceOut/' + tokenId,
method: 'delete'
})
}
diff --git a/Yi.Vue3.X.RuoYi/src/utils/signalR.js b/Yi.Vue3.X.RuoYi/src/utils/signalR.js
index 38d100bc..77019867 100644
--- a/Yi.Vue3.X.RuoYi/src/utils/signalR.js
+++ b/Yi.Vue3.X.RuoYi/src/utils/signalR.js
@@ -2,7 +2,8 @@
import * as signalR from '@microsoft/signalr'
import useSocketStore from '@/store/modules/socket'
import { getToken } from '@/utils/auth'
-
+import useUserStore from '@/store/modules/user'
+import { ElMessage } from 'element-plus'
export default {
// signalR对象
@@ -36,6 +37,12 @@ export default {
* 调用 this.signalR.start().then(async () => { await this.SR.invoke("method")})
* @returns
*/
+async close(){
+ var that = this;
+ await this.SR.stop();
+},
+
+
async start() {
var that = this;
@@ -62,6 +69,12 @@ export default {
const socketStore = useSocketStore();
socketStore.setOnlineNum(data)
});
+ connection.on("forceOut", (msg) => {
+ useUserStore().logOut().then(() => {
+ ElMessage.error(msg);
+ location.href = '/index';
+ })
+ });
// connection.on("onlineNum", (data) => {
// store.dispatch("socket/changeOnlineNum", data);
// });
diff --git a/Yi.Vue3.X.RuoYi/src/views/monitor/online/index.vue b/Yi.Vue3.X.RuoYi/src/views/monitor/online/index.vue
index 2ee7b7e5..a031b24e 100644
--- a/Yi.Vue3.X.RuoYi/src/views/monitor/online/index.vue
+++ b/Yi.Vue3.X.RuoYi/src/views/monitor/online/index.vue
@@ -1,10 +1,10 @@
-
+
@@ -24,17 +24,16 @@
- {{ (pageNum - 1) * pageSize + scope.$index + 1 }}
+ {{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}
-
+
-
@@ -56,7 +55,7 @@
-
+
@@ -68,10 +67,12 @@ const { proxy } = getCurrentInstance();
const onlineList = ref([]);
const loading = ref(true);
const total = ref(0);
-const pageNum = ref(1);
-const pageSize = ref(10);
+// const pageNum = ref(1);
+// const pageSize = ref(10);
const queryParams = ref({
+ pageNum: 1,
+ pageSize: 10,
ipaddr: undefined,
userName: undefined
});
@@ -80,14 +81,14 @@ const queryParams = ref({
function getList() {
loading.value = true;
initData(queryParams.value).then(response => {
- onlineList.value = response.rows;
- total.value = response.total;
+ onlineList.value = response.data.data;
+ total.value = response.data.total;
loading.value = false;
});
}
/** 搜索按钮操作 */
function handleQuery() {
- pageNum.value = 1;
+ queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
@@ -98,7 +99,7 @@ function resetQuery() {
/** 强退按钮操作 */
function handleForceLogout(row) {
proxy.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function () {
- return forceLogout(row.tokenId);
+ return forceLogout(row.connnectionId);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");