Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
spring-microservice-exam
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
汪想
spring-microservice-exam
Commits
11d480f6
Commit
11d480f6
authored
Mar 01, 2020
by
tangyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
优化登录
parent
b24c210c
Hide whitespace changes
Inline
Side-by-side
Showing
46 changed files
with
792 additions
and
201 deletions
+792
-201
.gitignore
.gitignore
+2
-2
ApiMsg.java
...n/java/com/github/tangyi/common/core/constant/ApiMsg.java
+5
-0
CustomResourceServerConfig.java
...yi/common/security/config/CustomResourceServerConfig.java
+19
-1
CustomOauthException.java
...angyi/common/security/exception/CustomOauthException.java
+19
-0
CustomAccessDeniedHandler.java
...yi/common/security/handler/CustomAccessDeniedHandler.java
+39
-0
CustomOauthExceptionSerializer.java
...n/security/serializer/CustomOauthExceptionSerializer.java
+36
-0
auth-service.yml
config-service/src/main/resources/config/auth-service.yml
+3
-4
exam-service.yml
config-service/src/main/resources/config/exam-service.yml
+3
-6
gateway-service.yml
config-service/src/main/resources/config/gateway-service.yml
+1
-2
user-service.yml
config-service/src/main/resources/config/user-service.yml
+3
-7
microservice_user.sql
docs/deploy/mysql/init/microservice_user.sql
+0
-16
image_web_incorrect_answer.png
docs/images/image_web_incorrect_answer.png
+0
-0
image_web_record.png
docs/images/image_web_record.png
+0
-0
user.js
frontend/spring-microservice-exam-ui/src/api/admin/user.js
+2
-2
logo.png
frontend/spring-microservice-exam-ui/src/assets/logo.png
+0
-0
errorCode.js
frontend/spring-microservice-exam-ui/src/const/errorCode.js
+3
-0
permission.js
frontend/spring-microservice-exam-ui/src/permission.js
+1
-1
axios.js
frontend/spring-microservice-exam-ui/src/router/axios.js
+18
-4
index.js
frontend/spring-microservice-exam-ui/src/router/index.js
+13
-0
500.vue
...d/spring-microservice-exam-ui/src/views/errorPage/500.vue
+219
-0
examSubjects.vue
...ring-microservice-exam-ui/src/views/exam/examSubjects.vue
+2
-2
user.vue
frontend/spring-microservice-exam-ui/src/views/sys/user.vue
+1
-1
login.js
frontend/spring-microservice-exam-web/src/api/admin/login.js
+1
-1
user.js
frontend/spring-microservice-exam-web/src/api/admin/user.js
+2
-2
examRecord.js
...d/spring-microservice-exam-web/src/api/exam/examRecord.js
+8
-0
errorCode.js
frontend/spring-microservice-exam-web/src/const/errorCode.js
+3
-0
index.js
frontend/spring-microservice-exam-web/src/filters/index.js
+98
-0
main.js
frontend/spring-microservice-exam-web/src/main.js
+5
-0
axios.js
frontend/spring-microservice-exam-web/src/router/axios.js
+12
-4
constant.js
frontend/spring-microservice-exam-web/src/utils/constant.js
+32
-0
util.js
frontend/spring-microservice-exam-web/src/utils/util.js
+24
-0
examRecords.vue
...ring-microservice-exam-web/src/views/exam/examRecords.vue
+3
-68
incorrect.vue
...spring-microservice-exam-web/src/views/exam/incorrect.vue
+111
-40
CustomAuthorizationServerConfigurer.java
...ngyi/auth/config/CustomAuthorizationServerConfigurer.java
+27
-1
LoginSuccessListener.java
...com/github/tangyi/auth/listener/LoginSuccessListener.java
+2
-1
CustomUserDetails.java
.../java/com/github/tangyi/auth/model/CustomUserDetails.java
+7
-1
CustomUserDetailsAuthenticationProvider.java
...uth/security/CustomUserDetailsAuthenticationProvider.java
+4
-6
CustomUserDetailsServiceImpl.java
...ub/tangyi/auth/security/CustomUserDetailsServiceImpl.java
+3
-3
MultipleChoicesAnswerHandler.java
...angyi/exam/handler/impl/MultipleChoicesAnswerHandler.java
+4
-3
UserServiceClient.java
...a/com/github/tangyi/user/api/feign/UserServiceClient.java
+9
-9
UserServiceClientFallbackImpl.java
...ser/api/feign/fallback/UserServiceClientFallbackImpl.java
+3
-3
MenuController.java
...ava/com/github/tangyi/user/controller/MenuController.java
+2
-2
TenantController.java
...a/com/github/tangyi/user/controller/TenantController.java
+1
-1
UserController.java
...ava/com/github/tangyi/user/controller/UserController.java
+35
-5
UserService.java
...main/java/com/github/tangyi/user/service/UserService.java
+4
-2
UserMapper.xml
...ent/user-service/src/main/resources/mapper/UserMapper.xml
+3
-1
No files found.
.gitignore
View file @
11d480f6
...
...
@@ -21,4 +21,4 @@ intellij/
atlassian-ide-plugin.xml
!etc/eclipse/.checkstyle
.checkstyle
docs/deploy/dev.env
\ No newline at end of file
.dev.env
\ No newline at end of file
common/common-core/src/main/java/com/github/tangyi/common/core/constant/ApiMsg.java
View file @
11d480f6
...
...
@@ -96,6 +96,11 @@ public class ApiMsg {
public
static
final
int
KEY_ACCESS
=
404
;
/**
* 认证
*/
public
static
final
int
KEY_AUTHENTICATION
=
405
;
/**
* code和提示内容的对应关系
*/
private
static
final
Map
<
Integer
,
String
>
CODE_MAP
=
new
HashMap
<>();
...
...
common/common-security/src/main/java/com/github/tangyi/common/security/config/CustomResourceServerConfig.java
View file @
11d480f6
package
com
.
github
.
tangyi
.
common
.
security
.
config
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.github.tangyi.common.security.handler.CustomAccessDeniedHandler
;
import
com.github.tangyi.common.security.mobile.MobileSecurityConfigurer
;
import
com.github.tangyi.common.security.properties.FilterIgnorePropertiesConfig
;
import
com.github.tangyi.common.security.wx.WxSecurityConfigurer
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity
;
import
org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer
;
import
org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter
;
import
org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer
;
import
org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler
;
import
org.springframework.security.web.access.AccessDeniedHandler
;
/**
* 资源服务器配置
...
...
@@ -38,16 +43,23 @@ public class CustomResourceServerConfig extends ResourceServerConfigurerAdapter
*/
private
final
WxSecurityConfigurer
wxSecurityConfigurer
;
private
final
ObjectMapper
objectMapper
;
@Autowired
public
CustomResourceServerConfig
(
FilterIgnorePropertiesConfig
filterIgnorePropertiesConfig
,
MobileSecurityConfigurer
mobileSecurityConfigurer
,
WxSecurityConfigurer
wxSecurityConfigurer
)
{
public
CustomResourceServerConfig
(
FilterIgnorePropertiesConfig
filterIgnorePropertiesConfig
,
MobileSecurityConfigurer
mobileSecurityConfigurer
,
WxSecurityConfigurer
wxSecurityConfigurer
,
ObjectMapper
objectMapper
)
{
this
.
filterIgnorePropertiesConfig
=
filterIgnorePropertiesConfig
;
this
.
mobileSecurityConfigurer
=
mobileSecurityConfigurer
;
this
.
wxSecurityConfigurer
=
wxSecurityConfigurer
;
this
.
objectMapper
=
objectMapper
;
}
@Override
public
void
configure
(
ResourceServerSecurityConfigurer
resources
)
{
resources
.
resourceId
(
RESOURCE_ID
).
stateless
(
false
);
resources
.
accessDeniedHandler
(
accessDeniedHandler
());
}
@Override
...
...
@@ -65,4 +77,10 @@ public class CustomResourceServerConfig extends ResourceServerConfigurerAdapter
// 微信登录
http
.
apply
(
wxSecurityConfigurer
);
}
@Bean
@ConditionalOnMissingBean
(
AccessDeniedHandler
.
class
)
public
AccessDeniedHandler
accessDeniedHandler
()
{
return
new
CustomAccessDeniedHandler
(
objectMapper
);
}
}
common/common-security/src/main/java/com/github/tangyi/common/security/exception/CustomOauthException.java
0 → 100644
View file @
11d480f6
package
com
.
github
.
tangyi
.
common
.
security
.
exception
;
import
com.fasterxml.jackson.databind.annotation.JsonSerialize
;
import
com.github.tangyi.common.security.serializer.CustomOauthExceptionSerializer
;
import
org.springframework.security.oauth2.common.exceptions.OAuth2Exception
;
/**
* 自定义OauthException
*
* @author tangyi
* @date 2020/2/29 14:12
*/
@JsonSerialize
(
using
=
CustomOauthExceptionSerializer
.
class
)
public
class
CustomOauthException
extends
OAuth2Exception
{
public
CustomOauthException
(
String
msg
)
{
super
(
msg
);
}
}
common/common-security/src/main/java/com/github/tangyi/common/security/handler/CustomAccessDeniedHandler.java
0 → 100644
View file @
11d480f6
package
com
.
github
.
tangyi
.
common
.
security
.
handler
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.security.access.AccessDeniedException
;
import
org.springframework.security.web.access.AccessDeniedHandler
;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.IOException
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* 自定义AccessDeniedHandler
*
* @author tangyi
* @date 2020-02-29 15:39
*/
public
class
CustomAccessDeniedHandler
implements
AccessDeniedHandler
{
private
final
ObjectMapper
objectMapper
;
public
CustomAccessDeniedHandler
(
ObjectMapper
objectMapper
)
{
this
.
objectMapper
=
objectMapper
;
}
@Override
public
void
handle
(
HttpServletRequest
request
,
HttpServletResponse
response
,
AccessDeniedException
e
)
throws
IOException
,
ServletException
{
response
.
setContentType
(
"application/json;charset=UTF-8"
);
Map
<
String
,
Object
>
map
=
new
HashMap
<>();
map
.
put
(
"code"
,
400
);
map
.
put
(
"msg"
,
e
.
getMessage
());
map
.
put
(
"data"
,
e
.
getMessage
());
response
.
setStatus
(
HttpServletResponse
.
SC_UNAUTHORIZED
);
response
.
getWriter
().
write
(
objectMapper
.
writeValueAsString
(
map
));
}
}
common/common-security/src/main/java/com/github/tangyi/common/security/serializer/CustomOauthExceptionSerializer.java
0 → 100644
View file @
11d480f6
package
com
.
github
.
tangyi
.
common
.
security
.
serializer
;
import
com.fasterxml.jackson.core.JsonGenerator
;
import
com.fasterxml.jackson.databind.SerializerProvider
;
import
com.fasterxml.jackson.databind.ser.std.StdSerializer
;
import
com.github.tangyi.common.security.exception.CustomOauthException
;
import
java.io.IOException
;
import
java.util.Map
;
/**
* 自定义OauthException Serializer,定制异常返回结果
*
* @author tangyi
* @date 2020/2/29 14:12
*/
public
class
CustomOauthExceptionSerializer
extends
StdSerializer
<
CustomOauthException
>
{
public
CustomOauthExceptionSerializer
()
{
super
(
CustomOauthException
.
class
);
}
@Override
public
void
serialize
(
CustomOauthException
e
,
JsonGenerator
jsonGenerator
,
SerializerProvider
serializerProvider
)
throws
IOException
{
jsonGenerator
.
writeStartObject
();
jsonGenerator
.
writeNumberField
(
"code"
,
e
.
getHttpErrorCode
());
jsonGenerator
.
writeStringField
(
"msg"
,
e
.
getMessage
());
jsonGenerator
.
writeObjectField
(
"data"
,
e
.
getOAuth2ErrorCode
());
if
(
e
.
getAdditionalInformation
()
!=
null
)
{
for
(
Map
.
Entry
<
String
,
String
>
entry
:
e
.
getAdditionalInformation
().
entrySet
())
{
jsonGenerator
.
writeStringField
(
entry
.
getKey
(),
entry
.
getValue
());
}
}
jsonGenerator
.
writeEndObject
();
}
}
config-service/src/main/resources/config/auth-service.yml
View file @
11d480f6
...
...
@@ -91,12 +91,11 @@ ignore:
-
/actuator/**
-
/hystrix.sender
-
/v1/sms/**
-
/v1/user/
findUserByIdentifi
er/**
-
/v1/tenant/
findTenantByTenantCode
/**
-
/v1/user/
anonymousUs
er/**
-
/v1/tenant/
anonymousUser
/**
-
/v1/user/checkExist/**
-
/v1/user/updatePassword
-
/v1/menu/findMenuByRole/**
-
/v1/menu/findAllMenu
-
/v1/menu/anonymousUser/**
-
/v1/code/**
-
/v1/attachment/download
-
/v1/log/**
...
...
config-service/src/main/resources/config/exam-service.yml
View file @
11d480f6
...
...
@@ -119,12 +119,9 @@ ignore:
-
/actuator/**
-
/hystrix.sender
-
/v1/sms/**
-
/v1/user/findUserByIdentifier/**
-
/v1/tenant/findTenantByTenantCode/**
-
/v1/menu/findMenuByRole/**
-
/v1/menu/findAllMenu
-
/v1/user/checkExist/**
-
/v1/user/updatePassword
-
/v1/user/anonymousUser/**
-
/v1/tenant/anonymousUser/**
-
/v1/menu/anonymousUser/**
-
/v1/code/**
-
/v1/attachment/download
-
/v1/log/**
...
...
config-service/src/main/resources/config/gateway-service.yml
View file @
11d480f6
...
...
@@ -110,8 +110,7 @@ swagger:
preview
:
ignores
:
-
api/auth
# 授权服务
-
register
-
checkExist
-
anonymousUser
-
updateInfo
-
updateAvatar
-
attachment
...
...
config-service/src/main/resources/config/user-service.yml
View file @
11d480f6
...
...
@@ -153,13 +153,9 @@ ignore:
-
/hystrix.sender
-
/v1/sms/**
-
/v1/mobile/**
-
/v1/user/findUserByIdentifier/**
-
/v1/tenant/findTenantByTenantCode/**
-
/v1/menu/findMenuByRole/**
-
/v1/menu/findAllMenu
-
/v1/user/register
-
/v1/user/checkExist/**
-
/v1/user/updatePassword
-
/v1/user/anonymousUser/**
-
/v1/tenant/anonymousUser/**
-
/v1/menu/anonymousUser/**
-
/v1/code/**
-
/v1/attachment/download
-
/v1/log/**
...
...
docs/deploy/mysql/init/microservice_user.sql
View file @
11d480f6
/*
Navicat Premium Data Transfer
Source Server : 腾讯云-上海
Source Server Type : MySQL
Source Server Version : 50644
Source Host : 118.25.138.130:3306
Source Schema : dev_microservice_user
Target Server Type : MySQL
Target Server Version : 50644
File Encoding : 65001
Date: 23/02/2020 16:29:29
*/
SET
NAMES
utf8mb4
;
SET
FOREIGN_KEY_CHECKS
=
0
;
...
...
docs/images/image_web_incorrect_answer.png
View replaced file @
b24c210c
View file @
11d480f6
266 KB
|
W:
|
H:
219 KB
|
W:
|
H:
2-up
Swipe
Onion skin
docs/images/image_web_record.png
View replaced file @
b24c210c
View file @
11d480f6
196 KB
|
W:
|
H:
131 KB
|
W:
|
H:
2-up
Swipe
Onion skin
frontend/spring-microservice-exam-ui/src/api/admin/user.js
View file @
11d480f6
...
...
@@ -50,7 +50,7 @@ export function updateObjInfo (obj) {
export
function
updatePassword
(
obj
)
{
return
request
({
url
:
baseUserUrl
+
'updatePassword'
,
url
:
baseUserUrl
+
'
anonymousUser/
updatePassword'
,
method
:
'put'
,
data
:
obj
})
...
...
@@ -86,7 +86,7 @@ export function exportObj (obj) {
// 重置密码
export
function
resetPassword
(
obj
)
{
return
request
({
url
:
baseUserUrl
+
'resetPassword'
,
url
:
baseUserUrl
+
'
anonymousUser/
resetPassword'
,
method
:
'put'
,
data
:
obj
})
...
...
frontend/spring-microservice-exam-ui/src/assets/logo.png
deleted
100644 → 0
View file @
b24c210c
75.5 KB
frontend/spring-microservice-exam-ui/src/const/errorCode.js
View file @
11d480f6
...
...
@@ -5,5 +5,8 @@ export default {
'403'
:
'当前操作没有权限'
,
'400'
:
'用户名不存在或密码错误'
,
'500'
:
'服务器内部错误,请反馈给管理员'
,
'4015'
:
'服务不可用'
,
'4020'
:
'验证码错误'
,
'4026'
:
'验证码已过期,请重新获取'
,
'default'
:
'系统未知错误,请反馈给管理员'
}
frontend/spring-microservice-exam-ui/src/permission.js
View file @
11d480f6
...
...
@@ -13,7 +13,7 @@ function hasPermission (roles, permissionRoles) {
return
roles
.
some
(
role
=>
permissionRoles
.
indexOf
(
role
)
>=
0
)
}
const
whiteList
=
[
'/login'
,
'/auth-redirect'
,
'/404'
,
'/401'
,
'/lock'
]
// no redirect whitelist
const
whiteList
=
[
'/login'
,
'/auth-redirect'
,
'/404'
,
'/401'
,
'/
500'
,
'/
lock'
]
// no redirect whitelist
router
.
beforeEach
((
to
,
from
,
next
)
=>
{
NProgress
.
start
()
// start progress bar
...
...
frontend/spring-microservice-exam-ui/src/router/axios.js
View file @
11d480f6
import
axios
from
'axios'
import
store
from
'../store'
import
router
from
'./index'
import
{
getToken
,
setToken
,
getRefreshToken
,
getTenantCode
}
from
'@/utils/auth'
import
{
isNotEmpty
,
isSuccess
}
from
'@/utils/util'
import
{
refreshToken
}
from
'@/api/admin/login'
...
...
@@ -39,7 +40,9 @@ axios.interceptors.response.use(data => {
NProgress
.
done
()
// 请求失败,弹出提示信息
if
(
!
isSuccess
(
data
.
data
))
{
Message
({
message
:
data
.
data
.
msg
,
type
:
'error'
})
const
{
code
,
msg
}
=
data
.
data
const
errMsg
=
errorCode
[
String
(
code
)]
||
msg
||
errorCode
[
'default'
]
Message
({
message
:
errMsg
,
type
:
'error'
})
}
return
data
},
error
=>
{
...
...
@@ -67,11 +70,22 @@ axios.interceptors.response.use(data => {
})
}
else
if
(
error
.
response
.
status
===
423
)
{
Message
({
message
:
'演示环境不能操作'
,
type
:
'warning'
})
}
else
if
(
error
.
response
.
status
===
404
)
{
// 跳转到404页面
router
.
replace
({
path
:
'404'
,
query
:
{
redirect
:
router
.
currentRoute
.
fullPath
}
})
}
else
if
(
error
.
response
.
status
===
500
)
{
// 500提示页面
router
.
replace
({
path
:
'500'
,
query
:
{
redirect
:
router
.
currentRoute
.
fullPath
}
})
}
else
{
// 其它错误则弹出提示
const
{
code
,
data
}
=
error
.
response
.
data
const
errMsg
=
data
||
errorCode
[
code
]
||
errorCode
[
'default'
]
// TODO 跳转到对应的404、500提示页面
const
{
code
,
msg
}
=
error
.
response
.
data
const
errMsg
=
errorCode
[
String
(
code
)]
||
msg
||
errorCode
[
'default'
]
Message
({
message
:
errMsg
,
type
:
'error'
})
}
}
...
...
frontend/spring-microservice-exam-ui/src/router/index.js
View file @
11d480f6
...
...
@@ -47,6 +47,19 @@ export const constantRouterMap = [
hidden
:
true
},
{
path
:
'/500'
,
component
:
Layout
,
children
:
[
{
path
:
''
,
component
:
()
=>
import
(
'@/views/errorPage/500'
),
name
:
'500'
,
title
:
'500'
}
],
hidden
:
true
},
{
path
:
'/404'
,
component
:
Layout
,
children
:
[
...
...
frontend/spring-microservice-exam-ui/src/views/errorPage/500.vue
0 → 100644
View file @
11d480f6
<
template
>
<div
class=
"wscn-http500-container"
>
<div
class=
"wscn-http500"
>
<div
class=
"bullshit"
>
<div
class=
"bullshit__oops"
>
500
</div>
<div
class=
"bullshit__headline"
>
{{
message
}}
</div>
<div
class=
"bullshit__info"
>
服务器内部错误,请联系管理员
</div>
<a
href=
""
class=
"bullshit__return-home"
>
返回首页
</a>
</div>
</div>
</div>
</
template
>
<
script
>
export
default
{
name
:
'Page500'
,
computed
:
{
message
()
{
return
'服务器内部错误......'
}
}
}
</
script
>
<
style
rel=
"stylesheet/scss"
lang=
"scss"
scoped
>
.wscn-http500-container
{
transform
:
translate
(
-50%
,-
50%
);
position
:
absolute
;
top
:
40%
;
left
:
50%
;
}
.wscn-http500
{
position
:
relative
;
width
:
1200px
;
padding
:
0
50px
;
overflow
:
hidden
;
.pic-500
{
position
:
relative
;
float
:
left
;
width
:
600px
;
overflow
:
hidden
;
&
__parent
{
width
:
100%
;
}
&
__child
{
position
:
absolute
;
&
.left
{
width
:
80px
;
top
:
17px
;
left
:
220px
;
opacity
:
0
;
animation-name
:
cloudLeft
;
animation-duration
:
2s
;
animation-timing-function
:
linear
;
animation-fill-mode
:
forwards
;
animation-delay
:
1s
;
}
&
.mid
{
width
:
46px
;
top
:
10px
;
left
:
420px
;
opacity
:
0
;
animation-name
:
cloudMid
;
animation-duration
:
2s
;
animation-timing-function
:
linear
;
animation-fill-mode
:
forwards
;
animation-delay
:
1
.2s
;
}
&
.right
{
width
:
62px
;
top
:
100px
;
left
:
500px
;
opacity
:
0
;
animation-name
:
cloudRight
;
animation-duration
:
2s
;
animation-timing-function
:
linear
;
animation-fill-mode
:
forwards
;
animation-delay
:
1s
;
}
@keyframes
cloudLeft
{
0
%
{
top
:
17px
;
left
:
220px
;
opacity
:
0
;
}
20
%
{
top
:
33px
;
left
:
188px
;
opacity
:
1
;
}
80
%
{
top
:
81px
;
left
:
92px
;
opacity
:
1
;
}
100
%
{
top
:
97px
;
left
:
60px
;
opacity
:
0
;
}
}
@keyframes
cloudMid
{
0
%
{
top
:
10px
;
left
:
420px
;
opacity
:
0
;
}
20
%
{
top
:
40px
;
left
:
360px
;
opacity
:
1
;
}
70
%
{
top
:
130px
;
left
:
180px
;
opacity
:
1
;
}
100
%
{
top
:
160px
;
left
:
120px
;
opacity
:
0
;
}
}
@keyframes
cloudRight
{
0
%
{
top
:
100px
;
left
:
500px
;
opacity
:
0
;
}
20
%
{
top
:
120px
;
left
:
460px
;
opacity
:
1
;
}
80
%
{
top
:
180px
;
left
:
340px
;
opacity
:
1
;
}
100
%
{
top
:
200px
;
left
:
300px
;
opacity
:
0
;
}
}
}
}
.bullshit
{
position
:
relative
;
float
:
left
;
width
:
300px
;
padding
:
30px
0
;
overflow
:
hidden
;
&
__oops
{
font-size
:
32px
;
font-weight
:
bold
;
line-height
:
40px
;
color
:
#1482f0
;
opacity
:
0
;
margin-bottom
:
20px
;
animation-name
:
slideUp
;
animation-duration
:
0
.5s
;
animation-fill-mode
:
forwards
;
}
&
__headline
{
font-size
:
20px
;
line-height
:
24px
;
color
:
#222
;
font-weight
:
bold
;
opacity
:
0
;
margin-bottom
:
10px
;
animation-name
:
slideUp
;
animation-duration
:
0
.5s
;
animation-delay
:
0
.1s
;
animation-fill-mode
:
forwards
;
}
&
__info
{
font-size
:
13px
;
line-height
:
21px
;
color
:
grey
;
opacity
:
0
;
margin-bottom
:
30px
;
animation-name
:
slideUp
;
animation-duration
:
0
.5s
;
animation-delay
:
0
.2s
;
animation-fill-mode
:
forwards
;
}
&
__return-home
{
display
:
block
;
float
:
left
;
width
:
110px
;
height
:
36px
;
background
:
#1482f0
;
border-radius
:
100px
;
text-align
:
center
;
color
:
#ffffff
;
opacity
:
0
;
font-size
:
14px
;
line-height
:
36px
;
cursor
:
pointer
;
animation-name
:
slideUp
;
animation-duration
:
0
.5s
;
animation-delay
:
0
.3s
;
animation-fill-mode
:
forwards
;
}
@keyframes
slideUp
{
0
%
{
transform
:
translateY
(
60px
);
opacity
:
0
;
}
100
%
{
transform
:
translateY
(
0
);
opacity
:
1
;
}
}
}
}
</
style
>
frontend/spring-microservice-exam-ui/src/views/exam/examSubjects.vue
View file @
11d480f6
...
...
@@ -30,12 +30,12 @@
<span>
{{
scope
.
row
.
score
}}
</span>
</
template
>
</el-table-column>
<el-table-column
:label=
"$t('table.
subject.
modifyDate')"
property=
"updateTime"
width=
"150"
>
<el-table-column
:label=
"$t('table.modifyDate')"
property=
"updateTime"
width=
"150"
>
<
template
slot-scope=
"scope"
>
<span>
{{
scope
.
row
.
modifyDate
|
fmtDate
(
'yyyy-MM-dd hh:mm'
)
}}
</span>
</
template
>
</el-table-column>
<el-table-column
:label=
"$t('table.
subject.
modifier')"
property=
"modifier"
width=
"120"
>
<el-table-column
:label=
"$t('table.modifier')"
property=
"modifier"
width=
"120"
>
<
template
slot-scope=
"scope"
>
<span>
{{
scope
.
row
.
modifier
}}
</span>
</
template
>
...
...
frontend/spring-microservice-exam-ui/src/views/sys/user.vue
View file @
11d480f6
...
...
@@ -53,7 +53,7 @@
<span>
{{
scope
.
row
.
loginTime
|
fmtDate
(
'yyyy-MM-dd hh:mm'
)
}}
</span>
</
template
>
</el-table-column>
<el-table-column
:label=
"$t('table.actions')"
class-name=
"status-col"
>
<el-table-column
:label=
"$t('table.actions')"
class-name=
"status-col"
width=
"300"
>
<
template
slot-scope=
"scope"
>
<el-button
v-if=
"user_btn_edit"
type=
"primary"
size=
"mini"
@
click=
"handleUpdate(scope.row)"
>
{{
$t
(
'table.edit'
)
}}
</el-button>
<el-button
v-if=
"user_btn_edit"
type=
"warning"
size=
"mini"
@
click=
"handleResetPassword(scope.row)"
>
{{
$t
(
'table.resetPassword'
)
}}
</el-button>
...
...
frontend/spring-microservice-exam-web/src/api/admin/login.js
View file @
11d480f6
...
...
@@ -38,7 +38,7 @@ export function loginBySocial (social, code) {
export
function
registerByUsername
(
identifier
,
email
,
credential
,
code
,
randomStr
)
{
return
request
({
url
:
'/api/user/v1/user/register'
,
url
:
'/api/user/v1/user/
anonymousUser/
register'
,
method
:
'post'
,
params
:
{
identifier
,
email
,
credential
,
randomStr
,
code
},
data
:
{
identifier
,
email
,
credential
}
...
...
frontend/spring-microservice-exam-web/src/api/admin/user.js
View file @
11d480f6
...
...
@@ -50,7 +50,7 @@ export function updateObjInfo (obj) {
export
function
updatePassword
(
obj
)
{
return
request
({
url
:
baseUserUrl
+
'updatePassword'
,
url
:
baseUserUrl
+
'
anonymousUser/
updatePassword'
,
method
:
'put'
,
data
:
obj
})
...
...
@@ -74,7 +74,7 @@ export function delAllObj (obj) {
export
function
checkExist
(
username
,
tenantCode
)
{
return
request
({
url
:
baseUserUrl
+
'checkExist/'
+
username
,
url
:
baseUserUrl
+
'
anonymousUser/
checkExist/'
+
username
,
method
:
'get'
,
params
:
{
tenantCode
,
identityType
:
1
}
})
...
...
frontend/spring-microservice-exam-web/src/api/exam/examRecord.js
View file @
11d480f6
...
...
@@ -40,3 +40,11 @@ export function getCurrentTime () {
method
:
'get'
})
}
// 查询成绩详情
export
function
examRecordDetails
(
id
)
{
return
request
({
url
:
baseExamRecordUrl
+
id
+
'/details'
,
method
:
'get'
})
}
frontend/spring-microservice-exam-web/src/const/errorCode.js
View file @
11d480f6
...
...
@@ -5,5 +5,8 @@ export default {
'403'
:
'当前操作没有权限'
,
'400'
:
'用户名不存在或密码错误'
,
'500'
:
'服务器内部错误,请反馈给管理员'
,
'4015'
:
'服务不可用'
,
'4020'
:
'验证码错误'
,
'4026'
:
'验证码已过期,请重新获取'
,
'default'
:
'系统未知错误,请反馈给管理员'
}
frontend/spring-microservice-exam-web/src/filters/index.js
0 → 100644
View file @
11d480f6
import
{
formatDate
,
commonFilter
,
isNotEmpty
}
from
'../utils/util'
import
{
statusType
,
examType
,
subjectType
,
subjectTypeTag
}
from
'../utils/constant'
/**
* 日期格式化
* @param date
* @param format
* @returns {*}
*/
export
function
fmtDate
(
date
,
format
)
{
if
(
!
isNotEmpty
(
date
))
{
return
''
}
return
formatDate
(
new
Date
(
date
),
format
)
}
/**
* 通用状态
* @param status
* @returns {*}
*/
export
function
statusTypeFilter
(
status
)
{
return
statusType
[
status
]
}
/**
* 截取指定长度
* @param str
* @param length
* @returns {string}
*/
export
function
simpleStrFilter
(
str
,
length
)
{
if
(
length
===
undefined
)
{
length
=
20
}
return
commonFilter
(
str
,
length
)
}
/**
* 考试类型
* @param type
* @returns {*}
*/
export
function
examTypeFilter
(
type
)
{
return
examType
[
type
]
}
/**
* 发布类型
* @param status
* @returns {string}
*/
export
function
publicStatusFilter
(
status
)
{
return
parseInt
(
status
)
===
0
?
'已发布'
:
'草稿'
}
/**
* 题目类型
* @param type
* @returns {*}
*/
export
function
subjectTypeFilter
(
type
)
{
return
subjectType
[
type
]
}
/**
* 题目标签
* @param type
* @returns {*}
*/
export
function
subjectTypeTagFilter
(
type
)
{
return
subjectTypeTag
[
type
]
}
/**
* 考试提交状态
* @param type
* @returns {*}
*/
export
function
submitStatusFilter
(
type
)
{
const
typeMap
=
{
0
:
'待批改'
,
1
:
'已批改'
,
2
:
'待批改'
,
3
:
'统计完成'
}
return
typeMap
[
type
]
}
/**
* success状态
* @param status, 自动传入
* @param expectStatus
* @returns {string}
*/
export
function
simpleTagStatusFilter
(
status
,
expectStatus
)
{
return
status
===
expectStatus
?
'success'
:
'warning'
}
frontend/spring-microservice-exam-web/src/main.js
View file @
11d480f6
...
...
@@ -8,11 +8,16 @@ import store from './store'
import
'./permission'
// 权限控制
import
'element-ui/lib/theme-chalk/index.css'
import
'./icons'
// icon
import
*
as
filters
from
'./filters'
// global filters
Vue
.
config
.
productionTip
=
false
Vue
.
use
(
ElementUI
)
Object
.
keys
(
filters
).
forEach
(
key
=>
{
Vue
.
filter
(
key
,
filters
[
key
])
})
/* eslint-disable no-new */
new
Vue
({
el
:
'#app'
,
...
...
frontend/spring-microservice-exam-web/src/router/axios.js
View file @
11d480f6
import
axios
from
'axios'
import
store
from
'../store'
import
router
from
'./index'
import
{
getToken
,
setToken
,
getRefreshToken
,
getTenantCode
}
from
'@/utils/auth'
import
{
isNotEmpty
,
isSuccess
}
from
'@/utils/util'
import
{
refreshToken
}
from
'@/api/admin/login'
...
...
@@ -39,7 +40,9 @@ axios.interceptors.response.use(data => {
NProgress
.
done
()
// 请求失败,弹出提示信息
if
(
!
isSuccess
(
data
.
data
))
{
Message
({
message
:
data
.
data
.
msg
,
type
:
'error'
})
const
{
code
,
msg
}
=
data
.
data
const
errMsg
=
errorCode
[
String
(
code
)]
||
msg
||
errorCode
[
'default'
]
Message
({
message
:
errMsg
,
type
:
'error'
})
}
return
data
},
error
=>
{
...
...
@@ -67,11 +70,16 @@ axios.interceptors.response.use(data => {
})
}
else
if
(
error
.
response
.
status
===
423
)
{
Message
({
message
:
'演示环境不能操作'
,
type
:
'warning'
})
}
else
if
(
error
.
response
.
status
===
404
)
{
// 跳转到404页面
router
.
replace
({
path
:
'404'
,
query
:
{
redirect
:
router
.
currentRoute
.
fullPath
}
})
}
else
{
// 其它错误则弹出提示
const
{
code
,
data
}
=
error
.
response
.
data
const
errMsg
=
data
||
errorCode
[
code
]
||
errorCode
[
'default'
]
// TODO 跳转到对应的404、500提示页面
const
{
code
,
msg
}
=
error
.
response
.
data
const
errMsg
=
errorCode
[
String
(
code
)]
||
msg
||
errorCode
[
'default'
]
Message
({
message
:
errMsg
,
type
:
'error'
})
}
}
...
...
frontend/spring-microservice-exam-web/src/utils/constant.js
0 → 100644
View file @
11d480f6
export
const
dialogStatusConstant
=
{
create
:
'create'
,
update
:
'update'
}
export
const
statusType
=
{
0
:
'success'
,
1
:
'warning'
}
// 考试类型
export
const
examType
=
{
0
:
'正式考试'
,
1
:
'模拟考试'
,
2
:
'在线练习'
}
// 题目类型
export
const
subjectType
=
{
0
:
'单选题'
,
2
:
'判断题'
,
1
:
'简答题'
,
3
:
'多选题'
}
export
const
subjectTypeTag
=
{
0
:
'success'
,
1
:
'info'
,
2
:
'warning'
,
3
:
'default'
}
frontend/spring-microservice-exam-web/src/utils/util.js
View file @
11d480f6
...
...
@@ -284,3 +284,27 @@ export const cropStr = (str, len) => {
}
return
result
}
/**
* 截取指定长度
* @param str
* @param length
* @returns {string}
*/
export
const
commonFilter
=
(
str
,
length
)
=>
{
if
(
str
.
length
>
length
)
{
return
str
.
substring
(
0
,
length
)
+
'...'
}
return
str
}
/**
* 新建状态
*/
export
const
isCreate
=
(
status
)
=>
{
return
status
===
'create'
}
export
const
trimComma
=
(
str
)
=>
{
return
str
.
replace
(
new
RegExp
(
'^,*|,*$'
,
'gm'
),
''
)
}
frontend/spring-microservice-exam-web/src/views/exam/examRecords.vue
View file @
11d480f6
...
...
@@ -17,22 +17,17 @@
</el-table-column>
<el-table-column
label=
"考试类型"
min-width=
"90"
align=
"center"
>
<
template
slot-scope=
"scope"
>
<span>
{{
scope
.
row
.
type
|
typeFilter
}}
</span>
</
template
>
</el-table-column>
<el-table-column
label=
"所属课程"
min-width=
"90"
align=
"center"
>
<
template
slot-scope=
"scope"
>
<span>
{{
scope
.
row
.
type
|
typeFilter
}}
</span>
<span>
{{
scope
.
row
.
type
|
examTypeFilter
}}
</span>
</
template
>
</el-table-column>
<el-table-column
label=
"考试时间"
sortable
prop=
"start_time"
min-width=
"90"
align=
"center"
>
<
template
slot-scope=
"scope"
>
<span>
{{
scope
.
row
.
startTime
|
timeFilter
}}
</span>
<span>
{{
scope
.
row
.
startTime
|
fmtDate
(
'yyyy-MM-dd hh:mm'
)
}}
</span>
</
template
>
</el-table-column>
<el-table-column
label=
"状态"
min-width=
"90"
align=
"center"
>
<
template
slot-scope=
"scope"
>
<el-tag
:type=
"scope.row.submitStatus | s
ubmitStatusTypeFilter
"
>
{{
scope
.
row
.
submitStatus
|
submitStatusFilter
}}
</el-tag>
<el-tag
:type=
"scope.row.submitStatus | s
impleTagStatusFilter(3)
"
>
{{
scope
.
row
.
submitStatus
|
submitStatusFilter
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
label=
"成绩"
sortable
prop=
"score"
align=
"center"
width=
"120px"
>
...
...
@@ -43,7 +38,6 @@
<el-table-column
label=
"操作"
align=
"center"
>
<
template
slot-scope=
"scope"
>
<el-button
type=
"success"
size=
"mini"
@
click=
"handleDetail(scope.row)"
:disabled=
"scope.row.submitStatus !== 3"
>
成绩详情
</el-button>
<el-button
type=
"danger"
size=
"mini"
@
click=
"incorrectAnswer(scope.row)"
:disabled=
"scope.row.submitStatus !== 3"
>
查看错题
</el-button>
</
template
>
</el-table-column>
</el-table>
...
...
@@ -52,73 +46,19 @@
</div>
</el-col>
</el-row>
<!-- 成绩详情 -->
<el-dialog
:visible
.
sync=
"dialogDetailVisible"
title=
"成绩详情"
>
<el-row>
<el-col
:span=
"24"
>
<div
slot=
"header"
class=
"score-gray-box-title"
>
<span>
考试成绩
</span>
</div>
<div
class=
"score"
>
<h4>
成绩:
<span
type=
"success"
>
{{ tempScore.score }}
</span></h4>
<h4>
正确题数:
<span
type=
"success"
>
{{ tempScore.correctNumber }}
</span></h4>
<h4>
错误题数:
<span
type=
"success"
>
{{ tempScore.inCorrectNumber }}
</span></h4>
<h4>
开始时间:
<span
type=
"success"
>
{{ tempScore.startTime | timeFilter }}
</span></h4>
<h4>
结束时间:
<span
type=
"success"
>
{{ tempScore.endTime | timeFilter }}
</span></h4>
</div>
</el-col>
</el-row>
</el-dialog>
</div>
</template>
<
script
>
import
{
mapState
}
from
'vuex'
import
{
fetchList
}
from
'@/api/exam/examRecord'
import
store
from
'@/store'
import
{
formatDate
,
cropStr
}
from
'@/utils/util'
export
default
{
filters
:
{
typeFilter
(
type
)
{
const
typeMap
=
{
0
:
'正式考试'
,
1
:
'模拟考试'
,
2
:
'在线练习'
}
return
typeMap
[
type
]
},
submitStatusFilter
(
type
)
{
const
typeMap
=
{
0
:
'未提交'
,
1
:
'已提交'
,
2
:
'待批改'
,
3
:
'批改完成'
}
return
typeMap
[
type
]
},
submitStatusTypeFilter
(
status
)
{
const
statusMap
=
{
0
:
'warning'
,
1
:
'warning'
,
2
:
'warning'
,
3
:
'success'
}
return
statusMap
[
status
]
},
timeFilter
(
time
)
{
return
formatDate
(
new
Date
(
time
),
'yyyy-MM-dd hh:mm'
)
},
examinationNameFilter
(
name
)
{
return
cropStr
(
name
,
8
)
}
},
data
()
{
return
{
examRecodeList
:
[],
total
:
0
,
listLoading
:
true
,
dialogDetailVisible
:
false
,
tableKey
:
0
,
listQuery
:
{
pageNum
:
1
,
...
...
@@ -172,11 +112,6 @@ export default {
},
// 查看成绩详情
handleDetail
(
row
)
{
this
.
tempScore
=
row
this
.
dialogDetailVisible
=
true
},
// 查看错题
incorrectAnswer
(
row
)
{
store
.
dispatch
(
'SetIncorrectRecord'
,
{
id
:
row
.
id
}).
then
(()
=>
{
this
.
$router
.
push
({
name
:
'incorrect'
})
}).
catch
((
error
)
=>
{
...
...
frontend/spring-microservice-exam-web/src/views/exam/incorrect.vue
View file @
11d480f6
<
template
>
<div
class=
"app-container"
>
<el-row>
<el-col
:span=
"20"
:offset=
"2"
>
<div
class=
"subject-content"
v-for=
"(tempIncorrectAnswer, index) in list"
:key=
"tempIncorrectAnswer.id"
>
<div
class=
"subject-content-option"
>
<div
class=
"subject-title"
>
<span
class=
"subject-title-number"
>
{{
index
+
1
}}
.
</span>
{{
tempIncorrectAnswer
.
subject
.
subjectName
}}
(
{{
tempIncorrectAnswer
.
subject
.
score
}}
分)
<el-card>
<spinner-loading
v-if=
"listLoading"
/>
<el-row>
<el-col
:span=
"20"
:offset=
"2"
>
<el-divider>
成绩详情
</el-divider>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"20"
:offset=
"2"
>
<el-row>
<el-col
:span=
"8"
>
<label
class=
"el-form-item__label"
>
考试名称:
{{
examRecordDetail
.
examinationName
}}
</label>
</el-col>
<el-col
:span=
"8"
>
<label
class=
"el-form-item__label"
>
考生姓名:
{{
examRecordDetail
.
userName
}}
</label>
</el-col>
<el-col
:span=
"8"
>
<label
class=
"el-form-item__label"
>
总得分:
{{
examRecordDetail
.
score
}}
</label>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"8"
>
<label
class=
"el-form-item__label"
>
开始时间:
{{
examRecordDetail
.
startTime
|
fmtDate
(
'yyyy-MM-dd hh:mm'
)
}}
</label>
</el-col>
<el-col
:span=
"8"
>
<label
class=
"el-form-item__label"
>
结束时间:
{{
examRecordDetail
.
endTime
|
fmtDate
(
'yyyy-MM-dd hh:mm'
)
}}
</label>
</el-col>
<el-col
:span=
"8"
>
<label
class=
"el-form-item__label"
>
耗时:
{{
examRecordDetail
.
duration
}}
</label>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"8"
>
<label
class=
"el-form-item__label"
>
评卷人: 系统自动评分
</label>
</el-col>
<el-col
:span=
"8"
>
<label
class=
"el-form-item__label"
>
正确题数:
</label><el-tag
type=
"success"
size=
"small"
effect=
"dark"
>
{{
examRecordDetail
.
correctNumber
}}
</el-tag>
</el-col>
<el-col
:span=
"8"
>
<label
class=
"el-form-item__label"
>
错误题数:
</label><el-tag
type=
"danger"
size=
"small"
effect=
"dark"
>
{{
examRecordDetail
.
inCorrectNumber
}}
</el-tag>
</el-col>
</el-row>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"20"
:offset=
"2"
>
<el-divider>
错题列表
</el-divider>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"20"
:offset=
"2"
>
<div
class=
"subject-content"
v-for=
"(tempIncorrectAnswer, index) in list"
:key=
"tempIncorrectAnswer.id"
>
<div
class=
"subject-content-option"
>
<div
class=
"subject-title"
>
<span
class=
"subject-title-number"
>
{{
index
+
1
}}
.
</span>
{{
tempIncorrectAnswer
.
subject
.
subjectName
}}
(
{{
tempIncorrectAnswer
.
subject
.
score
}}
分)
</div>
<!-- 选择题 -->
<div>
<ul
class=
"subject-options"
v-for=
"option in tempIncorrectAnswer.subject.options"
:key=
"option.id"
>
<li
class=
"subject-option"
:class=
"getClass(option.right)"
>
<label><span
class=
"subject-option-prefix"
>
{{
option
.
optionName
}}
</span><span
v-html=
"option.optionContent"
class=
"subject-option-prefix"
></span></label>
</li>
</ul>
</div>
</div>
<!-- 选择题 -->
<div>
<ul
class=
"subject-options"
v-for=
"option in tempIncorrectAnswer.subject.options"
:key=
"option.id"
>
<li
class=
"subject-option"
:class=
"getClass(option.right)"
>
<label><span
class=
"subject-option-prefix"
>
{{
option
.
optionName
}}
</span><span
v-html=
"option.optionContent"
class=
"subject-option-prefix"
></span></label>
</li>
</ul>
<!-- 简答题 -->
<div
v-if=
"tempIncorrectAnswer.subject.type === 1"
>
<p>
<span
v-html=
"tempIncorrectAnswer.subject.answer.answer"
></span>
</p>
</div>
</div
>
<!-- 简答题 -->
<div
v-if=
"tempIncorrectAnswer.subject.type === 1"
>
<p>
<span
v-html=
"tempIncorrectAnswer.subject.answer"
></span>
<p
class=
"subject-content-answer"
>
参考答案:
{{
tempIncorrectAnswer
.
subject
.
answer
.
answer
}}
</p
>
<p
class=
"subject-content-analysis"
>
解析:
{{
tempIncorrectAnswer
.
subject
.
analysis
}}
</p>
</div>
<p
class=
"subject-content-answer"
>
参考答案:
{{
tempIncorrectAnswer
.
subject
.
answer
.
answer
}}
</p>
<p
class=
"subject-content-analysis"
>
解析:
{{
tempIncorrectAnswer
.
subject
.
analysis
}}
</p>
</div>
<div
class=
"pagination-container"
>
<el-pagination
v-show=
"total > 0"
:current-page=
"listQuery.pageNum"
:page-sizes=
"[10,20,30, 50]"
:page-size=
"listQuery.pageSize"
:total=
"total"
background
layout=
"total, sizes, prev, pager, next, jumper"
@
size-change=
"handleSizeChange"
@
current-change=
"handleCurrentChange"
/>
</div>
</el-col>
</el-row>
<div
class=
"pagination-container"
>
<el-pagination
v-show=
"total > 0"
:current-page=
"listQuery.pageNum"
:page-sizes=
"[10,20,30, 50]"
:page-size=
"listQuery.pageSize"
:total=
"total"
background
layout=
"total, sizes, prev, pager, next, jumper"
@
size-change=
"handleSizeChange"
@
current-change=
"handleCurrentChange"
/>
</div>
</el-col>
</el-row>
</el-card>
</div>
</
template
>
<
script
>
import
{
mapState
}
from
'vuex'
import
{
getAnswerListInfo
}
from
'@/api/exam/answer'
import
{
examRecordDetails
}
from
'@/api/exam/examRecord'
import
{
notifyFail
}
from
'@/utils/util'
import
{
answerType
}
from
'@/const/constant'
import
SpinnerLoading
from
'@/components/SpinnerLoading'
export
default
{
name
:
'Incorrect'
,
components
:
{
SpinnerLoading
},
data
()
{
return
{
total
:
0
,
listLoading
:
true
,
total
:
0
,
tableKey
:
0
,
list
:
[],
listQuery
:
{
...
...
@@ -56,6 +112,17 @@ export default {
pageNum
:
1
,
pageSize
:
10
,
answerType
:
1
},
examRecordDetail
:
{
correctNumber
:
0
,
endTime
:
0
,
duration
:
''
,
examinationName
:
''
,
inCorrectNumber
:
0
,
score
:
0
,
startTime
:
0
,
submitStatus
:
0
,
totalScore
:
0
}
}
},
...
...
@@ -67,16 +134,20 @@ export default {
})
},
created
()
{
this
.
get
List
()
this
.
get
RecordDetail
()
},
methods
:
{
getList
()
{
getAnswerListInfo
(
this
.
incorrectRecord
.
id
,
this
.
listQuery
).
then
(
response
=>
{
this
.
list
=
response
.
data
.
list
this
.
total
=
response
.
data
.
total
this
.
listLoading
=
false
}).
catch
(()
=>
{
notifyFail
(
this
,
'加载错题失败'
)
getRecordDetail
()
{
this
.
listLoading
=
true
examRecordDetails
(
this
.
incorrectRecord
.
id
).
then
(
response
=>
{
this
.
examRecordDetail
=
response
.
data
.
data
getAnswerListInfo
(
this
.
incorrectRecord
.
id
,
this
.
listQuery
).
then
(
response
=>
{
this
.
list
=
response
.
data
.
list
this
.
total
=
response
.
data
.
total
this
.
listLoading
=
false
}).
catch
(()
=>
{
notifyFail
(
this
,
'加载错题失败'
)
})
})
},
handleSizeChange
(
val
)
{
...
...
modules/auth-service-parent/auth-service/src/main/java/com/github/tangyi/auth/config/CustomAuthorizationServerConfigurer.java
View file @
11d480f6
...
...
@@ -2,17 +2,24 @@ package com.github.tangyi.auth.config;
import
com.github.tangyi.auth.security.CustomTokenConverter
;
import
com.github.tangyi.common.security.core.ClientDetailsServiceImpl
;
import
com.github.tangyi.common.security.exception.CustomOauthException
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.cloud.bootstrap.encrypt.KeyProperties
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Lazy
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
;
import
org.springframework.security.oauth2.common.exceptions.OAuth2Exception
;
import
org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer
;
import
org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter
;
import
org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer
;
import
org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer
;
import
org.springframework.security.oauth2.provider.ClientDetailsService
;
import
org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator
;
import
org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator
;
import
org.springframework.security.oauth2.provider.token.TokenStore
;
import
org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter
;
import
org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory
;
...
...
@@ -107,7 +114,9 @@ public class CustomAuthorizationServerConfigurer extends AuthorizationServerConf
// 将token存储到redis
.
tokenStore
(
tokenStore
())
// token增强
.
tokenEnhancer
(
jwtTokenEnhancer
());
.
tokenEnhancer
(
jwtTokenEnhancer
())
// 异常转换
.
exceptionTranslator
(
webResponseExceptionTranslator
());
}
/**
...
...
@@ -125,5 +134,22 @@ public class CustomAuthorizationServerConfigurer extends AuthorizationServerConf
.
checkTokenAccess
(
"isAuthenticated()"
)
.
allowFormAuthenticationForClients
();
}
@Bean
@Lazy
public
WebResponseExceptionTranslator
<
OAuth2Exception
>
webResponseExceptionTranslator
()
{
return
new
DefaultWebResponseExceptionTranslator
()
{
@Override
public
ResponseEntity
<
OAuth2Exception
>
translate
(
Exception
e
)
throws
Exception
{
if
(
e
instanceof
OAuth2Exception
)
{
OAuth2Exception
exception
=
(
OAuth2Exception
)
e
;
// 转换返回结果
return
ResponseEntity
.
status
(
exception
.
getHttpErrorCode
()).
body
(
new
CustomOauthException
(
e
.
getMessage
()));
}
else
{
throw
e
;
}
}
};
}
}
modules/auth-service-parent/auth-service/src/main/java/com/github/tangyi/auth/listener/LoginSuccessListener.java
View file @
11d480f6
...
...
@@ -64,6 +64,7 @@ public class LoginSuccessListener implements ApplicationListener<CustomAuthentic
logInfo
.
setServiceId
(
ServiceConstant
.
AUTH_SERVICE
);
// 记录日志和登录时间
UserDto
userDto
=
new
UserDto
();
userDto
.
setId
(
customUserDetails
.
getId
());
userDto
.
setIdentifier
(
username
);
userDto
.
setLoginTime
(
DateUtils
.
asDate
(
LocalDateTime
.
now
()));
saveLoginInfo
(
logInfo
,
userDto
);
...
...
@@ -82,7 +83,7 @@ public class LoginSuccessListener implements ApplicationListener<CustomAuthentic
public
void
saveLoginInfo
(
Log
logInfo
,
UserDto
userDto
)
{
try
{
userServiceClient
.
saveLog
(
logInfo
);
//userServiceClient.updateUser
(userDto);
userServiceClient
.
updateLoginInfo
(
userDto
);
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
...
...
modules/auth-service-parent/auth-service/src/main/java/com/github/tangyi/auth/model/CustomUserDetails.java
View file @
11d480f6
...
...
@@ -24,6 +24,11 @@ public class CustomUserDetails extends User {
private
String
tenantCode
;
/**
* id
*/
private
Long
id
;
/**
* 开始授权时间
*/
private
long
start
;
...
...
@@ -44,9 +49,10 @@ public class CustomUserDetails extends User {
* @param start start
* @param loginType loginType
*/
public
CustomUserDetails
(
String
username
,
String
password
,
boolean
enabled
,
Collection
<?
extends
GrantedAuthority
>
authorities
,
String
tenantCode
,
long
start
,
LoginTypeEnum
loginType
)
{
public
CustomUserDetails
(
String
username
,
String
password
,
boolean
enabled
,
Collection
<?
extends
GrantedAuthority
>
authorities
,
String
tenantCode
,
Long
id
,
long
start
,
LoginTypeEnum
loginType
)
{
super
(
username
,
password
,
enabled
,
true
,
true
,
true
,
authorities
);
this
.
tenantCode
=
tenantCode
;
this
.
id
=
id
;
this
.
start
=
start
;
this
.
loginType
=
loginType
;
}
...
...
modules/auth-service-parent/auth-service/src/main/java/com/github/tangyi/auth/security/CustomUserDetailsAuthenticationProvider.java
View file @
11d480f6
...
...
@@ -43,7 +43,7 @@ public class CustomUserDetailsAuthenticationProvider extends AbstractUserDetails
protected
void
additionalAuthenticationChecks
(
UserDetails
userDetails
,
UsernamePasswordAuthenticationToken
authentication
)
throws
AuthenticationException
{
if
(
authentication
.
getCredentials
()
==
null
)
{
log
.
debug
(
"Authentication failed: password is blank"
);
throw
new
BadCredentialsException
(
messages
.
getMessage
(
"AbstractUserDetailsAuthenticationProvider.badCredentials"
,
"密码为空
.
"
));
throw
new
BadCredentialsException
(
messages
.
getMessage
(
"AbstractUserDetailsAuthenticationProvider.badCredentials"
,
"密码为空"
));
}
// 获取密码
String
presentedPassword
=
authentication
.
getCredentials
().
toString
();
...
...
@@ -51,7 +51,7 @@ public class CustomUserDetailsAuthenticationProvider extends AbstractUserDetails
if
(!
passwordEncoder
.
matches
(
presentedPassword
,
userDetails
.
getPassword
()))
{
log
.
debug
(
"Authentication failed: invalid password"
);
publisher
.
publishEvent
(
new
CustomAuthenticationFailureEvent
(
authentication
,
userDetails
));
throw
new
BadCredentialsException
(
messages
.
getMessage
(
"AbstractUserDetailsAuthenticationProvider.badCredentials"
,
"
密码错误.
"
));
throw
new
BadCredentialsException
(
messages
.
getMessage
(
"AbstractUserDetailsAuthenticationProvider.badCredentials"
,
"
用户名或密码错误
"
));
}
publisher
.
publishEvent
(
new
CustomAuthenticationSuccessEvent
(
authentication
,
userDetails
));
}
...
...
@@ -77,16 +77,14 @@ public class CustomUserDetailsAuthenticationProvider extends AbstractUserDetails
try
{
// 加载用户信息
loadedUser
=
this
.
userDetailsService
.
loadUserByIdentifierAndTenantCode
(
TenantContextHolder
.
getTenantCode
(),
authentication
.
getPrincipal
().
toString
());
}
catch
(
TenantNotFoundException
tenantNotFound
)
{
throw
new
InternalAuthenticationServiceException
(
tenantNotFound
.
getMessage
(),
tenantNotFound
);
}
catch
(
UsernameNotFoundException
notFound
)
{
if
(
authentication
.
getCredentials
()
!=
null
)
{
String
presentedPassword
=
authentication
.
getCredentials
().
toString
();
passwordEncoder
.
matches
(
presentedPassword
,
userNotFoundEncodedPassword
);
}
throw
notFound
;
}
catch
(
Exception
repositoryProblem
)
{
throw
new
InternalAuthenticationServiceException
(
repositoryProblem
.
getMessage
(),
repositoryProblem
);
}
catch
(
Exception
tenantNotFound
)
{
throw
new
InternalAuthenticationServiceException
(
tenantNotFound
.
getMessage
(),
tenantNotFound
);
}
if
(
loadedUser
==
null
)
{
throw
new
InternalAuthenticationServiceException
(
"get user information failed"
);
...
...
modules/auth-service-parent/auth-service/src/main/java/com/github/tangyi/auth/security/CustomUserDetailsServiceImpl.java
View file @
11d480f6
...
...
@@ -63,7 +63,7 @@ public class CustomUserDetailsServiceImpl implements CustomUserDetailsService {
UserVo
userVo
=
userVoResponseBean
.
getData
();
if
(
userVo
==
null
)
throw
new
UsernameNotFoundException
(
"user does not exist"
);
return
new
CustomUserDetails
(
username
,
userVo
.
getCredential
(),
CommonConstant
.
STATUS_NORMAL
.
equals
(
userVo
.
getStatus
()),
getAuthority
(
userVo
),
userVo
.
getTenantCode
(),
start
,
LoginTypeEnum
.
PWD
);
return
new
CustomUserDetails
(
username
,
userVo
.
getCredential
(),
CommonConstant
.
STATUS_NORMAL
.
equals
(
userVo
.
getStatus
()),
getAuthority
(
userVo
),
userVo
.
getTenantCode
(),
userVo
.
getId
(),
start
,
LoginTypeEnum
.
PWD
);
}
/**
...
...
@@ -103,7 +103,7 @@ public class CustomUserDetailsServiceImpl implements CustomUserDetailsService {
throw
new
ServiceException
(
GET_USER_INFO_FAIL
+
userVoResponseBean
.
getMsg
());
userVo
=
userVoResponseBean
.
getData
();
}
return
new
CustomUserDetails
(
userVo
.
getIdentifier
(),
userVo
.
getCredential
(),
CommonConstant
.
STATUS_NORMAL
.
equals
(
userVo
.
getStatus
()),
getAuthority
(
userVo
),
userVo
.
getTenantCode
(),
start
,
LoginTypeEnum
.
SMS
);
return
new
CustomUserDetails
(
userVo
.
getIdentifier
(),
userVo
.
getCredential
(),
CommonConstant
.
STATUS_NORMAL
.
equals
(
userVo
.
getStatus
()),
getAuthority
(
userVo
),
userVo
.
getTenantCode
(),
userVo
.
getId
(),
start
,
LoginTypeEnum
.
SMS
);
}
/**
...
...
@@ -149,7 +149,7 @@ public class CustomUserDetailsServiceImpl implements CustomUserDetailsService {
throw
new
ServiceException
(
GET_USER_INFO_FAIL
+
userVoResponseBean
.
getMsg
());
userVo
=
userVoResponseBean
.
getData
();
}
return
new
CustomUserDetails
(
userVo
.
getIdentifier
(),
userVo
.
getCredential
(),
CommonConstant
.
STATUS_NORMAL
.
equals
(
userVo
.
getStatus
()),
getAuthority
(
userVo
),
userVo
.
getTenantCode
(),
start
,
LoginTypeEnum
.
WECHAT
);
return
new
CustomUserDetails
(
userVo
.
getIdentifier
(),
userVo
.
getCredential
(),
CommonConstant
.
STATUS_NORMAL
.
equals
(
userVo
.
getStatus
()),
getAuthority
(
userVo
),
userVo
.
getTenantCode
(),
userVo
.
getId
(),
start
,
LoginTypeEnum
.
WECHAT
);
}
/**
...
...
modules/exam-service-parent/exam-service/src/main/java/com/github/tangyi/exam/handler/impl/MultipleChoicesAnswerHandler.java
View file @
11d480f6
...
...
@@ -6,6 +6,7 @@ import com.github.tangyi.exam.api.dto.SubjectDto;
import
com.github.tangyi.exam.api.module.Answer
;
import
com.github.tangyi.exam.enums.SubjectTypeEnum
;
import
com.github.tangyi.exam.handler.AbstractAnswerHandler
;
import
com.github.tangyi.exam.utils.AnswerHandlerUtil
;
import
lombok.AllArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang.ArrayUtils
;
...
...
@@ -41,8 +42,8 @@ public class MultipleChoicesAnswerHandler extends AbstractAnswerHandler {
String
userAnswer
=
answer
.
getAnswer
();
String
correctAnswer
=
subject
.
getAnswer
().
getAnswer
();
if
(
StringUtils
.
isNotBlank
(
userAnswer
)
&&
StringUtils
.
isNotBlank
(
correctAnswer
))
{
String
[]
userAnswers
=
userAnswer
.
split
(
CommonConstant
.
COMMA
);
String
[]
correctAnswers
=
correctAnswer
.
split
(
CommonConstant
.
COMMA
);
String
[]
userAnswers
=
AnswerHandlerUtil
.
replaceComma
(
userAnswer
)
.
split
(
CommonConstant
.
COMMA
);
String
[]
correctAnswers
=
AnswerHandlerUtil
.
replaceComma
(
correctAnswer
)
.
split
(
CommonConstant
.
COMMA
);
subject
.
getOptions
().
forEach
(
option
->
{
if
(
ArrayUtils
.
contains
(
correctAnswers
,
option
.
getOptionName
()))
{
option
.
setRight
(
ArrayUtils
.
contains
(
userAnswers
,
option
.
getOptionName
())
?
TRUE
:
FALSE
);
...
...
@@ -53,7 +54,7 @@ public class MultipleChoicesAnswerHandler extends AbstractAnswerHandler {
@Override
public
boolean
judgeRight
(
Answer
answer
,
SubjectDto
subject
)
{
String
[]
correctAnswers
=
subject
.
getAnswer
().
getAnswer
(
).
split
(
CommonConstant
.
COMMA
);
String
[]
correctAnswers
=
AnswerHandlerUtil
.
replaceComma
(
subject
.
getAnswer
().
getAnswer
()
).
split
(
CommonConstant
.
COMMA
);
for
(
String
as
:
answer
.
getAnswer
().
split
(
CommonConstant
.
COMMA
))
{
if
(!
ArrayUtils
.
contains
(
correctAnswers
,
as
))
{
return
false
;
...
...
modules/user-service-parent/user-service-api/src/main/java/com/github/tangyi/user/api/feign/UserServiceClient.java
View file @
11d480f6
...
...
@@ -35,7 +35,7 @@ public interface UserServiceClient {
* @author tangyi
* @date 2019/03/17 12:14
*/
@GetMapping
(
"/v1/user/findUserByIdentifier/{identifier}"
)
@GetMapping
(
"/v1/user/
anonymousUser/
findUserByIdentifier/{identifier}"
)
ResponseBean
<
UserVo
>
findUserByIdentifier
(
@PathVariable
(
"identifier"
)
String
identifier
,
@RequestParam
(
"tenantCode"
)
String
tenantCode
);
/**
...
...
@@ -48,7 +48,7 @@ public interface UserServiceClient {
* @author tangyi
* @date 2019/07/06 14:14:11
*/
@GetMapping
(
"/v1/user/findUserByIdentifier/{identifier}"
)
@GetMapping
(
"/v1/user/
anonymousUser/
findUserByIdentifier/{identifier}"
)
ResponseBean
<
UserVo
>
findUserByIdentifier
(
@PathVariable
(
"identifier"
)
String
identifier
,
@RequestParam
(
value
=
"identityType"
,
required
=
false
)
Integer
identityType
,
@RequestParam
(
"tenantCode"
)
String
tenantCode
);
...
...
@@ -131,7 +131,7 @@ public interface UserServiceClient {
* @author tangyi
* @date 2019/04/08 20:42
*/
@GetMapping
(
"/v1/menu/findMenuByRole/{role}"
)
@GetMapping
(
"/v1/menu/
anonymousUser/
findMenuByRole/{role}"
)
ResponseBean
<
List
<
Menu
>>
findMenuByRole
(
@PathVariable
(
"role"
)
String
role
,
@RequestParam
(
"tenantCode"
)
String
tenantCode
);
/**
...
...
@@ -142,7 +142,7 @@ public interface UserServiceClient {
* @author tangyi
* @date 2019/04/26 11:48
*/
@GetMapping
(
"/v1/menu/findAllMenu"
)
@GetMapping
(
"/v1/menu/
anonymousUser/
findAllMenu"
)
ResponseBean
<
List
<
Menu
>>
findAllMenu
(
@RequestParam
(
"tenantCode"
)
String
tenantCode
);
/**
...
...
@@ -153,7 +153,7 @@ public interface UserServiceClient {
* @author tangyi
* @date 2019/05/26 10:21
*/
@GetMapping
(
"/v1/tenant/findTenantByTenantCode/{tenantCode}"
)
@GetMapping
(
"/v1/tenant/
anonymousUser/
findTenantByTenantCode/{tenantCode}"
)
ResponseBean
<
Tenant
>
findTenantByTenantCode
(
@PathVariable
(
"tenantCode"
)
String
tenantCode
);
/**
...
...
@@ -176,17 +176,17 @@ public interface UserServiceClient {
* @author tangyi
* @date 2019/07/05 20:57:31
*/
@PostMapping
(
"/v1/user/register"
)
@PostMapping
(
"/v1/user/
anonymousUser/
register"
)
ResponseBean
<
Boolean
>
registerUser
(
@RequestBody
UserDto
userDto
);
/**
* 更新用户
* 更新用户
登录信息
*
* @param userDto userDto
* @return ResponseBean
* @author tangyi
* @date 2019/07/05 20:59:06
*/
@PutMapping
(
"/v1/user"
)
ResponseBean
<
Boolean
>
update
User
(
UserDto
userDto
);
@PutMapping
(
"/v1/user
/anonymousUser/updateLoginInfo
"
)
ResponseBean
<
Boolean
>
update
LoginInfo
(
UserDto
userDto
);
}
modules/user-service-parent/user-service-api/src/main/java/com/github/tangyi/user/api/feign/fallback/UserServiceClientFallbackImpl.java
View file @
11d480f6
...
...
@@ -203,14 +203,14 @@ public class UserServiceClientFallbackImpl implements UserServiceClient {
}
/**
* 更新用户
* 更新用户
登录信息
*
* @param userDto userDto
* @return ResponseBean
*/
@Override
public
ResponseBean
<
Boolean
>
update
User
(
UserDto
userDto
)
{
log
.
error
(
"Feign update
User
failed, {}, {}, {}"
,
userDto
.
getIdentityType
(),
userDto
.
getIdentifier
(),
throwable
);
public
ResponseBean
<
Boolean
>
update
LoginInfo
(
UserDto
userDto
)
{
log
.
error
(
"Feign update
LoginInfo
failed, {}, {}, {}"
,
userDto
.
getIdentityType
(),
userDto
.
getIdentifier
(),
throwable
);
return
null
;
}
...
...
modules/user-service-parent/user-service/src/main/java/com/github/tangyi/user/controller/MenuController.java
View file @
11d480f6
...
...
@@ -179,7 +179,7 @@ public class MenuController extends BaseController {
* @author tangyi
* @date 2018/8/27 15:58
*/
@GetMapping
(
"findMenuByRole/{role}"
)
@GetMapping
(
"
anonymousUser/
findMenuByRole/{role}"
)
@ApiOperation
(
value
=
"根据角色查找菜单"
,
notes
=
"根据角色id获取角色菜单"
)
@ApiImplicitParam
(
name
=
"role"
,
value
=
"角色名称"
,
required
=
true
,
dataType
=
"String"
,
paramType
=
"path"
)
public
ResponseBean
<
List
<
Menu
>>
findMenuByRole
(
@PathVariable
String
role
,
@RequestParam
@NotBlank
String
tenantCode
)
{
...
...
@@ -194,7 +194,7 @@ public class MenuController extends BaseController {
* @author tangyi
* @date 2019/04/26 11:50
*/
@GetMapping
(
"findAllMenu"
)
@GetMapping
(
"
anonymousUser/
findAllMenu"
)
@ApiOperation
(
value
=
"查询所有菜单"
,
notes
=
"查询所有菜单"
)
public
ResponseBean
<
List
<
Menu
>>
findAllMenu
(
@RequestParam
@NotBlank
String
tenantCode
)
{
Menu
menu
=
new
Menu
();
...
...
modules/user-service-parent/user-service/src/main/java/com/github/tangyi/user/controller/TenantController.java
View file @
11d480f6
...
...
@@ -61,7 +61,7 @@ public class TenantController extends BaseController {
* @author tangyi
* @date 2019/05/26 10:23
*/
@GetMapping
(
"findTenantByTenantCode/{tenantCode}"
)
@GetMapping
(
"
anonymousUser/
findTenantByTenantCode/{tenantCode}"
)
public
ResponseBean
<
Tenant
>
findTenantByTenantCode
(
@PathVariable
String
tenantCode
)
{
return
new
ResponseBean
<>(
tenantService
.
getByTenantCode
(
tenantCode
));
}
...
...
modules/user-service-parent/user-service/src/main/java/com/github/tangyi/user/controller/UserController.java
View file @
11d480f6
...
...
@@ -105,7 +105,7 @@ public class UserController extends BaseController {
* @param tenantCode tenantCode
* @return ResponseBean
*/
@GetMapping
(
"/findUserByIdentifier/{identifier}"
)
@GetMapping
(
"
anonymousUser
/findUserByIdentifier/{identifier}"
)
@ApiOperation
(
value
=
"获取用户信息"
,
notes
=
"根据用户name获取用户详细信息"
)
@ApiImplicitParams
({
@ApiImplicitParam
(
name
=
"identifier"
,
value
=
"用户唯一标识"
,
required
=
true
,
dataType
=
"String"
,
paramType
=
"path"
),
...
...
@@ -235,7 +235,7 @@ public class UserController extends BaseController {
* @author tangyi
* @date 2019/06/21 20:09
*/
@PutMapping
(
"updatePassword"
)
@PutMapping
(
"
anonymousUser/
updatePassword"
)
@ApiOperation
(
value
=
"修改用户密码"
,
notes
=
"修改用户密码"
)
@ApiImplicitParam
(
name
=
"userDto"
,
value
=
"用户实体user"
,
required
=
true
,
dataType
=
"UserDto"
)
@Log
(
"更新用户密码"
)
...
...
@@ -403,7 +403,7 @@ public class UserController extends BaseController {
@ApiImplicitParam
(
name
=
"randomStr"
,
value
=
"随机数"
,
dataType
=
"String"
,
paramType
=
"query"
),
@ApiImplicitParam
(
name
=
"mobile"
,
value
=
"手机号"
,
dataType
=
"String"
,
paramType
=
"query"
)
})
@PostMapping
(
"register"
)
@PostMapping
(
"
anonymousUser/
register"
)
@Log
(
"注册用户"
)
public
ResponseBean
<
Boolean
>
register
(
@RequestBody
@Valid
UserDto
userDto
)
{
return
new
ResponseBean
<>(
userService
.
register
(
userDto
));
...
...
@@ -425,7 +425,7 @@ public class UserController extends BaseController {
@ApiImplicitParam
(
name
=
"identifier"
,
value
=
"用户唯一标识"
,
required
=
true
,
dataType
=
"String"
,
paramType
=
"path"
),
@ApiImplicitParam
(
name
=
"tenantCode"
,
value
=
"租户标识"
,
required
=
true
,
dataType
=
"String"
),
})
@GetMapping
(
"checkExist/{identifier}"
)
@GetMapping
(
"
anonymousUser/
checkExist/{identifier}"
)
public
ResponseBean
<
Boolean
>
checkExist
(
@PathVariable
(
"identifier"
)
String
identifier
,
@RequestParam
Integer
identityType
,
@RequestHeader
(
SecurityConstant
.
TENANT_CODE_HEADER
)
String
tenantCode
)
{
return
new
ResponseBean
<>(
userService
.
checkIdentifierIsExist
(
identityType
,
identifier
,
tenantCode
));
}
...
...
@@ -451,7 +451,7 @@ public class UserController extends BaseController {
* @author tangyi
* @date 2019/6/7 12:00
*/
@PutMapping
(
"/resetPassword"
)
@PutMapping
(
"
anonymousUser
/resetPassword"
)
@AdminTenantTeacherAuthorization
@ApiOperation
(
value
=
"重置密码"
,
notes
=
"根据用户id重置密码"
)
@ApiImplicitParam
(
name
=
"userDto"
,
value
=
"用户实体user"
,
required
=
true
,
dataType
=
"UserDto"
)
...
...
@@ -459,4 +459,34 @@ public class UserController extends BaseController {
public
ResponseBean
<
Boolean
>
resetPassword
(
@RequestBody
UserDto
userDto
)
{
return
new
ResponseBean
<>(
userService
.
resetPassword
(
userDto
));
}
/**
* 更新用户的基本信息
*
* @param userDto userDto
* @return ResponseBean
* @author tangyi
* @date 2020/02/29 16:55
*/
@PutMapping
(
"anonymousUser/updateLoginInfo"
)
@ApiOperation
(
value
=
"更新用户登录信息"
,
notes
=
"根据用户id更新用户的登录信息"
)
@ApiImplicitParam
(
name
=
"userDto"
,
value
=
"用户实体user"
,
required
=
true
,
dataType
=
"UserDto"
)
@Log
(
"更新用户登录信息"
)
public
ResponseBean
<
Boolean
>
updateLoginInfo
(
@RequestBody
UserDto
userDto
)
{
Boolean
success
=
Boolean
.
FALSE
;
if
(
StringUtils
.
isNotBlank
(
userDto
.
getIdentifier
()))
{
UserAuths
userAuths
=
new
UserAuths
();
userAuths
.
setIdentifier
(
userDto
.
getIdentifier
());
userAuths
=
userAuthsService
.
getByIdentifier
(
userAuths
);
if
(
userAuths
!=
null
)
{
User
user
=
new
User
();
user
.
setId
(
userAuths
.
getUserId
());
user
.
setLoginTime
(
userDto
.
getLoginTime
());
user
.
setModifyDate
(
userDto
.
getLoginTime
());
user
.
setModifier
(
userAuths
.
getIdentifier
());
success
=
userService
.
update
(
user
)
>
0
;
}
}
return
new
ResponseBean
<>(
success
);
}
}
modules/user-service-parent/user-service/src/main/java/com/github/tangyi/user/service/UserService.java
View file @
11d480f6
...
...
@@ -657,8 +657,10 @@ public class UserService extends CrudService<UserMapper, User> {
userVos
=
userStream
.
map
(
tempUser
->
{
UserVo
tempUserVo
=
new
UserVo
();
BeanUtils
.
copyProperties
(
tempUser
,
tempUserVo
);
attachment
.
setId
(
tempUser
.
getAvatarId
());
tempUserVo
.
setAvatarUrl
(
attachmentService
.
getPreviewUrl
(
attachment
));
if
(
tempUser
.
getAvatarId
()
!=
null
)
{
attachment
.
setId
(
tempUser
.
getAvatarId
());
tempUserVo
.
setAvatarUrl
(
attachmentService
.
getPreviewUrl
(
attachment
));
}
return
tempUserVo
;
}).
collect
(
Collectors
.
toList
());
}
...
...
modules/user-service-parent/user-service/src/main/resources/mapper/UserMapper.xml
View file @
11d480f6
...
...
@@ -249,7 +249,9 @@
<if
test=
"applicationCode != null"
>
application_code = #{applicationCode} ,
</if>
modifier = #{modifier} ,
<if
test=
"modifier != null"
>
modifier = #{modifier} ,
</if>
modify_date = #{modifyDate, jdbcType=TIMESTAMP, javaType=java.util.Date}
where id = #{id}
</update>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment