refactor: 临时密码登录功能
This commit is contained in:
parent
6ff58b943e
commit
5e9857ee99
@ -10,6 +10,14 @@ ADD COLUMN `wx_open_id` varchar(255) NULL COMMENT '微信-开放平台-openid' A
|
|||||||
ADD COLUMN `wx_union_id` varchar(255) NULL COMMENT '微信-开放平台-unionid' AFTER `wx_open_id`;
|
ADD COLUMN `wx_union_id` varchar(255) NULL COMMENT '微信-开放平台-unionid' AFTER `wx_open_id`;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 开放白名单
|
||||||
|
|
||||||
|
### 临时登录接口
|
||||||
|
|
||||||
|
```
|
||||||
|
/router/systemuser/temporary-login
|
||||||
|
```
|
||||||
|
|
||||||
# 20250325(已上线)
|
# 20250325(已上线)
|
||||||
|
|
||||||
## user_expand
|
## user_expand
|
||||||
|
@ -3,12 +3,12 @@ package cn.com.tenlion.operator.controller.api.systemuser;
|
|||||||
import cn.com.tenlion.operator.pojo.dtos.account.AccountDTO;
|
import cn.com.tenlion.operator.pojo.dtos.account.AccountDTO;
|
||||||
import cn.com.tenlion.operator.service.account.IAccountService;
|
import cn.com.tenlion.operator.service.account.IAccountService;
|
||||||
import cn.com.tenlion.operator.service.custompersonal.ICustomPersonalService;
|
import cn.com.tenlion.operator.service.custompersonal.ICustomPersonalService;
|
||||||
|
import cn.com.tenlion.operator.service.login.temporary.LoginTemporaryService;
|
||||||
import cn.com.tenlion.projectconfig.util.ProjectConfigUtil;
|
import cn.com.tenlion.projectconfig.util.ProjectConfigUtil;
|
||||||
import ink.wgink.annotation.CheckRequestBodyAnnotation;
|
import ink.wgink.annotation.CheckRequestBodyAnnotation;
|
||||||
import ink.wgink.common.base.DefaultBaseController;
|
import ink.wgink.common.base.DefaultBaseController;
|
||||||
import ink.wgink.exceptions.SearchException;
|
import ink.wgink.exceptions.SearchException;
|
||||||
import ink.wgink.interfaces.consts.ISystemConstant;
|
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||||
import ink.wgink.interfaces.user.IUserBaseService;
|
|
||||||
import ink.wgink.pojo.result.ErrorResult;
|
import ink.wgink.pojo.result.ErrorResult;
|
||||||
import ink.wgink.pojo.result.SuccessResult;
|
import ink.wgink.pojo.result.SuccessResult;
|
||||||
import ink.wgink.pojo.result.SuccessResultData;
|
import ink.wgink.pojo.result.SuccessResultData;
|
||||||
@ -16,7 +16,6 @@ import ink.wgink.service.user.service.IUserService;
|
|||||||
import io.swagger.annotations.*;
|
import io.swagger.annotations.*;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ClassName: SystemUserlController
|
* @ClassName: SystemUserlController
|
||||||
@ -28,7 +27,7 @@ import org.springframework.web.servlet.ModelAndView;
|
|||||||
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "系统用户接口")
|
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "系统用户接口")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(ISystemConstant.API_PREFIX + "/systemuser")
|
@RequestMapping(ISystemConstant.API_PREFIX + "/systemuser")
|
||||||
public class SystemUserApiontroller extends DefaultBaseController {
|
public class SystemUserController extends DefaultBaseController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ICustomPersonalService customPersonalService;
|
private ICustomPersonalService customPersonalService;
|
||||||
@ -38,6 +37,8 @@ public class SystemUserApiontroller extends DefaultBaseController {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IUserService iUserService;
|
private IUserService iUserService;
|
||||||
|
@Autowired
|
||||||
|
private LoginTemporaryService loginTemporaryService;
|
||||||
|
|
||||||
@ApiOperation(value = "更改开放状态", notes = "更改开放状态")
|
@ApiOperation(value = "更改开放状态", notes = "更改开放状态")
|
||||||
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||||
@ -77,4 +78,14 @@ public class SystemUserApiontroller extends DefaultBaseController {
|
|||||||
throw new SearchException("系统错误");
|
throw new SearchException("系统错误");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("get-temporary-password")
|
||||||
|
public SuccessResultData<String> getTemporaryPassword() {
|
||||||
|
return new SuccessResultData<>(loginTemporaryService.getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("generate-temporary-password")
|
||||||
|
public SuccessResultData<String> generateTemporaryPassword() {
|
||||||
|
return new SuccessResultData<>(loginTemporaryService.generatePassword());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -64,7 +64,7 @@ public class SystemUserRouteController extends DefaultBaseController {
|
|||||||
List<RoleSimpleDTO> roleSimpleDTOList = userInfoBO.getRoles();
|
List<RoleSimpleDTO> roleSimpleDTOList = userInfoBO.getRoles();
|
||||||
String url = systemProperties.getUrl();
|
String url = systemProperties.getUrl();
|
||||||
if (userInfoBO.getUserId().equals("1")) {
|
if (userInfoBO.getUserId().equals("1")) {
|
||||||
return new ModelAndView("forward:/default-main");
|
return new ModelAndView("forward:/route/systemuser/system-select");
|
||||||
}
|
}
|
||||||
if (roleSimpleDTOList == null || roleSimpleDTOList.isEmpty()) {
|
if (roleSimpleDTOList == null || roleSimpleDTOList.isEmpty()) {
|
||||||
throw new SaveException("角色不存在");
|
throw new SaveException("角色不存在");
|
||||||
@ -73,7 +73,7 @@ public class SystemUserRouteController extends DefaultBaseController {
|
|||||||
StringUtils.contains("项目运营", roleSimpleDTO.getRoleName()) ||
|
StringUtils.contains("项目运营", roleSimpleDTO.getRoleName()) ||
|
||||||
StringUtils.contains("开发人员", roleSimpleDTO.getRoleName()));
|
StringUtils.contains("开发人员", roleSimpleDTO.getRoleName()));
|
||||||
if (isAdmin || userInfoBO.getUserId().equals("1")) {
|
if (isAdmin || userInfoBO.getUserId().equals("1")) {
|
||||||
return new ModelAndView("forward:/default-main");
|
return new ModelAndView("forward:/route/systemuser/system-select");
|
||||||
} else if (roleSimpleDTOList.stream().anyMatch(roleSimpleDTO -> StringUtils.contains("普通用户", roleSimpleDTO.getRoleName()))) {
|
} else if (roleSimpleDTOList.stream().anyMatch(roleSimpleDTO -> StringUtils.contains("普通用户", roleSimpleDTO.getRoleName()))) {
|
||||||
return new ModelAndView(new RedirectView(ProjectConfigUtil.getText("AiServerUrl")));
|
return new ModelAndView(new RedirectView(ProjectConfigUtil.getText("AiServerUrl")));
|
||||||
}
|
}
|
||||||
@ -99,5 +99,24 @@ public class SystemUserRouteController extends DefaultBaseController {
|
|||||||
return mv;
|
return mv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("home")
|
||||||
|
public ModelAndView home() {
|
||||||
|
ModelAndView mv = new ModelAndView();
|
||||||
|
mv.setViewName("systemuser/home");
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("system-select")
|
||||||
|
public ModelAndView systemSelect() {
|
||||||
|
ModelAndView mv = new ModelAndView();
|
||||||
|
mv.setViewName("systemuser/system-select");
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("temporary-login")
|
||||||
|
public ModelAndView temporaryLogin() {
|
||||||
|
ModelAndView mv = new ModelAndView("systemuser/temporary-login");
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -22,7 +22,7 @@ public class LoginTemporaryAuthFilter extends AbstractAuthenticationProcessingFi
|
|||||||
private final LoginTemporaryService loginTemporaryService;
|
private final LoginTemporaryService loginTemporaryService;
|
||||||
|
|
||||||
public LoginTemporaryAuthFilter(LoginTemporaryService loginTemporaryService) {
|
public LoginTemporaryAuthFilter(LoginTemporaryService loginTemporaryService) {
|
||||||
super(new AntPathRequestMatcher("/oauth/temporary", "POST"));
|
super(new AntPathRequestMatcher("/oauth/temporary/login", "POST"));
|
||||||
this.loginTemporaryService = loginTemporaryService;
|
this.loginTemporaryService = loginTemporaryService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ public class LoginWxOauth2AuthProvider implements AuthenticationProvider {
|
|||||||
username = openid;
|
username = openid;
|
||||||
} else {
|
} else {
|
||||||
UserPO userPO = userService.getPO(userExpandPO.getUserId());
|
UserPO userPO = userService.getPO(userExpandPO.getUserId());
|
||||||
username = userPO.getUserName();
|
username = userPO.getUserUsername();
|
||||||
if (userPO.getUserState() == 1) {
|
if (userPO.getUserState() == 1) {
|
||||||
userService.updateUserState(userPO.getUserId(), UserStateEnum.NORMAL);
|
userService.updateUserState(userPO.getUserId(), UserStateEnum.NORMAL);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.com.tenlion.operator.service.login.temporary;
|
package cn.com.tenlion.operator.service.login.temporary;
|
||||||
|
|
||||||
|
import ink.wgink.util.UUIDUtil;
|
||||||
import ink.wgink.util.string.WStringUtil;
|
import ink.wgink.util.string.WStringUtil;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -11,9 +12,10 @@ public class LoginTemporaryService {
|
|||||||
private long lastUpdateTime = 0;
|
private long lastUpdateTime = 0;
|
||||||
|
|
||||||
public String generatePassword() {
|
public String generatePassword() {
|
||||||
String code = "" + System.currentTimeMillis();
|
String code = UUIDUtil.get32UUID();
|
||||||
this.lastUpdateTime = System.currentTimeMillis();
|
this.lastUpdateTime = System.currentTimeMillis();
|
||||||
return WStringUtil.randomSubStr(code, 6);
|
this.password = WStringUtil.randomSubStr(code, 10);
|
||||||
|
return password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPassword() {
|
public String getPassword() {
|
||||||
|
@ -2,10 +2,11 @@ server:
|
|||||||
port: 8091
|
port: 8091
|
||||||
# url: http://127.0.0.1:8091/operator/
|
# url: http://127.0.0.1:8091/operator/
|
||||||
url: http://121.36.71.250:58038/operator/
|
url: http://121.36.71.250:58038/operator/
|
||||||
ip: 127.0.0.1
|
ip: 121.36.71.250
|
||||||
system-title: 运营平台
|
system-title: 运营平台
|
||||||
system-sub-title: 运营平台
|
system-sub-title: 运营平台
|
||||||
default-index-page: route/systemuser/index
|
default-index-page: route/systemuser/index
|
||||||
|
default-home-page: route/systemuser/home
|
||||||
servlet:
|
servlet:
|
||||||
context-path: /operator
|
context-path: /operator
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ file:
|
|||||||
|
|
||||||
security:
|
security:
|
||||||
oauth2:
|
oauth2:
|
||||||
oauth-server: http://127.0.0.1:8091/operator/
|
oauth-server: http://121.36.71.250:58038/operator/
|
||||||
oauth-logout: ${security.oauth2.oauth-server}/logout?redirect_uri=${server.url}
|
oauth-logout: ${security.oauth2.oauth-server}/logout?redirect_uri=${server.url}
|
||||||
client:
|
client:
|
||||||
client-id: 46c4715a2a504dd48398bda88b5c3a88
|
client-id: 46c4715a2a504dd48398bda88b5c3a88
|
||||||
@ -134,7 +135,7 @@ security:
|
|||||||
api-path:
|
api-path:
|
||||||
user-center: http://127.0.0.1:8091/operator/
|
user-center: http://127.0.0.1:8091/operator/
|
||||||
copyright: http://127.0.0.1:7025/copyright/
|
copyright: http://127.0.0.1:7025/copyright/
|
||||||
copyright-external: http://192.168.0.15:7025/copyright/
|
copyright-external: http://121.36.71.250:58038/copyright/
|
||||||
operator-plugin: http://192.168.0.15:8099/operator-plugin/
|
operator-plugin: http://192.168.0.15:8099/operator-plugin/
|
||||||
|
|
||||||
|
|
||||||
|
614
src/main/resources/templates/systemuser/home.html
Normal file
614
src/main/resources/templates/systemuser/home.html
Normal file
@ -0,0 +1,614 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<base th:href="${#request.getContextPath() + '/'}">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="renderer" content="webkit">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||||
|
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
|
||||||
|
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
|
||||||
|
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
|
||||||
|
<style>
|
||||||
|
.layui-badge {height: auto;}
|
||||||
|
.layui-card-header {overflow: hidden; white-space: nowrap; text-overflow: ellipsis;}
|
||||||
|
.count-second-row {padding-bottom: 0px;}
|
||||||
|
[v-cloak] {display: none;}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="LAY-app" class="layui-fluid">
|
||||||
|
<div class="layui-row layui-col-space15">
|
||||||
|
<div class="layui-col-sm12 layui-col-md6">
|
||||||
|
<div class="layui-row layui-col-space15">
|
||||||
|
<div class="layui-col-sm4 layui-col-md4">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">
|
||||||
|
系统登录用户量
|
||||||
|
<span class="layui-badge layui-bg-blue layuiadmin-badge">天</span>
|
||||||
|
</div>
|
||||||
|
<div class="layui-card-body layuiadmin-card-list">
|
||||||
|
<p id="loginCount" class="layuiadmin-big-font">0</p>
|
||||||
|
<p>
|
||||||
|
增长率
|
||||||
|
<span class="layuiadmin-span-color">
|
||||||
|
<span id="loginPercentage">0</span>% <i class="layui-inline fa fa-arrow-up"></i>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-sm4 layui-col-md4">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">
|
||||||
|
新增用户量
|
||||||
|
<span class="layui-badge layui-bg-orange layuiadmin-badge">周</span>
|
||||||
|
</div>
|
||||||
|
<div class="layui-card-body layuiadmin-card-list">
|
||||||
|
<p id="newUserWeekCount" class="layuiadmin-big-font">0</p>
|
||||||
|
<p>
|
||||||
|
占比
|
||||||
|
<span class="layuiadmin-span-color">
|
||||||
|
<span id="newUserWeekPercentage">0</span>% <i class="layui-inline fa fa-users"></i></i>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-sm4 layui-col-md4">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">
|
||||||
|
总用户量
|
||||||
|
<span class="layui-badge layui-bg-cyan layuiadmin-badge">月</span>
|
||||||
|
</div>
|
||||||
|
<div class="layui-card-body layuiadmin-card-list">
|
||||||
|
<p id="userCount" class="layuiadmin-big-font">0</p>
|
||||||
|
<p>
|
||||||
|
增长人数
|
||||||
|
<span class="layuiadmin-span-color">
|
||||||
|
<span id="userMonthNewCount">0</span> <i class="layui-inline fa fa-arrow-up"></i>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-row layui-col-space15">
|
||||||
|
<div class="layui-col-sm4 layui-col-md4">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<div class="layui-card-header">
|
||||||
|
临时密码
|
||||||
|
<span class="layui-badge layui-bg-red layuiadmin-badge"><i class="layui-inline fa fa-lock"></i></span>
|
||||||
|
</div>
|
||||||
|
<div class="layui-card-body layuiadmin-card-list" v-cloak>
|
||||||
|
<i class="layui-inline fa fa-key" style="margin-right: 5px;" v-if="temporaryPassword"></i>
|
||||||
|
<input v-model="temporaryPassword" id="temporaryPassword" readonly style="width: 100px; height: 22px; padding: 2px; border: 1px solid #efefef; text-align: center;" v-if="temporaryPassword" @click="onCopyTemporaryPassword"/>
|
||||||
|
<button type="button" class="layui-btn layui-btn-primary layui-border layui-btn-xs" @click="onCopyTemporaryPassword" v-if="temporaryPassword">复制</button>
|
||||||
|
<button type="button" class="layui-btn layui-btn-primary layui-border layui-btn-xs" @click="onGenerateTemporaryPassword" style="margin-left: 2px;">生成</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-sm4 layui-col-md4">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">
|
||||||
|
角色数量
|
||||||
|
<span class="layui-badge layui-bg-red layuiadmin-badge"><i class="layui-inline fa fa-user-o"></i></span>
|
||||||
|
</div>
|
||||||
|
<div class="layui-card-body layuiadmin-card-list">
|
||||||
|
<p id="roleCount" class="layuiadmin-big-font">0</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-sm4 layui-col-md4">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">
|
||||||
|
职位数量
|
||||||
|
<span class="layui-badge layui-bg-green layuiadmin-badge"><i class="layui-inline fa fa-briefcase"></i></span>
|
||||||
|
</div>
|
||||||
|
<div class="layui-card-body layuiadmin-card-list">
|
||||||
|
<p id="positionCount" class="layuiadmin-big-font">0</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-sm12 layui-col-md6">
|
||||||
|
<div class="layui-col-sm12">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<div id="loginEChart" style="width: 100%; height: 267px;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-row layui-col-space15">
|
||||||
|
<div class="layui-col-sm6 layui-col-md6">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">用户状态占比</div>
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<div id="userTypeEChart" style="width: 100%; height: 300px;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-sm6 layui-col-md6">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">用户类型占比</div>
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<div id="userStateEChart" style="width: 100%; height: 300px;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-row layui-col-space15">
|
||||||
|
<div class="layui-col-sm6 layui-col-md6">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">
|
||||||
|
系统登录日志(最新10条)
|
||||||
|
</div>
|
||||||
|
<div class="layui-card-body layuiadmin-card-list" style="height: 200px; overflow: auto;">
|
||||||
|
<table class="layui-table" lay-skin="line">
|
||||||
|
<colgroup>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col width="180">
|
||||||
|
</colgroup>
|
||||||
|
<tbody v-cloak>
|
||||||
|
<tr v-for="loginLogger in loginLoggerList">
|
||||||
|
<td>
|
||||||
|
<span class="layui-badge layui-bg-blue"><i class="fa fa-user-circle-o"></i> {{loginLogger.creatorName}}</span> 登录了系统
|
||||||
|
</td>
|
||||||
|
<td>{{loginLogger.loginAddress}}</td>
|
||||||
|
<td><i class="fa fa-clock-o"></i> {{loginLogger.gmtCreate}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-sm6 layui-col-md6">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">
|
||||||
|
用户调整日志(最新10条)
|
||||||
|
</div>
|
||||||
|
<div class="layui-card-body layuiadmin-card-list" style="height: 200px; overflow: auto;">
|
||||||
|
<table class="layui-table" lay-skin="line">
|
||||||
|
<colgroup>
|
||||||
|
<col>
|
||||||
|
<col width="180">
|
||||||
|
</colgroup>
|
||||||
|
<tbody v-cloak>
|
||||||
|
<tr v-for="userAdjustment in userAdjustmentList">
|
||||||
|
<td v-if="userAdjustment.updateType == 'username'">
|
||||||
|
<span class="layui-badge layui-bg-blue"><i class="fa fa-user-circle-o"></i> {{userAdjustment.userName}}</span> 变更了用户名为 <span class="layui-badge layui-bg-cyan" :title="'原用户名:'+ userAdjustment.oldValue" style="cursor:pointer;">{{userAdjustment.newValue}}</span>
|
||||||
|
</td>
|
||||||
|
<td v-if="userAdjustment.updateType == 'password'">
|
||||||
|
<span class="layui-badge layui-bg-blue"><i class="fa fa-user-circle-o"></i> {{userAdjustment.userName}}</span> 修改了密码
|
||||||
|
</td>
|
||||||
|
<td v-if="userAdjustment.updateType == 'restPassword'">
|
||||||
|
<span class="layui-badge layui-bg-blue"><i class="fa fa-user-circle-o"></i> {{userAdjustment.userName}}</span> 重置了密码为 <span class="layui-badge layui-bg-cyan">{{userAdjustment.newValue}}</span>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-clock-o"></i> {{userAdjustment.gmtCreate}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="assets/js/vue.min.js"></script>
|
||||||
|
<script type="text/javascript" src="assets/js/vendor/echarts/echarts.min.js"></script>
|
||||||
|
<script src="assets/layuiadmin/layui/layui.js"></script>
|
||||||
|
<script>
|
||||||
|
layui.config({
|
||||||
|
base: 'assets/layuiadmin/' //静态资源所在路径
|
||||||
|
}).extend({
|
||||||
|
index: 'lib/index' //主入口模块
|
||||||
|
}).use(['index', 'animate-numbers'], function() {
|
||||||
|
var $ = layui.$;
|
||||||
|
var $win = $(window);
|
||||||
|
new Vue({
|
||||||
|
el: '#LAY-app',
|
||||||
|
data: {
|
||||||
|
newUserWeekCount: 0,
|
||||||
|
newUserWeekPercentage: 0,
|
||||||
|
loginCount: 0,
|
||||||
|
loginPercentage: 0,
|
||||||
|
userCount: 0,
|
||||||
|
userMonthNewCount: 0,
|
||||||
|
departmentCount: 0,
|
||||||
|
roleCount: 0,
|
||||||
|
positionCount: 0,
|
||||||
|
loginLoggerList: [],
|
||||||
|
userAdjustmentList: [],
|
||||||
|
departmentAdjustmentList: [],
|
||||||
|
userDepartmentAdjustmentList: [],
|
||||||
|
resizeTimeout: null,
|
||||||
|
loginEChart: null,
|
||||||
|
userTypeEChart: null,
|
||||||
|
temporaryPassword: '',
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
countUserWeek: function() {
|
||||||
|
var self = this;
|
||||||
|
top.restAjax.get('api/count/count-new-user-by-week', {}, null, function(code, data) {
|
||||||
|
self.newUserWeekCount = data.data.count;
|
||||||
|
self.userWeekPercentage = data.data.percentage;
|
||||||
|
self.$nextTick(function() {
|
||||||
|
$('#newUserWeekCount').animateNumbers(self.newUserWeekCount);
|
||||||
|
$('#newUserWeekPercentage').animateNumbers(self.userWeekPercentage);
|
||||||
|
});
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
countLogin: function() {
|
||||||
|
var self = this;
|
||||||
|
top.restAjax.get('api/count/count-login', {}, null, function(code, data) {
|
||||||
|
self.loginCount = data.data.count;
|
||||||
|
self.loginPercentage = data.data.percentage
|
||||||
|
self.$nextTick(function() {
|
||||||
|
$('#loginCount').animateNumbers(self.loginCount);
|
||||||
|
$('#loginPercentage').animateNumbers(self.loginPercentage);
|
||||||
|
});
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
countUser: function() {
|
||||||
|
var self = this;
|
||||||
|
top.restAjax.get('api/count/count-user', {}, null, function(code, data) {
|
||||||
|
self.userCount = data.data.count;
|
||||||
|
self.userMonthNewCount = data.data.newCount;
|
||||||
|
self.$nextTick(function() {
|
||||||
|
$('#userCount').animateNumbers(self.userCount);
|
||||||
|
$('#userMonthNewCount').animateNumbers(self.userMonthNewCount);
|
||||||
|
});
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
countDepartment: function() {
|
||||||
|
var self = this;
|
||||||
|
top.restAjax.get('api/count/count-department', {}, null, function(code, data) {
|
||||||
|
self.departmentCount = data.data;
|
||||||
|
self.$nextTick(function() {
|
||||||
|
$('#departmentCount').animateNumbers(self.departmentCount);
|
||||||
|
});
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
countRole: function() {
|
||||||
|
var self = this;
|
||||||
|
top.restAjax.get('api/count/count-role', {}, null, function(code, data) {
|
||||||
|
self.roleCount = data.data;
|
||||||
|
self.$nextTick(function() {
|
||||||
|
$('#roleCount').animateNumbers(self.roleCount);
|
||||||
|
});
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
countPosition: function() {
|
||||||
|
var self = this;
|
||||||
|
top.restAjax.get('api/count/count-position', {}, null, function(code, data) {
|
||||||
|
self.positionCount = data.data;
|
||||||
|
self.$nextTick(function() {
|
||||||
|
$('#positionCount').animateNumbers(self.positionCount);
|
||||||
|
});
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
initLoginEChart: function() {
|
||||||
|
var self = this;
|
||||||
|
if(self.loginEChart) {
|
||||||
|
self.loginEChart.resize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
top.restAjax.get('api/count/count-login-for-days/10', {}, null, function(code, data) {
|
||||||
|
self.loginEChart = echarts.init(document.getElementById('loginEChart'));
|
||||||
|
self.loginEChart.setOption({
|
||||||
|
title: {
|
||||||
|
text: '近期系统登录情况'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross',
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#6a7985'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '3%',
|
||||||
|
containLabel: true,
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['登录人数']
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: data.data.dateArray,
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: '登录人数',
|
||||||
|
data: data.data.loginCountArray,
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
stack: '总数',
|
||||||
|
areaStyle: {},
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
initUserTypeEChart: function() {
|
||||||
|
var self = this;
|
||||||
|
if(self.userTypeEChart) {
|
||||||
|
self.userTypeEChart.resize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
top.restAjax.get('api/count/count-user-type-proportion', {}, null, function(code, data) {
|
||||||
|
self.userTypeEChart = echarts.init(document.getElementById('userTypeEChart'));
|
||||||
|
var legendData = [];
|
||||||
|
var seriesData = [];
|
||||||
|
for(var i = 0, item; item = data.data[i++];) {
|
||||||
|
legendData.push(item.name);
|
||||||
|
seriesData.push({
|
||||||
|
name: item.name,
|
||||||
|
value: item.value,
|
||||||
|
itemStyle: {
|
||||||
|
color: item.color
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
self.userTypeEChart.setOption({
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
orient: 'vertical',
|
||||||
|
left: 10,
|
||||||
|
data: legendData
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '用户类型占比',
|
||||||
|
type: 'pie',
|
||||||
|
radius: '66%',
|
||||||
|
avoidLabelOverlap: false,
|
||||||
|
label: {
|
||||||
|
formatter: '{b|{b}}\n{hr|}\n {c|{c}} {per|{d}%} ',
|
||||||
|
backgroundColor: '#eee',
|
||||||
|
borderColor: '#aaa',
|
||||||
|
borderWidth: 0.5,
|
||||||
|
borderRadius: 4,
|
||||||
|
rich: {
|
||||||
|
b: {
|
||||||
|
fontSize: 14,
|
||||||
|
lineHeight: 22,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
hr: {
|
||||||
|
borderColor: '#aaa',
|
||||||
|
width: '100%',
|
||||||
|
borderWidth: 0.5,
|
||||||
|
height: 0
|
||||||
|
},
|
||||||
|
per: {
|
||||||
|
color: '#eee',
|
||||||
|
backgroundColor: '#334455',
|
||||||
|
padding: [2, 4],
|
||||||
|
borderRadius: 2
|
||||||
|
},
|
||||||
|
c: {
|
||||||
|
fontSize: 14,
|
||||||
|
lineHeight: 22,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
fontSize: '14',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: seriesData
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
initUserStateEChart: function() {
|
||||||
|
var self = this;
|
||||||
|
if(self.userStateEChart) {
|
||||||
|
self.userStateEChart.resize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
top.restAjax.get('api/count/count-user-state-proportion', {}, null, function(code, data) {
|
||||||
|
self.userStateEChart = echarts.init(document.getElementById('userStateEChart'));
|
||||||
|
var legendData = [];
|
||||||
|
var seriesData = [];
|
||||||
|
for(var i = 0, item; item = data.data[i++];) {
|
||||||
|
legendData.push(item.name);
|
||||||
|
seriesData.push({
|
||||||
|
name: item.name,
|
||||||
|
value: item.value,
|
||||||
|
itemStyle: {
|
||||||
|
color: item.color
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
self.userStateEChart.setOption({
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
orient: 'vertical',
|
||||||
|
left: 10,
|
||||||
|
data: legendData
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '用户状态占比',
|
||||||
|
type: 'pie',
|
||||||
|
radius: '66%',
|
||||||
|
avoidLabelOverlap: false,
|
||||||
|
label: {
|
||||||
|
formatter: '{b|{b}}\n{hr|}\n {c|{c}} {per|{d}%} ',
|
||||||
|
backgroundColor: '#eee',
|
||||||
|
borderColor: '#aaa',
|
||||||
|
borderWidth: 0.5,
|
||||||
|
borderRadius: 4,
|
||||||
|
rich: {
|
||||||
|
b: {
|
||||||
|
fontSize: 14,
|
||||||
|
lineHeight: 22,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
hr: {
|
||||||
|
borderColor: '#aaa',
|
||||||
|
width: '100%',
|
||||||
|
borderWidth: 0.5,
|
||||||
|
height: 0
|
||||||
|
},
|
||||||
|
per: {
|
||||||
|
color: '#eee',
|
||||||
|
backgroundColor: '#334455',
|
||||||
|
padding: [2, 4],
|
||||||
|
borderRadius: 2
|
||||||
|
},
|
||||||
|
c: {
|
||||||
|
fontSize: 14,
|
||||||
|
lineHeight: 22,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
fontSize: '14',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: seriesData
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
initLoginLogger: function() {
|
||||||
|
var self = this;
|
||||||
|
top.restAjax.get(top.restAjax.path('api/log/listpage/login-log', []), {
|
||||||
|
page: 1,
|
||||||
|
rows: 10
|
||||||
|
}, null, function(code, data) {
|
||||||
|
self.loginLoggerList = data.rows;
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
initUserAdjustment: function() {
|
||||||
|
var self = this;
|
||||||
|
top.restAjax.get(top.restAjax.path('api/log/listpage/user-adjustment', []), {
|
||||||
|
page: 1,
|
||||||
|
rows: 10
|
||||||
|
}, null, function(code, data) {
|
||||||
|
self.userAdjustmentList = data.rows;
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getTemporaryPassword: function() {
|
||||||
|
var self = this;
|
||||||
|
top.restAjax.get('api/systemuser/get-temporary-password', {}, null, function(code, data) {
|
||||||
|
self.temporaryPassword = data.data;
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onGenerateTemporaryPassword: function() {
|
||||||
|
var self = this;
|
||||||
|
top.restAjax.get('api/systemuser/generate-temporary-password', {}, null, function(code, data) {
|
||||||
|
self.temporaryPassword = data.data;
|
||||||
|
}, function(code, data) {
|
||||||
|
top.dialog.msg(data.msg)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onCopyTemporaryPassword: function() {
|
||||||
|
const input = document.getElementById('temporaryPassword');
|
||||||
|
input.select();
|
||||||
|
try {
|
||||||
|
const successful = document.execCommand('copy');
|
||||||
|
if (successful) {
|
||||||
|
top.dialog.msg('复制成功');
|
||||||
|
} else {
|
||||||
|
top.dialog.msg('复制失败');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
top.dialog.msg('复制时出错:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted: function() {
|
||||||
|
var self = this;
|
||||||
|
self.countUserWeek();
|
||||||
|
self.countLogin();
|
||||||
|
self.countUser();
|
||||||
|
self.countDepartment();
|
||||||
|
self.countRole();
|
||||||
|
self.countPosition();
|
||||||
|
self.initLoginEChart();
|
||||||
|
self.initUserTypeEChart();
|
||||||
|
self.initUserStateEChart();
|
||||||
|
self.initLoginLogger();
|
||||||
|
self.initUserAdjustment();
|
||||||
|
self.getTemporaryPassword();
|
||||||
|
// 事件 - 页面变化
|
||||||
|
$win.on('resize', function() {
|
||||||
|
if(self.resizeTimeout) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.resizeTimeout = setTimeout(function() {
|
||||||
|
self.initLoginEChart();
|
||||||
|
self.initUserTypeEChart();
|
||||||
|
self.initUserStateEChart();
|
||||||
|
self.resizeTimeout = null;
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
51
src/main/resources/templates/systemuser/system-select.html
Normal file
51
src/main/resources/templates/systemuser/system-select.html
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<base th:href="${#request.getContextPath() + '/'}">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="renderer" content="webkit">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||||
|
<title>AI喵著</title>
|
||||||
|
<style>
|
||||||
|
html, body {margin: 0;padding: 0;height: 100%;}
|
||||||
|
.container {width: 100%;height: 100%; display: flex; justify-content: center; align-items: center;}
|
||||||
|
.container .systems {display: flex; }
|
||||||
|
.container .systems .system {width: 200px; height: 200px; margin: 10px; cursor: pointer; border-radius: 5px; box-shadow: 0 0 5px silver; padding: 15px; box-sizing: border-box; display: flex; flex-direction: column; justify-content: center; align-items: center;}
|
||||||
|
.container .systems .system .logo {}
|
||||||
|
.container .systems .system .title {margin-top: 10px;}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="systems">
|
||||||
|
<div class="system" data-href="/operator/default-main">
|
||||||
|
<div class="logo"></div>
|
||||||
|
<div class="title">统一用户</div>
|
||||||
|
</div>
|
||||||
|
<div class="system" data-href="/operator-plugin">
|
||||||
|
<div class="logo"></div>
|
||||||
|
<div class="title">运营平台</div>
|
||||||
|
</div>
|
||||||
|
<div class="system" data-href="/copyright">
|
||||||
|
<div class="logo"></div>
|
||||||
|
<div class="title">喵著系统</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="assets/layuiadmin/layui/layui.js"></script>
|
||||||
|
<script>
|
||||||
|
layui.config({
|
||||||
|
base: 'assets/layuiadmin/' //静态资源所在路径
|
||||||
|
}).extend({
|
||||||
|
index: 'lib/index' //主入口模块
|
||||||
|
}).use(['index', 'animate-numbers'], function() {
|
||||||
|
var $ = layui.$;
|
||||||
|
$('.system').on('click', function() {
|
||||||
|
var href = $(this).data('href');
|
||||||
|
window.location.href = href;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
21
src/main/resources/templates/systemuser/temporary-login.html
Normal file
21
src/main/resources/templates/systemuser/temporary-login.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<base th:href="${#request.getContextPath() + '/'}">
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>临时登录</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form action="oauth/temporary/login" method="post" enctype="application/x-www-form-urlencoded">
|
||||||
|
<div>
|
||||||
|
<label for="username">用户名:</label>
|
||||||
|
<input type="text" id="username" name="username" placeholder="输入用户名"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="password">密码:</label>
|
||||||
|
<input type="password" id="password" name="password" placeholder="输入密码"/>
|
||||||
|
</div>
|
||||||
|
<button type="submit">登录</button>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user