Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
jinli gu
Springboot Plus
Commits
875339d5
Commit
875339d5
authored
Jun 14, 2020
by
trumansdo
Browse files
补完菜单项管理
parent
fbc2862e
Changes
20
Hide whitespace changes
Inline
Side-by-side
plus-admin/admin-console/pom.xml
View file @
875339d5
...
...
@@ -29,4 +29,15 @@
<artifactId>
spring-boot-starter-log4j2
</artifactId>
</dependency>
</dependencies>
</project>
<build>
<plugins>
<plugin>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
<configuration>
<classifier>
exec
</classifier>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
plus-admin/admin-console/src/main/java/com/ibeetl/admin/console/dao/MenuConsoleDao.java
View file @
875339d5
package
com.ibeetl.admin.console.dao
;
import
java.util.List
;
import
org.beetl.sql.core.annotatoin.SqlResource
;
import
org.beetl.sql.core.engine.PageQuery
;
import
org.beetl.sql.core.mapper.BaseMapper
;
...
...
@@ -15,4 +16,6 @@ public interface MenuConsoleDao extends BaseMapper<CoreMenu> {
* @param query 查询条件
*/
void
queryByCondtion
(
PageQuery
query
);
List
<
CoreMenu
>
selectMenuAndRelationFunction
();
}
plus-admin/admin-console/src/main/java/com/ibeetl/admin/console/service/FunctionConsoleService.java
View file @
875339d5
package
com.ibeetl.admin.console.service
;
import
static
com
.
ibeetl
.
admin
.
core
.
service
.
CorePlatformService
.
FUNCTION_TREE_CACHE
;
import
cn.hutool.core.collection.CollUtil
;
import
com.ibeetl.admin.console.dao.FunctionConsoleDao
;
import
com.ibeetl.admin.console.dao.RoleFunctionConsoleDao
;
...
...
@@ -24,6 +26,7 @@ import java.util.stream.Collectors;
import
javax.validation.constraints.NotNull
;
import
org.beetl.sql.core.engine.PageQuery
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.cache.annotation.Cacheable
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
...
...
@@ -52,13 +55,13 @@ public class FunctionConsoleService extends CoreBaseService<CoreFunction> {
/**
* @return 返回功能点构成的树结构
*/
@Cacheable
(
FUNCTION_TREE_CACHE
)
public
List
<
CoreFunction
>
getFuncTree
()
{
List
<
CoreFunction
>
coreFunctionList
=
functionConsoleDao
.
getSQLManager
()
.
lambdaQuery
(
CoreFunction
.
class
)
.
andEq
(
CoreFunction:
:
getDelFlag
,
DelFlagEnum
.
NORMAL
).
select
();
System
.
out
.
println
(
coreFunctionList
);
CoreFunction
root
=
new
CoreFunction
();
root
.
setId
(-
1L
);
...
...
plus-admin/admin-console/src/main/java/com/ibeetl/admin/console/service/MenuConsoleService.java
View file @
875339d5
package
com.ibeetl.admin.console.service
;
import
static
com
.
ibeetl
.
admin
.
core
.
service
.
CorePlatformService
.
MENU_FUNC_TREE_CACHE
;
import
cn.hutool.core.collection.CollUtil
;
import
cn.hutool.core.util.ObjectUtil
;
import
com.ibeetl.admin.console.dao.MenuConsoleDao
;
import
com.ibeetl.admin.core.dao.CoreRoleMenuDao
;
import
com.ibeetl.admin.core.entity.CoreMenu
;
...
...
@@ -7,46 +11,59 @@ import com.ibeetl.admin.core.rbac.tree.MenuItem;
import
com.ibeetl.admin.core.service.CoreBaseService
;
import
com.ibeetl.admin.core.service.CorePlatformService
;
import
com.ibeetl.admin.core.util.PlatformException
;
import
java.util.ArrayList
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.stream.Collectors
;
import
javax.validation.constraints.NotNull
;
import
org.beetl.sql.core.engine.PageQuery
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.cache.annotation.Cacheable
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.util.ArrayList
;
import
java.util.List
;
@Service
@Transactional
public
class
MenuConsoleService
extends
CoreBaseService
<
CoreMenu
>
{
@Autowired
MenuConsoleDao
menuDao
;
@Autowired
CoreRoleMenuDao
roleM
enuDao
;
@Autowired
MenuConsoleDao
m
enuDao
;
@Autowired
CorePlatformService
platformService
;
@Autowired
CoreRoleMenuDao
roleMenuDao
;
@Autowired
CorePlatformService
platformService
;
public
void
queryByCondtion
(
PageQuery
<
CoreMenu
>
query
)
{
menuDao
.
queryByCondtion
(
query
);
queryListAfter
(
query
.
getList
());
}
public
Long
saveMenu
(
CoreMenu
menu
)
{
CoreMenu
query
=
new
CoreMenu
();
query
.
setCode
(
menu
.
getCode
());
long
queryCount
=
menuDao
.
templateCount
(
query
);
if
(
queryCount
>
0
)
{
throw
new
PlatformException
(
"菜单编码已存在"
);
}
menu
.
setCreateTime
(
new
Date
());
menu
.
setParentMenuId
(
menu
.
getParent
().
getId
());
menu
.
setFunctionId
(
menu
.
getRelationFunction
().
getId
());
menuDao
.
insert
(
menu
,
true
);
platformService
.
clearMenuCache
();
return
menu
.
getId
();
}
public
void
deleteMenu
(
Long
menuId
)
{
deleteMenuId
(
menuId
);
}
public
void
batchDeleteMenuId
(
List
<
Long
>
menuIds
)
{
for
(
Long
id
:
menuIds
)
{
deleteMenuId
(
id
);
}
...
...
@@ -54,17 +71,22 @@ public class MenuConsoleService extends CoreBaseService<CoreMenu> {
}
public
void
updateMenu
(
CoreMenu
menu
)
{
menu
.
setParentMenuId
(
menu
.
getParent
().
getId
());
menu
.
setFunctionId
(
menu
.
getRelationFunction
().
getId
());
menuDao
.
updateById
(
menu
);
platformService
.
clearMenuCache
();
}
public
CoreMenu
getMenu
(
Long
menuId
)
{
CoreMenu
menu
=
menuDao
.
unique
(
menuId
);
platformService
.
clearMenuCache
();
return
menu
;
}
private
void
deleteMenuId
(
Long
menuId
)
{
MenuItem
root
=
platformService
.
buildMenu
();
MenuItem
fun
=
root
.
findChild
(
menuId
);
List
<
MenuItem
>
all
=
fun
.
findAllItem
();
...
...
@@ -74,6 +96,7 @@ public class MenuConsoleService extends CoreBaseService<CoreMenu> {
}
private
void
realDeleteMenu
(
List
<
MenuItem
>
all
)
{
List
<
Long
>
ids
=
new
ArrayList
<>(
all
.
size
());
for
(
MenuItem
item
:
all
)
{
ids
.
add
(
item
.
getId
());
...
...
@@ -82,4 +105,41 @@ public class MenuConsoleService extends CoreBaseService<CoreMenu> {
// 删除角色和菜单的关系
roleMenuDao
.
deleteRoleMenu
(
ids
);
}
/**
* @return 菜单树,排序
*/
@Cacheable
(
MENU_FUNC_TREE_CACHE
)
public
List
<
CoreMenu
>
getMenusTree
()
{
List
<
CoreMenu
>
coreMenuList
=
menuDao
.
selectMenuAndRelationFunction
();
System
.
out
.
println
(
coreMenuList
);
CoreMenu
root
=
new
CoreMenu
();
root
.
setId
(
0L
);
buildTree
(
root
,
coreMenuList
);
return
root
.
getChildren
();
}
/**
* 深度优先算法递归构建菜单树,根据seq排序
*/
private
void
buildTree
(
CoreMenu
root
,
@NotNull
List
<
CoreMenu
>
allNodes
)
{
if
(
CollUtil
.
isEmpty
(
allNodes
))
{
return
;
}
List
<
CoreMenu
>
childNodes
=
allNodes
.
stream
()
.
filter
(
route
->
ObjectUtil
.
equal
(
route
.
getParentMenuId
(),
root
.
getId
()))
.
sorted
()
.
collect
(
Collectors
.
toList
());
root
.
setChildren
(
childNodes
);
allNodes
.
removeAll
(
childNodes
);
List
<
CoreMenu
>
rootChildrenList
=
root
.
getChildren
();
for
(
CoreMenu
coreFunction
:
rootChildrenList
)
{
buildTree
(
coreFunction
,
allNodes
);
}
}
}
plus-admin/admin-console/src/main/java/com/ibeetl/admin/console/web/MenuElController.java
0 → 100644
View file @
875339d5
package
com.ibeetl.admin.console.web
;
import
com.ibeetl.admin.console.service.MenuConsoleService
;
import
com.ibeetl.admin.core.annotation.Function
;
import
com.ibeetl.admin.core.annotation.RequestBodyPlus
;
import
com.ibeetl.admin.core.entity.CoreFunction
;
import
com.ibeetl.admin.core.entity.CoreMenu
;
import
com.ibeetl.admin.core.rbac.tree.MenuItem
;
import
com.ibeetl.admin.core.service.CorePlatformService
;
import
com.ibeetl.admin.core.util.ConvertUtil
;
import
com.ibeetl.admin.core.web.JsonResult
;
import
java.util.ArrayList
;
import
java.util.Date
;
import
java.util.List
;
import
org.beetl.sql.core.engine.PageQuery
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.DeleteMapping
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.PutMapping
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.springframework.web.bind.annotation.RestController
;
@RequestMapping
(
"menus"
)
@RestController
public
class
MenuElController
{
@Autowired
MenuConsoleService
menuConsoleService
;
@Autowired
CorePlatformService
platformService
;
@GetMapping
@Function
(
"menu.query"
)
public
JsonResult
<
List
<
CoreMenu
>>
menusTree
()
{
List
<
CoreMenu
>
menuTreeItems
=
menuConsoleService
.
getMenusTree
();
return
JsonResult
.
success
(
menuTreeItems
);
}
/**
* 添加
*
* @param menu
* @return
*/
@PostMapping
@Function
(
"menu.save"
)
@ResponseBody
public
JsonResult
save
(
@Validated
@RequestBody
CoreMenu
menu
)
{
Long
id
=
menuConsoleService
.
saveMenu
(
menu
);
return
JsonResult
.
success
(
id
);
}
/**
* 更新
*
* @param menu
* @return
*/
@PutMapping
@Function
(
"menu.update"
)
@ResponseBody
public
JsonResult
update
(
@RequestBody
CoreMenu
menu
)
{
menuConsoleService
.
updateMenu
(
menu
);
return
JsonResult
.
success
();
}
/**
* 批量删除
*
* @param ids 菜单id集合
* @return
*/
@DeleteMapping
@Function
(
"menu.delete"
)
@ResponseBody
public
JsonResult
delete
(
@RequestBodyPlus
(
"ids"
)
ArrayList
<
Long
>
ids
)
{
menuConsoleService
.
batchDeleteMenuId
(
ids
);
return
JsonResult
.
success
();
}
}
plus-admin/admin-console/src/main/resources/application.yml
View file @
875339d5
...
...
@@ -10,7 +10,7 @@ user:
orgId
:
1
# 文件操作的根目录配置 请根据各自计算机配置
localFile
:
root
:
E:\code_workspace\
temp_space
\
root
:
/home/pi/java_dir/
temp_space
/
# --------beetl配置
beetl
:
suffix
:
html
...
...
@@ -60,7 +60,7 @@ spring:
baseDataSource
:
driver-class-name
:
com.mysql.cj.jdbc.Driver
password
:
123456
url
:
jdbc:mysql://
127.0.0.1
:3306/starter_vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false&useInformationSchema=true
url
:
jdbc:mysql://
localhost
:3306/starter_vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false&useInformationSchema=true
username
:
root
session
:
store-type
:
none
plus-admin/admin-console/src/main/resources/log4j2.xml
View file @
875339d5
...
...
@@ -7,8 +7,8 @@
<!-- 日志文件目录、压缩文件目录、日志格式配置 -->
<properties>
<Property
name=
"fileName"
>
/
Users
/admin/Code/log
</Property>
<Property
name=
"fileGz"
>
/
Users
/admin/Code/log/7z
</Property>
<Property
name=
"fileName"
>
/
home/pi/java_dir
/admin/Code/log
</Property>
<Property
name=
"fileGz"
>
/
home/pi/java_dir
/admin/Code/log/7z
</Property>
<Property
name=
"PID"
>
????
</Property>
<Property
name=
"LOG_PATTERN"
>
%clr{%d{DEFAULT}}{blue} %clr{%5level} %clr{${sys:PID}}{magenta}
%clr{---}{faint} %clr{[%.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{信息:%m}{magenta} %clr{%l}{faint} %n%xwEx
...
...
plus-admin/admin-console/src/main/resources/sql/console/menu.md
View file @
875339d5
...
...
@@ -30,5 +30,47 @@ queryByCondtion
order by m.id
@}
selectMenuAndRelationFunction
=======
*
查询菜单和其关联的功能点
```
sql
select
cm
.
id
,
cm
.
name
,
cm
.
code
,
cm
.
function_id
,
cm
.
icon
,
cm
.
parent_menu_id
,
cm
.
seq
,
cm
.
type
,
cf
.
id
func_id
,
cf
.
access_url
func_access_url
,
cf
.
name
func_name
,
cf
.
type
func_type
from
core_menu
cm
join
core_function
cf
on
cf
.
id
=
cm
.
function_id
and
cm
.
del_flag
=
0
and
cf
.
del_flag
=
0
```
@ mapping("MenuFunctionMapping");
MenuFunctionMapping
===
*
菜单功能点结果集映射
```
javascript
var
menu_func_mapping
=
{
"
id
"
:
"
menu_func_map
"
,
"
mapping
"
:
{
"
resultType
"
:
"
com.ibeetl.admin.core.entity.CoreMenu
"
,
"
id
"
:
"
id
"
,
"
name
"
:
"
name
"
,
"
code
"
:
"
code
"
,
"
functionId
"
:
"
function_id
"
,
"
parentMenuId
"
:
"
parent_menu_id
"
,
"
icon
"
:
"
icon
"
,
"
seq
"
:
"
seq
"
,
"
type
"
:
"
type
"
,
"
relationFunction
"
:
{
"
resultType
"
:
"
com.ibeetl.admin.core.entity.CoreFunction
"
,
"
id
"
:
"
func_id
"
,
"
name
"
:
"
func_name
"
,
"
accessUrl
"
:
"
func_access_url
"
,
"
type
"
:
"
func_type
"
}
}
};
```
\ No newline at end of file
plus-admin/admin-core/src/main/java/com/ibeetl/admin/core/conf/CustomErrorController.java
View file @
875339d5
...
...
@@ -6,16 +6,17 @@ import cn.hutool.core.collection.CollUtil;
import
cn.hutool.core.convert.Convert
;
import
cn.hutool.core.util.CharsetUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.http.ContentType
;
import
cn.hutool.system.SystemUtil
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.ibeetl.admin.core.util.PlatformException
;
import
com.ibeetl.admin.core.web.JsonResult
;
import
java.io.IOException
;
import
java.io.UnsupportedEncodingException
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.validation.ConstraintViolation
;
...
...
@@ -25,11 +26,15 @@ import org.slf4j.LoggerFactory;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController
;
import
org.springframework.boot.web.servlet.error.DefaultErrorAttributes
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.util.MimeTypeUtils
;
import
org.springframework.validation.BindingResult
;
import
org.springframework.validation.FieldError
;
import
org.springframework.web.bind.MethodArgumentNotValidException
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.context.request.RequestAttributes
;
import
org.springframework.web.context.request.ServletWebRequest
;
import
org.springframework.web.context.request.WebRequest
;
import
org.springframework.web.servlet.ModelAndView
;
/**
...
...
@@ -46,15 +51,19 @@ public class CustomErrorController extends AbstractErrorController {
private
final
DefaultErrorAttributes
defaultErrorAttributes
;
@Autowired
ObjectMapper
objectMapper
;
@Autowired
ObjectMapper
objectMapper
;
public
CustomErrorController
(
DefaultErrorAttributes
defaultErrorAttributes
)
{
super
(
defaultErrorAttributes
);
this
.
defaultErrorAttributes
=
defaultErrorAttributes
;
}
@RequestMapping
(
ERROR_PATH
)
public
ModelAndView
getErrorPath
(
HttpServletRequest
request
,
HttpServletResponse
response
)
{
public
ModelAndView
getErrorPath
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
UnsupportedEncodingException
{
Throwable
cause
=
getRealException
(
request
);
Map
<
String
,
Object
>
errorInfo
=
wrapErrorInfo
(
request
);
// 后台打印日志信息方方便查错
...
...
@@ -64,13 +73,42 @@ public class CustomErrorController extends AbstractErrorController {
return
hanlderPlatformException
(
errorInfo
,
response
);
}
else
if
(
cause
instanceof
ConstraintViolationException
)
{
return
hanlderConstraintViolationException
(
errorInfo
,
request
,
response
);
}
else
if
(
cause
instanceof
MethodArgumentNotValidException
)
{
return
hanlderMethodArgumentNotValidException
(
errorInfo
,
request
,
response
);
}
else
{
return
hanlderGeneralException
(
errorInfo
,
response
);
}
}
private
ModelAndView
hanlderMethodArgumentNotValidException
(
Map
<
String
,
Object
>
errorInfo
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
UnsupportedEncodingException
{
ModelAndView
modelAndView
=
handlerHtml
(
errorInfo
);
if
(
modelAndView
!=
null
)
{
modelAndView
.
addObject
(
"errorMessage"
,
"服务器内部错误,请联系管理员"
);
logger
.
error
(
"方法参数校验失败,请查看上述详细信息"
);
}
else
{
if
(
Convert
.
toInt
(
errorInfo
.
get
(
"status"
)).
equals
(
HttpStatus
.
NOT_FOUND
.
value
()))
{
writeJson
(
response
,
JsonResult
.
http404
(
errorInfo
.
get
(
"path"
)));
}
else
{
MethodArgumentNotValidException
methodArgumentNotValidException
=
(
MethodArgumentNotValidException
)
getRealException
(
request
);
BindingResult
bindingResult
=
methodArgumentNotValidException
.
getBindingResult
();
List
<
String
>
messages
=
CollUtil
.<
String
>
newArrayList
();
List
<
FieldError
>
fieldErrors
=
bindingResult
.
getFieldErrors
();
for
(
FieldError
fieldError
:
fieldErrors
)
{
messages
.
add
(
fieldError
.
getDefaultMessage
());
}
writeJson
(
response
,
JsonResult
.
fail
(
messages
));
}
}
return
modelAndView
;
}
private
ModelAndView
hanlderGeneralException
(
Map
<
String
,
Object
>
errorInfo
,
HttpServletResponse
response
)
{
ModelAndView
modelAndView
=
handlerHtml
(
errorInfo
);
if
(
modelAndView
!=
null
)
{
modelAndView
.
addObject
(
"errorMessage"
,
"服务器内部错误,请联系管理员"
);
...
...
@@ -82,6 +120,7 @@ public class CustomErrorController extends AbstractErrorController {
private
ModelAndView
hanlderConstraintViolationException
(
Map
<
String
,
Object
>
errorInfo
,
HttpServletRequest
request
,
HttpServletResponse
response
)
{
ModelAndView
modelAndView
=
handlerHtml
(
errorInfo
);
if
(
modelAndView
!=
null
)
{
modelAndView
.
addObject
(
"errorMessage"
,
"服务器内部错误,请联系管理员"
);
...
...
@@ -107,6 +146,7 @@ public class CustomErrorController extends AbstractErrorController {
private
ModelAndView
hanlderPlatformException
(
Map
<
String
,
Object
>
errorInfo
,
HttpServletResponse
response
)
{
ModelAndView
modelAndView
=
handlerHtml
(
errorInfo
);
if
(
modelAndView
!=
null
)
{
modelAndView
.
addObject
(
"errorMessage"
,
errorInfo
.
get
(
"message"
));
...
...
@@ -118,11 +158,9 @@ public class CustomErrorController extends AbstractErrorController {
/**
* 通用处理页面请求方法
*
* @param errorInfo
* @return
*/
protected
ModelAndView
handlerHtml
(
Map
<
String
,
Object
>
errorInfo
)
{
ModelAndView
view
=
null
;
if
(!
Convert
.
toBool
(
errorInfo
.
get
(
"isAjax"
)))
{
view
=
new
ModelAndView
(
"/error.html"
);
...
...
@@ -135,6 +173,7 @@ public class CustomErrorController extends AbstractErrorController {
}
protected
void
handlerAjax
(
Map
<
String
,
Object
>
errorInfo
,
HttpServletResponse
response
)
{
if
(
Convert
.
toInt
(
errorInfo
.
get
(
"status"
)).
equals
(
HttpStatus
.
NOT_FOUND
.
value
()))
{
writeJson
(
response
,
JsonResult
.
http404
(
errorInfo
.
get
(
"path"
)));
}
else
{
...
...
@@ -144,26 +183,19 @@ public class CustomErrorController extends AbstractErrorController {
}
/**
* 提取errorAttributes 中的错误信息,包括:<br>
* timestamp:时间<br>
* status:http响应码<br>
* error:响应码的原因<br>
* exception:异常类名<br>
* errors:controller可能的校验错误对象集合<br>
* message:controller的错误信息<br>
* trace: 异常的堆栈信息<br>
* path:请求路径<br>
*
* @param request
* @return
* 提取errorAttributes 中的错误信息,包括:<br> timestamp:时间<br> status:http响应码<br> error:响应码的原因<br>
* exception:异常类名<br> errors:controller可能的校验错误对象集合<br> message:controller的错误信息<br> trace:
* 异常的堆栈信息<br> path:请求路径<br>
*/
protected
Map
<
String
,
Object
>
wrapErrorInfo
(
HttpServletRequest
request
)
{
Map
<
String
,
Object
>
errorAttributes
=
super
.
getErrorAttributes
(
request
,
true
);
errorAttributes
.
put
(
"isAjax"
,
isJsonRequest
(
request
));
return
Collections
.
unmodifiableMap
(
errorAttributes
);
}
protected
void
prettyLog
(
Map
errorInfo
)
{
Object
path
=
errorInfo
.
get
(
"path"
);
Object
status
=
errorInfo
.
get
(
"status"
);
Object
message
=
errorInfo
.
get
(
"message"
);
...
...
@@ -185,30 +217,25 @@ public class CustomErrorController extends AbstractErrorController {
/**
* json请求,要么是.json后缀的请求,要么是http请求报文中规定的json请求
*
* @param request
* @return
*/
protected
boolean
isJsonRequest
(
HttpServletRequest
request
)
{
String
requestUri
=
(
String
)
request
.
getAttribute
(
"javax.servlet.error.request_uri"
);
if
(
requestUri
!=
null
&&
requestUri
.
endsWith
(
".json"
))
{
return
true
;
}
else
{
return
(
request
.
getHeader
(
"Accept"
).
contains
(
"application/json"
)
||
(
request
.
getHeader
(
"X-Requested-With"
)
!=
null
&&
request
.
getHeader
(
"X-Requested-With"
).
contains
(
"XMLHttpRequest"
)));
&&
request
.
getHeader
(
"X-Requested-With"
).
contains
(
"XMLHttpRequest"
)));
}
}
/**
* json响应的输出流方式
*
* @param response
* @param error
*/
protected
void
writeJson
(
HttpServletResponse
response
,
JsonResult
error
)
{
response
.
addHeader
(
HttpHeaders
.
CONTENT_TYPE
,
MimeTypeUtils
.
APPLICATION_JSON_VALUE
);
response
.
addHeader
(
HttpHeaders
.
ACCEPT_CHARSET
,
CharsetUtil
.
UTF_8
);
response
.
setContentType
(
ContentType
.
JSON
.
toString
(
CharsetUtil
.
CHARSET_
UTF_8
)
)
;
try
{
response
.
getWriter
().
write
(
objectMapper
.
writeValueAsString
(
error
));
}
catch
(
IOException
e
)
{
...
...
@@ -218,22 +245,24 @@ public class CustomErrorController extends AbstractErrorController {
/**
* 获取真正的异常,而不是被tomcat等包装的异常
*
* @param request
* @return
*/
protected
Throwable
getRealException
(
HttpServletRequest
request
)
{
Throwable
error
=
(
Throwable
)
request
.
getAttribute
(
"javax.servlet.error.exception"
);
if
(
error
!=
null
)
{
while
(
error
instanceof
ServletException
&&
error
.
getCause
()
!=
null
)
{
error
=
error
.
getCause
();
}
WebRequest
webRequest
=
new
ServletWebRequest
(
request
);
Throwable
error
=
(
Throwable
)
webRequest
.
getAttribute
(
DefaultErrorAttributes
.
class
.
getName
()
+
".ERROR"
,
RequestAttributes
.
SCOPE_REQUEST
);
if
(
error
==
null
)
{
error
=
(
Throwable
)
webRequest
.
getAttribute
(
"javax.servlet.error.exception"
,
RequestAttributes
.
SCOPE_REQUEST
);
}
return
error
;
}
@Override
public
String
getErrorPath
()
{
return
ERROR_PATH
;
}
}
plus-admin/admin-core/src/main/java/com/ibeetl/admin/core/conf/SpringWebMvcConfigurer.java
View file @
875339d5
...
...
@@ -7,12 +7,15 @@ import static org.springframework.http.HttpMethod.POST;
import
static
org
.
springframework
.
http
.
HttpMethod
.
PUT
;
import
cn.hutool.core.collection.CollUtil
;
import
cn.hutool.core.util.CharsetUtil
;
import
com.ibeetl.admin.core.conf.springmvc.convert.DateConditionalGenericConverter
;
import
com.ibeetl.admin.core.conf.springmvc.convert.StringToDictTypeEnumConverterFactory
;
import
com.ibeetl.admin.core.conf.springmvc.interceptor.HttpRequestInterceptor
;
import
com.ibeetl.admin.core.conf.springmvc.interceptor.SessionInterceptor
;
import
com.ibeetl.admin.core.conf.springmvc.resolve.RequestBodyPlusProcessor
;
import
com.ibeetl.admin.core.service.CoreUserService
;
import
java.nio.charset.Charset
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
...
...
@@ -24,41 +27,56 @@ import org.springframework.context.annotation.Configuration;
import
org.springframework.core.env.Environment
;
import
org.springframework.format.FormatterRegistry
;
import
org.springframework.format.datetime.DateFormatter
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.converter.HttpMessageConverter
;
import
org.springframework.http.converter.StringHttpMessageConverter
;
import
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
;
import
org.springframework.web.method.support.HandlerMethodArgumentResolver
;
import
org.springframework.web.servlet.config.annotation.CorsRegistry
;
import
org.springframework.web.servlet.config.annotation.InterceptorRegistry
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurer
;
import
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
;
/** 切勿在此配置类中向SpringMVC中添加bean。 也就是不要 @Bean这类方法。 会出现无法ServletContext注入null,因为父接口的原因 */
/**
* 切勿在此配置类中向SpringMVC中添加bean。 也就是不要 @Bean这类方法。 会出现无法ServletContext注入null,因为父接口的原因
*/
@Configuration
public
class
SpringWebMvcConfigurer
implements
WebMvcConfigurer
,
InitializingBean
{
public
static
final
String
DEFAULT_APP_NAME
=
"开发平台"
;
/** 系统名称,可以在application.properties中配置 app.name=xxx */
/**
* 系统名称,可以在application.properties中配置 app.name=xxx
*/
// @Value("${app.name}")
// String appName;
private
String
mvcTestPath
;
@Autowired
private
Environment
env
;
@Autowired
private
Environment
env
;
@Autowired
private
CoreUserService
userService
;
@Autowired
private
CoreUserService
userService
;
@Autowired
private
BeetlGroupUtilConfiguration
beetlGroupUtilConfiguration
;
@Autowired
private
BeetlGroupUtilConfiguration
beetlGroupUtilConfiguration
;
@Autowired
private
GroupTemplate
groupTemplate
;
@Autowired
private
GroupTemplate
groupTemplate
;
@Autowired
private
RequestMappingHandlerAdapter
adapter
;
@Autowired
private
RequestMappingHandlerAdapter
adapter
;
/**
* 添加拦截器
*
* @param registry 拦截器的注册器
* @param registry
* 拦截器的注册器
*/
@Override
public
void
addInterceptors
(
InterceptorRegistry
registry
)
{
registry
.
addInterceptor
(
new
HttpRequestInterceptor
()).
addPathPatterns
(
"/**"
);
registry
.
addInterceptor
(
new
SessionInterceptor
(
userService
))
...
...
@@ -66,13 +84,33 @@ public class SpringWebMvcConfigurer implements WebMvcConfigurer, InitializingBea
.
addPathPatterns
(
"/**"
);
}
@Override
public
void
configureMessageConverters
(
List
<
HttpMessageConverter
<?>>
converters
)
{
for
(
HttpMessageConverter
<?>
converter
:
converters
)
{
if
(
converter
instanceof
MappingJackson2HttpMessageConverter
)
{
MappingJackson2HttpMessageConverter
mappingJackson2HttpMessageConverter
=
(
MappingJackson2HttpMessageConverter
)
converter
;
mappingJackson2HttpMessageConverter
.
setDefaultCharset
(
CharsetUtil
.
CHARSET_UTF_8
);
List
<
MediaType
>
supportedMediaTypes
=
mappingJackson2HttpMessageConverter
.
getSupportedMediaTypes
();
List
<
MediaType
>
customMediaTypes
=
CollUtil
.
newArrayList
(
supportedMediaTypes
);
customMediaTypes
.
add
(
MediaType
.
APPLICATION_JSON_UTF8
);
customMediaTypes
.
add
(
MediaType
.
parseMediaType
(
"text/html;charset=UTF-8"
));
customMediaTypes
.
add
(
MediaType
.
parseMediaType
(
"text/plain;charset=UTF-8"
));
customMediaTypes
.
add
(
MediaType
.
parseMediaType
(
"application/xml;charset=UTF-8"
));
mappingJackson2HttpMessageConverter
.
setSupportedMediaTypes
(
customMediaTypes
);
}
}
}
/**
* 增加跨域映射
*
* @param registry 跨域映射注册器
* @param registry
* 跨域映射注册器
*/
@Override
public
void
addCorsMappings
(
CorsRegistry
registry
)
{
registry
.
addMapping
(
"/**"
)
.
allowedOrigins
(
"*"
)
...
...
@@ -81,15 +119,16 @@ public class SpringWebMvcConfigurer implements WebMvcConfigurer, InitializingBea
}
@Override
public
void
addArgumentResolvers
(
List
<
HandlerMethodArgumentResolver
>
resolvers
)
{}
public
void
addArgumentResolvers
(
List
<
HandlerMethodArgumentResolver
>
resolvers
)
{
}
/**
* SpringMVC的请求响应消息的转换格式器
*
* @param registry
*/
@Override
public
void
addFormatters
(
FormatterRegistry
registry
)
{
registry
.
addFormatter
(
new
DateFormatter
(
"yyyy-MM-dd HH:mm:ss"
));
registry
.
addFormatter
(
new
DateFormatter
(
"yyyy-MM-dd"
));
/*converter 在json传参时无效*/
...
...
@@ -99,6 +138,7 @@ public class SpringWebMvcConfigurer implements WebMvcConfigurer, InitializingBea
@Override
public
void
afterPropertiesSet
()
{
this
.
mvcTestPath
=
env
.
getProperty
(
"mvc.test.path"
);
Map
<
String
,
Object
>
var
=
new
HashMap
<>(
5
);
String
appName
=
env
.
getProperty
(
"app.name"
);
...
...
@@ -113,4 +153,5 @@ public class SpringWebMvcConfigurer implements WebMvcConfigurer, InitializingBea
argumentResolvers
.
addAll
(
adapter
.
getArgumentResolvers
());
adapter
.
setArgumentResolvers
(
argumentResolvers
);
}
}
plus-admin/admin-core/src/main/java/com/ibeetl/admin/core/entity/CoreMenu.java
View file @
875339d5
package
com.ibeetl.admin.core.entity
;
import
com.ibeetl.admin.core.annotation.Dict
;
import
com.ibeetl.admin.core.util.ValidateConfig
;
import
com.ibeetl.admin.core.util.enums.CoreDictType
;
import
java.util.Date
;
import
java.util.List
;
import
javax.validation.constraints.NotBlank
;
import
javax.validation.constraints.NotNull
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
org.beetl.sql.core.annotatoin.AutoID
;
import
org.beetl.sql.core.annotatoin.SeqID
;
import
org.beetl.sql.core.annotatoin.UpdateIgnore
;
import
com.ibeetl.admin.core.annotation.Dict
;
import
com.ibeetl.admin.core.util.ValidateConfig
;
import
com.ibeetl.admin.core.util.enums.CoreDictType
;
/** 系统菜单 */
public
class
CoreMenu
extends
BaseEntity
{
/**
* 系统菜单
*/
@NoArgsConstructor
@Data
public
class
CoreMenu
extends
BaseEntity
implements
Comparable
{
public
static
final
String
TYPE_SYSTEM
=
"MENU_S"
;
public
static
final
String
TYPE_NAV
=
"MENU_N"
;
public
static
final
String
TYPE_MENUITEM
=
"MENU_M"
;
@NotNull
(
message
=
"ID不能为空"
,
groups
=
ValidateConfig
.
UPDATE
.
class
)
...
...
@@ -26,7 +32,8 @@ public class CoreMenu extends BaseEntity {
protected
Long
id
;
// 创建时间
@UpdateIgnore
protected
Date
createTime
;
@UpdateIgnore
protected
Date
createTime
;
// 菜单代码
@NotBlank
(
message
=
"菜单代码不能为空"
,
groups
=
ValidateConfig
.
ADD
.
class
)
...
...
@@ -35,6 +42,8 @@ public class CoreMenu extends BaseEntity {
// 功能id
private
Long
functionId
;
private
CoreFunction
relationFunction
;
// 类型 /*1 系统 2 导航 3 菜单项(与功能点有关)*/
@NotNull
(
message
=
"菜单类型不能为空"
)
@Dict
(
type
=
CoreDictType
.
MENU_TYPE
)
...
...
@@ -49,83 +58,35 @@ public class CoreMenu extends BaseEntity {
private
Long
parentMenuId
;
// 排序
@NotNull
(
message
=
"排序不能为空"
)
private
Integer
seq
;
private
Integer
seq
=
Integer
.
MAX_VALUE
;
// 图标
private
String
icon
;
public
CoreMenu
()
{}
public
Long
getId
()
{
return
id
;
}
public
void
setId
(
Long
id
)
{
this
.
id
=
id
;
}
public
String
getCode
()
{
return
code
;
}
public
void
setCode
(
String
code
)
{
this
.
code
=
code
;
}
private
String
icon
=
"menu"
;
public
Long
getFunctionId
()
{
return
functionId
;
}
public
void
setFunctionId
(
Long
functionId
)
{
this
.
functionId
=
functionId
;
}
private
CoreMenu
parent
;
public
String
getType
()
{
return
type
;
}
private
List
<
CoreMenu
>
children
;
public
void
setType
(
String
type
)
{
this
.
type
=
type
;
}
private
short
delFlag
;
public
String
getName
()
{
return
name
;
}
@Override
public
int
compareTo
(
Object
o
)
{
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
if
(!(
o
instanceof
CoreMenu
))
{
throw
new
IllegalArgumentException
(
"给定的对象不是同一个类型"
);
}
if
(
o
==
null
)
{
throw
new
NullPointerException
(
"给定的对象为NULL"
);
}
CoreMenu
other
=
(
CoreMenu
)
o
;
// <0 =0 >0
if
(
this
.
seq
==
null
)
{
this
.
seq
=
Integer
.
MAX_VALUE
;
}
if
(
other
.
seq
==
null
)
{
other
.
seq
=
Integer
.
MAX_VALUE
;
}
return
this
.
seq
-
other
.
seq
;
}
public
Long
getParentMenuId
()
{
return
parentMenuId
;
}
public
void
setParentMenuId
(
Long
parentMenuId
)
{
this
.
parentMenuId
=
parentMenuId
;
}
public
Integer
getSeq
()
{
return
seq
;
}
public
void
setSeq
(
Integer
seq
)
{
this
.
seq
=
seq
;
}
public
String
getIcon
()
{
return
icon
;
}
public
void
setIcon
(
String
icon
)
{
this
.
icon
=
icon
;
}
public
Date
getCreateTime
()
{
return
createTime
;
}
public
void
setCreateTime
(
Date
createTime
)
{
this
.
createTime
=
createTime
;
}
}
plus-admin/admin-core/src/main/java/com/ibeetl/admin/core/service/CorePlatformService.java
View file @
875339d5
...
...
@@ -4,19 +4,6 @@ import static com.ibeetl.admin.core.util.HttpRequestLocal.ACCESS_CURRENT_ORG;
import
static
com
.
ibeetl
.
admin
.
core
.
util
.
HttpRequestLocal
.
ACCESS_CURRENT_USER
;
import
static
com
.
ibeetl
.
admin
.
core
.
util
.
HttpRequestLocal
.
ACCESS_USER_ORGS
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Set
;
import
javax.annotation.PostConstruct
;
import
org.beetl.sql.core.SQLManager
;
import
org.beetl.sql.core.engine.SQLPlaceholderST
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.cache.annotation.CacheEvict
;
import
org.springframework.cache.annotation.Cacheable
;
import
org.springframework.stereotype.Service
;
import
com.ibeetl.admin.core.dao.CoreFunctionDao
;
import
com.ibeetl.admin.core.dao.CoreMenuDao
;
import
com.ibeetl.admin.core.dao.CoreOrgDao
;
...
...
@@ -40,6 +27,17 @@ import com.ibeetl.admin.core.util.PlatformException;
import
com.ibeetl.admin.core.util.beetl.DataAccessFunction
;
import
com.ibeetl.admin.core.util.beetl.NextDayFunction
;
import
com.ibeetl.admin.core.util.enums.DelFlagEnum
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Set
;
import
javax.annotation.PostConstruct
;
import
org.beetl.sql.core.SQLManager
;
import
org.beetl.sql.core.engine.SQLPlaceholderST
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.cache.annotation.CacheEvict
;
import
org.springframework.cache.annotation.Cacheable
;
import
org.springframework.stereotype.Service
;
/**
* 系统平台功能访问入口,所有方法应该支持缓存或者快速访问
...
...
@@ -51,53 +49,85 @@ public class CorePlatformService {
// 菜单树,组织机构树,功能树缓存标记
public
static
final
String
MENU_TREE_CACHE
=
"cache:core:menuTree"
;
/**
* 菜单与其关联功能点树
*/
public
static
final
String
MENU_FUNC_TREE_CACHE
=
"cache:core:menuFuncTree"
;
public
static
final
String
ORG_TREE_CACHE
=
"cache:core:orgTree"
;
public
static
final
String
ORG_CACHE_TREE_CHILDREN
=
"cache:core:orgTreeChildrens"
;
public
static
final
String
ORG_CACHE_TREE_LIST
=
"cache:core:orgTreeList"
;
public
static
final
String
FUNCTION_TREE_CACHE
=
"cache:core:functionTree"
;
// 字典列表
public
static
final
String
DICT_CACHE_TREE_CHILDREN
=
"cache:core:dictTreeChildrens"
;
public
static
final
String
DICT_CACHE_TREE_LIST
=
"cache:core:dictTreeList"
;
public
static
final
String
DICT_CACHE_TYPE
=
"cache:core:dictType"
;
public
static
final
String
DICT_CACHE_VALUE
=
"cache:core:dictValue"
;
public
static
final
String
DICT_CACHE_SAME_LEVEL
=
"cache:core:ditcSameLevel"
;
public
static
final
String
DICT_CACHE_CHILDREN
=
"cache:core:dictChildren"
;
public
static
final
String
USER_FUNCTION_ACCESS_CACHE
=
"cache:core:userFunctionAccess"
;
public
static
final
String
USER_FUNCTION_CHIDREN_CACHE
=
"ccache:core:functionChildren"
;
public
static
final
String
FUNCTION_CACHE
=
"cache:core:function"
;
public
static
final
String
USER_DATA_ACCESS_CACHE
=
"cache:core:userDataAccess"
;
public
static
final
String
USER_MENU_CACHE
=
"cache:core:userMenu"
;
public
static
final
String
ACCESS_SUPPER_ADMIN
=
"admin"
;
@Autowired
HttpRequestLocal
httpRequestLocal
;
@Autowired
HttpRequestLocal
httpRequestLocal
;
@Autowired
CoreRoleFunctionDao
roleFunctionDao
;
@Autowired
CoreRoleFunctionDao
roleFunctionDao
;
@Autowired
CoreRoleMenuDao
sysRoleMenuDao
;
@Autowired
CoreRoleMenuDao
sysRoleMenuDao
;
@Autowired
CoreOrgDao
sysOrgDao
;
@Autowired
CoreOrgDao
sysOrgDao
;
@Autowired
CoreRoleFunctionDao
sysRoleFunctionDao
;
@Autowired
CoreRoleFunctionDao
sysRoleFunctionDao
;
@Autowired
CoreMenuDao
sysMenuDao
;
@Autowired
CoreMenuDao
sysMenuDao
;
@Autowired
CoreUserDao
sysUserDao
;
@Autowired
CoreUserDao
sysUserDao
;
@Autowired
CoreFunctionDao
sysFunctionDao
;
@Autowired
CoreFunctionDao
sysFunctionDao
;
@Autowired
SQLManager
sqlManager
;
@Autowired
SQLManager
sqlManager
;
@Autowired
DataAccessFunction
dataAccessFunction
;
@Autowired
DataAccessFunction
dataAccessFunction
;
@Autowired
CorePlatformService
self
;
@Autowired
CorePlatformService
self
;
@Autowired
DataAccessFactory
dataAccessFactory
;
@Autowired
DataAccessFactory
dataAccessFactory
;
@PostConstruct
@SuppressWarnings
(
"unchecked"
)
public
void
init
()
{
SQLPlaceholderST
.
textFunList
.
add
(
"function"
);
// sql语句里带有此函数来判断数据权限
sqlManager
.
getBeetl
().
getGroupTemplate
().
registerFunction
(
"function"
,
dataAccessFunction
);
...
...
@@ -105,51 +135,59 @@ public class CorePlatformService {
}
public
CoreUser
getCurrentUser
()
{
checkSession
();
CoreUser
user
=
(
CoreUser
)
h
ttpRequestLocal
.
getSessionValue
(
ACCESS_CURRENT_USER
);
CoreUser
user
=
(
CoreUser
)
H
ttpRequestLocal
.
getSessionValue
(
ACCESS_CURRENT_USER
);
return
user
;
}
public
void
changeOrg
(
Long
orgId
)
{
List
<
CoreOrg
>
orgs
=
this
.
getCurrentOrgs
();
for
(
CoreOrg
org
:
orgs
)
{
if
(
org
.
getId
().
equals
(
orgId
))
{
h
ttpRequestLocal
.
setSessionValue
(
ACCESS_CURRENT_ORG
,
org
);
H
ttpRequestLocal
.
setSessionValue
(
ACCESS_CURRENT_ORG
,
org
);
}
}
}
public
Long
getCurrentOrgId
()
{
checkSession
();
CoreOrg
org
=
(
CoreOrg
)
h
ttpRequestLocal
.
getSessionValue
(
ACCESS_CURRENT_ORG
);
CoreOrg
org
=
(
CoreOrg
)
H
ttpRequestLocal
.
getSessionValue
(
ACCESS_CURRENT_ORG
);
return
org
.
getId
();
}
public
CoreOrg
getCurrentOrg
()
{
checkSession
();
CoreOrg
org
=
(
CoreOrg
)
h
ttpRequestLocal
.
getSessionValue
(
ACCESS_CURRENT_ORG
);
CoreOrg
org
=
(
CoreOrg
)
H
ttpRequestLocal
.
getSessionValue
(
ACCESS_CURRENT_ORG
);
return
org
;
}
public
List
<
CoreOrg
>
getCurrentOrgs
()
{
List
<
CoreOrg
>
orgs
=
(
List
<
CoreOrg
>)
httpRequestLocal
.
getSessionValue
(
ACCESS_USER_ORGS
);
List
<
CoreOrg
>
orgs
=
(
List
<
CoreOrg
>)
HttpRequestLocal
.
getSessionValue
(
ACCESS_USER_ORGS
);
return
orgs
;
}
protected
void
checkSession
()
{
CoreOrg
org
=
(
CoreOrg
)
httpRequestLocal
.
getSessionValue
(
ACCESS_CURRENT_ORG
);
CoreOrg
org
=
(
CoreOrg
)
HttpRequestLocal
.
getSessionValue
(
ACCESS_CURRENT_ORG
);
if
(
org
==
null
)
{
throw
new
PlatformException
(
"会话过期,重新登录"
);
}
}
public
void
setLoginUser
(
CoreUser
user
,
CoreOrg
currentOrg
,
List
<
CoreOrg
>
orgs
)
{
httpRequestLocal
.
setSessionValue
(
ACCESS_CURRENT_USER
,
user
);
httpRequestLocal
.
setSessionValue
(
ACCESS_CURRENT_ORG
,
currentOrg
);
httpRequestLocal
.
setSessionValue
(
ACCESS_USER_ORGS
,
orgs
);
HttpRequestLocal
.
setSessionValue
(
ACCESS_CURRENT_USER
,
user
);
HttpRequestLocal
.
setSessionValue
(
ACCESS_CURRENT_ORG
,
currentOrg
);
HttpRequestLocal
.
setSessionValue
(
ACCESS_USER_ORGS
,
orgs
);
}
public
MenuItem
getMenuItem
(
long
userId
,
long
orgId
)
{
CoreUser
user
=
this
.
sysUserDao
.
unique
(
userId
);
if
(
this
.
isSupperAdmin
(
user
))
{
return
self
.
buildMenu
();
...
...
@@ -160,7 +198,8 @@ public class CorePlatformService {
return
menu
;
}
public
OrgItem
getUserOrgTree
()
{
public
OrgItem
getUserOrgTree
()
{
if
(
this
.
isCurrentSupperAdmin
())
{
OrgItem
root
=
self
.
buildOrg
();
return
root
;
...
...
@@ -189,33 +228,29 @@ public class CorePlatformService {
/**
* 判断用户是否是超级管理员
*
* @param user
* @return
*/
public
boolean
isSupperAdmin
(
CoreUser
user
)
{
return
user
.
getCode
().
startsWith
(
ACCESS_SUPPER_ADMIN
);
}
public
boolean
isCurrentSupperAdmin
()
{
CoreUser
user
=
this
.
getCurrentUser
();
return
isSupperAdmin
(
user
);
}
public
boolean
isAllowUserName
(
String
name
)
{
return
!
name
.
startsWith
(
ACCESS_SUPPER_ADMIN
);
}
/**
* 获取用户在指定功能点的数据权限配置,如果没有,返回空集合
*
* @param userId
* @param orgId
* @param fucntionCode
* @return
*/
@Cacheable
(
USER_DATA_ACCESS_CACHE
)
public
List
<
CoreRoleFunction
>
getRoleFunction
(
Long
userId
,
Long
orgId
,
String
fucntionCode
)
{
List
<
CoreRoleFunction
>
list
=
sysRoleFunctionDao
.
getRoleFunction
(
userId
,
orgId
,
fucntionCode
);
return
list
;
}
...
...
@@ -223,14 +258,14 @@ public class CorePlatformService {
/**
* 当前用户是否能访问功能,用于后台功能验证,functionCode 目前只支持二级域名方式,不支持更多级别
*
* @param functionCode
"user.add","user"
*
@return
* @param functionCode
*
"user.add","user"
*/
@Cacheable
(
USER_FUNCTION_ACCESS_CACHE
)
public
boolean
canAcessFunction
(
Long
userId
,
Long
orgId
,
String
functionCode
)
{
CoreUser
user
=
getCurrentUser
();
if
(
user
.
getId
()
==
userId
&&
isSupperAdmin
(
user
))
{
if
(
Objects
.
equals
(
user
.
getId
()
,
userId
)
&&
isSupperAdmin
(
user
))
{
return
true
;
}
String
str
=
functionCode
;
...
...
@@ -246,13 +281,12 @@ public class CorePlatformService {
/**
* 当前功能的子功能,如果有,则页面需要做按钮级别的过滤
*
* @param userId
* @param orgId
* @param parentFunction 菜单对应的function
* @return
* @param parentFunction
* 菜单对应的function
*/
@Cacheable
(
USER_FUNCTION_CHIDREN_CACHE
)
public
List
<
String
>
getChildrenFunction
(
Long
userId
,
Long
orgId
,
String
parentFunction
)
{
CoreFunction
template
=
new
CoreFunction
();
template
.
setCode
(
parentFunction
);
List
<
CoreFunction
>
list
=
sysFunctionDao
.
template
(
template
);
...
...
@@ -266,23 +300,19 @@ public class CorePlatformService {
/**
* 查询当前用户有用的菜单项目,可以在随后验证是否能显示某项菜单
*
* @return
*/
@Cacheable
(
USER_MENU_CACHE
)
public
Set
<
Long
>
getCurrentMenuIds
(
Long
userId
,
Long
orgId
)
{
List
<
Long
>
list
=
sysRoleMenuDao
.
queryMenuByUser
(
userId
,
orgId
);
return
new
HashSet
<
Long
>(
list
);
}
/**
* 验证菜单是否能被显示
*
* @param item
* @param allows
* @return
*/
public
boolean
canShowMenu
(
CoreUser
user
,
MenuItem
item
,
Set
<
Long
>
allows
)
{
if
(
isSupperAdmin
(
user
))
{
return
true
;
}
...
...
@@ -291,6 +321,7 @@ public class CorePlatformService {
@Cacheable
(
MENU_TREE_CACHE
)
public
MenuItem
buildMenu
()
{
List
<
CoreMenu
>
list
=
sysMenuDao
.
allMenuWithURL
();
return
MenuBuildUtil
.
buildMenuTree
(
list
);
}
...
...
@@ -310,13 +341,13 @@ public class CorePlatformService {
@Cacheable
(
FUNCTION_TREE_CACHE
)
public
FunctionItem
buildFunction
()
{
List
<
CoreFunction
>
list
=
sysFunctionDao
.
all
();
return
FunctionBuildUtil
.
buildOrgTree
(
list
);
}
/**
* 用户信息被管理员修改,重置会话,让用户操作重新登录
*
* @param name
*/
public
void
restUserSession
(
String
name
)
{
// TODO
...
...
@@ -324,13 +355,14 @@ public class CorePlatformService {
@CacheEvict
(
cacheNames
=
{
FUNCTION_CACHE
,
FUNCTION_TREE_CACHE
,
/*功能点本身缓存*/
MENU_TREE_CACHE
,
USER_MENU_CACHE
,
/*功能点关联菜单缓存*/
USER_FUNCTION_ACCESS_CACHE
,
USER_FUNCTION_CHIDREN_CACHE
,
USER_DATA_ACCESS_CACHE
,
/*功能点相关权限缓存*/
FUNCTION_CACHE
,
FUNCTION_TREE_CACHE
,
/*功能点本身缓存*/
MENU_TREE_CACHE
,
MENU_FUNC_TREE_CACHE
,
USER_MENU_CACHE
,
/*功能点关联菜单缓存*/
USER_FUNCTION_ACCESS_CACHE
,
USER_FUNCTION_CHIDREN_CACHE
,
USER_DATA_ACCESS_CACHE
,
/*功能点相关权限缓存*/
},
allEntries
=
true
)
public
void
clearFunctionCache
()
{
...
...
@@ -338,7 +370,8 @@ public class CorePlatformService {
}
@CacheEvict
(
cacheNames
=
{
CorePlatformService
.
MENU_TREE_CACHE
,
CorePlatformService
.
USER_MENU_CACHE
},
cacheNames
=
{
MENU_TREE_CACHE
,
MENU_FUNC_TREE_CACHE
,
USER_MENU_CACHE
},
allEntries
=
true
)
public
void
clearMenuCache
()
{
// 没有做任何事情,交给spring cache来处理了
...
...
@@ -346,25 +379,28 @@ public class CorePlatformService {
@CacheEvict
(
cacheNames
=
{
CorePlatformService
.
DICT_CACHE_CHILDREN
,
CorePlatformService
.
DICT_CACHE_SAME_LEVEL
,
CorePlatformService
.
DICT_CACHE_TYPE
,
CorePlatformService
.
DICT_CACHE_VALUE
CorePlatformService
.
DICT_CACHE_CHILDREN
,
CorePlatformService
.
DICT_CACHE_SAME_LEVEL
,
CorePlatformService
.
DICT_CACHE_TYPE
,
CorePlatformService
.
DICT_CACHE_VALUE
},
allEntries
=
true
)
public
void
clearDictCache
()
{}
public
void
clearDictCache
()
{
}
@CacheEvict
(
cacheNames
=
{
CorePlatformService
.
ORG_TREE_CACHE
},
allEntries
=
true
)
public
void
clearOrgCache
()
{}
public
void
clearOrgCache
()
{
}
/**
* 得到类型为系统的菜单,通常就是根菜单下面
*
* @return
*/
public
List
<
MenuItem
>
getSysMenu
()
{
MenuItem
root
=
buildMenu
();
List
<
MenuItem
>
list
=
root
.
getChildren
();
for
(
MenuItem
item
:
list
)
{
...
...
@@ -377,13 +413,12 @@ public class CorePlatformService {
/**
* 得到菜单的子菜单
*
* @param menuId
* @return
*/
public
List
<
MenuItem
>
getChildMenu
(
Long
menuId
)
{
MenuItem
root
=
buildMenu
();
List
<
MenuItem
>
list
=
root
.
findChild
(
menuId
).
getChildren
();
return
list
;
}
}
ve-admin/admin-web/.env.development
View file @
875339d5
...
...
@@ -6,7 +6,8 @@ ENV = 'development'
# 仅限开发环境,生产环境要用NGINX仅限代理
VUE_APP_BASE_API = '/dev-api'
# VUE_APP_SERVER_HOST = 'http://127.0.0.1:9527/mock'
VUE_APP_SERVER_HOST = 'http://127.0.0.1:8080'
VUE_APP_SERVER_HOST = 'http://127.0.0.1:8080'
#VUE_APP_SERVER_HOST = 'http://192.168.1.177:8080'
# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
# to control whether the babel-plugin-dynamic-import-node plugin is enabled.
...
...
ve-admin/admin-web/Description.md
View file @
875339d5
1、路由由登录后从后端动态生成发送给前端使用addRoutes添加到路由表中
\ No newline at end of file
1、路由由登录后从后端动态生成发送给前端使用addRoutes添加到路由表中
2、不能滥用key属性,更多是同一个父元素下的子元素每一个都要有独特的key,或者你需要一个完整的生命周期
key是vue区分新旧node时对比的关键
ve-admin/admin-web/src/api/menu.js
0 → 100644
View file @
875339d5
/*
* @Author: 一日看尽长安花
* @since: 2020-05-31 14:38:23
* @LastEditTime: 2020-06-13 12:42:08
* @LastEditors: 一日看尽长安花
* @Description:
*/
import
request
from
'
@/utils/request
'
;
/**
* 功能点管理的数据
* @param {*} params
*/
export
function
menus
(
params
)
{
return
request
({
url
:
'
/menus
'
,
method
:
'
get
'
,
params
});
}
/**
* 功能点管理的数据
* @param {*} params
*/
export
function
createMenuItem
(
params
)
{
return
request
({
url
:
'
/menus
'
,
method
:
'
post
'
,
params
});
}
/**
* 功能点管理的数据
* @param {*} params
*/
export
function
updateMenuItem
(
params
)
{
return
request
({
url
:
'
/menus
'
,
method
:
'
put
'
,
params
});
}
/**
* 功能点管理的数据
* @param {*} params
*/
export
function
delMenuItemsByParent
(
params
)
{
return
request
({
url
:
'
/menus
'
,
method
:
'
delete
'
,
params
});
}
ve-admin/admin-web/src/components/Refresh/index.vue
View file @
875339d5
<!--
* @Author: 一日看尽长安花
* @since: 2020-06-07 14:41:55
* @LastEditTime: 2020-06-
07 14:45:23
* @LastEditTime: 2020-06-
14 18:55:44
* @LastEditors: 一日看尽长安花
* @Description:
-->
<
template
><span></span></
template
>
<
script
>
export
default
{
name
:
'
Refresh
'
,
...
...
ve-admin/admin-web/src/icons/svg/menu.svg
0 → 100644
View file @
875339d5
<svg
t=
"1592122095549"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"1126"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"200"
height=
"200"
>
<path
d=
"M864 0h-152c-88.224 0-160 71.776-160 160v152c0 88.224 71.776 160 160 160h152c88.224 0 160-71.776 160-160V160c0-88.224-71.776-160-160-160z m80 312c0 44.112-35.888 80-80 80h-152c-44.112 0-80-35.888-80-80V160c0-44.112 35.888-80 80-80h152c44.112 0 80 35.888 80 80v152zM312 0H160C71.776 0 0 71.776 0 160v152c0 88.224 71.776 160 160 160h152c88.224 0 160-71.776 160-160V160c0-88.224-71.776-160-160-160z m80 312c0 44.112-35.888 80-80 80H160c-44.112 0-80-35.888-80-80V160c0-44.112 35.888-80 80-80h152c44.112 0 80 35.888 80 80v152zM312 552H160c-88.224 0-160 71.776-160 160v152c0 88.224 71.776 160 160 160h152c88.224 0 160-71.776 160-160v-152c0-88.224-71.776-160-160-160z m80 312c0 44.112-35.888 80-80 80H160c-44.112 0-80-35.888-80-80v-152c0-44.112 35.888-80 80-80h152c44.112 0 80 35.888 80 80v152zM984 824c-22.092 0-40 17.908-40 40 0 44.112-35.888 80-80 80h-152c-44.112 0-80-35.888-80-80v-152c0-44.112 35.888-80 80-80h152a80.06 80.06 0 0 1 73.35 47.992c8.85 20.242 32.436 29.472 52.676 20.624 20.242-8.852 29.474-32.436 20.624-52.676C985.164 589.658 927.6 552 864 552h-152c-88.224 0-160 71.776-160 160v152c0 88.224 71.776 160 160 160h152c88.224 0 160-71.776 160-160 0-22.092-17.908-40-40-40z"
p-id=
"1127"
></path>
</svg>
ve-admin/admin-web/src/views/functions/select_dialog.vue
View file @
875339d5
<!--
* @Author: 一日看尽长安花
* @since: 2020-05-30 12:53:38
* @LastEditTime: 2020-06-
06 18:44:44
* @LastEditTime: 2020-06-
14 15:23:59
* @LastEditors: 一日看尽长安花
* @Description:
-->
<
template
>
<el-dialog
id=
"sel-func-dialog"
:key=
"Math.random()"
title=
"功能点选择"
:visible=
"visible"
@
update:visible=
"$emit('update:visible', $event)"
>
<el-input
v-model=
"filterText"
placeholder=
"输入关键字进行过滤"
@
input=
"filterInput"
>
</el-input>
<el-input
v-model=
"filterText"
placeholder=
"输入关键字进行过滤"
>
</el-input>
<el-tree
:key=
"Math.random()"
ref=
"tree"
:data=
"treeData"
node-key=
"id"
...
...
@@ -82,10 +75,12 @@ export default {
filterText
:
''
};
},
watch
:
{
filterText
(
nv
,
ov
)
{
this
.
$refs
.
tree
.
filter
(
nv
);
}
},
methods
:
{
filterInput
(
value
)
{
this
.
$refs
.
tree
.
filter
(
value
);
},
filterNode
(
value
,
data
)
{
if
(
!
value
)
return
true
;
return
data
.
name
.
indexOf
(
value
)
!==
-
1
;
...
...
ve-admin/admin-web/src/views/menus/index.vue
0 → 100644
View file @
875339d5
<!--
* @Author: 一日看尽长安花
* @since: 2020-05-30 12:53:38
* @LastEditTime: 2020-06-14 18:58:00
* @LastEditors: 一日看尽长安花
* @Description:
-->
<
template
>
<!-- vue实例外创建 -->
<div
id=
"menu-manager"
class=
"sp-transfer_editor--two"
>
<div
class=
"sp-side_panel--left"
>
<el-input
v-model=
"filterText"
placeholder=
"输入关键字进行过滤"
>
</el-input>
<el-tree
key=
"treeKey"
ref=
"tree"
:data=
"treeData"
node-key=
"id"
default-expand-all
:expand-on-click-node=
"false"
:filter-node-method=
"filterNode"
>
<template
v-slot=
"
{ node: node, data: data }">
<div
:class=
"['sp-tree_node', 'sp-tree_node_type--' + data.type]"
>
<span>
{{
data
.
name
}}
</span>
<span>
<el-button
plain
type=
"primary"
size=
"mini"
@
click=
"appendNode(node, data)"
>
添加
</el-button>
<el-button
v-if=
"data.id !== 0"
plain
type=
"primary"
size=
"mini"
@
click=
"editNode(node, data)"
>
编辑
</el-button>
<el-button
v-if=
"data.id !== 0"
plain
type=
"primary"
size=
"mini"
@
click=
"removeNode(node, data)"
>
删除
</el-button>
</span>
</div>
</
template
>
</el-tree>
</div>
<div
class=
"sp-side_panel--right"
>
<el-form
key=
"formKey"
ref=
"nodeForm"
:rules=
"rules"
:model=
"formModel"
label-width=
"80px"
>
<el-form-item
label=
"功能名"
prop=
"name"
>
<el-input
v-model=
"formModel.name"
placeholder=
"请输入菜单名称"
></el-input>
</el-form-item>
<el-form-item
label=
"菜单代码"
prop=
"code"
>
<el-input
v-model=
"formModel.code"
placeholder=
"请输入系统唯一菜单代码"
></el-input>
</el-form-item>
<el-form-item
label=
"菜单地址"
prop=
"relation_function"
>
<el-input
v-model=
"formModel.relation_function.access_url"
placeholder=
"请选择关联功能点"
readonly
@
focus=
"openSelectRelationFunctionLayer"
></el-input>
</el-form-item>
<el-form-item
label=
"菜单图标"
>
<el-input
v-model=
"formModel.icon"
placeholder=
"请输入已有的svg图标,询问前端"
></el-input>
</el-form-item>
<el-form-item
label=
"菜单序号"
>
<el-input
v-model=
"formModel.seq"
placeholder=
"请输入本级中的菜单序号"
></el-input>
</el-form-item>
<el-form-item
label=
"父菜单"
prop=
"parent"
>
<el-input
v-model=
"formModel.parent.name"
placeholder=
"点击选择上一级菜单"
readonly
@
focus=
"openSelectParentNodeLayer"
></el-input>
</el-form-item>
<el-form-item
label=
"菜单类型"
prop=
"type"
>
<el-select
v-model=
"formModel.type"
placeholder=
"请选择菜单类型"
>
<el-option
label=
"系统"
value=
"MENU_S"
></el-option>
<el-option
label=
"导航"
value=
"MENU_N"
></el-option>
<el-option
label=
"菜单"
value=
"MENU_M"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button
type=
"primary"
@
click=
"saveNode"
>
保存
</el-button>
<el-button>
取消
</el-button>
</el-form-item>
</el-form>
</div>
<sel-func-dialog
v-model=
"formModel"
:per-level-label=
"['relation_function']"
:visible.sync=
"selFuncDialogVisible"
:tree-data=
"funcTreeData"
>
</sel-func-dialog>
<sel-menu-dialog
v-model=
"formModel"
:per-level-label=
"['parent']"
:visible.sync=
"selParentDialogVisible"
:tree-data=
"treeData"
>
</sel-menu-dialog>
</div>
</template>
<
script
>
/** 菜单管理 */
import
{
menus
,
createMenuItem
,
updateMenuItem
,
delMenuItemsByParent
}
from
'
@/api/menu
'
;
import
{
funcs
}
from
'
@/api/func
'
;
import
SelFuncDialog
from
'
@/views/functions/select_dialog
'
;
import
SelMenuDialog
from
'
./select_dialog
'
;
export
default
{
name
:
'
MenuMange
'
,
components
:
{
SelFuncDialog
,
SelMenuDialog
},
props
:
{},
data
()
{
return
{
filterText
:
''
,
treeData
:
[],
funcTreeData
:
[],
formModel
:
{
parent
:
{
id
:
undefined
,
name
:
undefined
},
relation_function
:
{
id
:
undefined
,
name
:
undefined
}
},
actType
:
'
create
'
,
selFuncDialogVisible
:
false
,
selParentDialogVisible
:
false
,
rules
:
{
name
:
{
required
:
true
,
message
:
'
请输入名称
'
,
trigger
:
'
blur
'
},
code
:
{
required
:
true
,
message
:
'
请输入代码点
'
,
trigger
:
'
blur
'
},
relation_function
:
{
type
:
'
object
'
,
required
:
true
,
fields
:
{
access_url
:
{
type
:
'
string
'
,
message
:
'
请选择关联功能点
'
,
required
:
true
}
}
},
parent
:
{
type
:
'
object
'
,
required
:
true
,
fields
:
{
name
:
{
type
:
'
string
'
,
message
:
'
请选择父功能
'
,
required
:
true
}
}
},
type
:
{
type
:
'
string
'
,
required
:
true
,
message
:
'
请选择访问类型
'
,
trigger
:
'
change
'
}
}
};
},
watch
:
{
filterText
(
val
)
{
this
.
$refs
.
tree
.
filter
(
val
);
}
},
mounted
()
{
menus
().
then
(
res
=>
{
const
{
code
,
message
,
data
}
=
{
...
res
};
const
vmNode
=
[
{
id
:
0
,
name
:
'
平台
'
,
children
:
data
}
];
this
.
treeData
=
vmNode
;
});
funcs
().
then
(
res
=>
{
const
{
code
,
message
,
data
}
=
{
...
res
};
const
vmNode
=
[
{
id
:
-
1
,
name
:
'
平台
'
,
children
:
data
}
];
this
.
funcTreeData
=
vmNode
;
});
},
methods
:
{
filterNode
(
value
,
data
)
{
if
(
!
value
)
return
true
;
return
data
.
name
.
indexOf
(
value
)
!==
-
1
;
},
appendNode
(
node
,
data
)
{
this
.
formModel
=
{
parent
:
{
id
:
undefined
,
name
:
undefined
},
relation_function
:
{
id
:
undefined
,
name
:
undefined
}
};
this
.
formModel
.
parent
=
data
;
this
.
actType
=
'
create
'
;
},
editNode
(
node
,
data
)
{
this
.
formModel
=
data
;
this
.
formModel
.
parent
=
node
.
parent
.
data
;
this
.
actType
=
'
editor
'
;
},
removeNode
(
node
,
data
)
{
const
ids
=
this
.
getTreeBranchIds
(
node
);
this
.
$confirm
(
'
此操作将永久删除该菜单及其子菜单, 是否继续?
'
,
'
提示
'
,
{
confirmButtonText
:
'
确定
'
,
cancelButtonText
:
'
取消
'
,
type
:
'
warning
'
})
.
then
(()
=>
{
delMenuItemsByParent
({
ids
:
ids
}).
then
(
response
=>
{
const
{
code
,
message
,
data
}
=
{
...
response
};
const
loading
=
this
.
$loading
({
lock
:
true
,
text
:
'
Loading
'
,
spinner
:
'
el-icon-loading
'
,
background
:
'
rgba(0, 0, 0, 0.7)
'
});
const
_that
=
this
;
this
.
$message
({
message
:
'
删除成功
'
,
type
:
'
success
'
,
onClose
:
function
(
_instance
)
{
_that
.
$router
.
replace
(
'
/refresh
'
);
loading
.
close
();
}
});
});
})
.
catch
(()
=>
{});
},
getTreeBranchIds
(
node
)
{
let
ids
=
[];
ids
.
push
(
node
.
data
.
id
);
const
_children
=
node
.
childNodes
;
for
(
let
i
=
0
;
i
<
_children
.
length
;
i
++
)
{
const
child
=
_children
[
i
];
let
_child_ids
=
this
.
getTreeBranchIds
(
child
);
ids
=
ids
.
concat
(
_child_ids
);
}
return
ids
;
},
saveNode
()
{
const
_that
=
this
;
_that
.
$refs
.
nodeForm
.
validate
(
valid
=>
{
if
(
!
valid
)
{
_that
.
$message
.
error
(
'
数据请填写完成
'
);
return
false
;
}
// 解除循环引用
delete
_that
.
formModel
.
parent
.
children
;
if
(
_that
.
actType
===
'
create
'
)
{
_that
.
formModel
.
parent_menu_id
=
_that
.
formModel
.
parent
.
id
;
createMenuItem
(
_that
.
formModel
).
then
(
response
=>
{
const
{
code
,
message
,
data
}
=
{
...
response
};
const
_that
=
this
;
const
loading
=
this
.
$loading
({
lock
:
true
,
text
:
'
Loading
'
,
spinner
:
'
el-icon-loading
'
,
background
:
'
rgba(0, 0, 0, 0.7)
'
});
this
.
$message
({
message
:
'
创建菜单成功
'
,
type
:
'
success
'
,
onClose
:
function
(
_instance
)
{
// todo 可以用组件Mixin改写,或者直接挂载到Router原型上
_that
.
$router
.
replace
(
'
/refresh
'
);
loading
.
close
();
}
});
});
}
else
{
updateMenuItem
(
_that
.
formModel
).
then
(
response
=>
{
const
{
code
,
message
,
data
}
=
{
...
response
};
const
_that
=
this
;
const
loading
=
this
.
$loading
({
lock
:
true
,
text
:
'
Loading
'
,
spinner
:
'
el-icon-loading
'
,
background
:
'
rgba(0, 0, 0, 0.7)
'
});
this
.
$message
({
message
:
'
更新菜单成功
'
,
type
:
'
success
'
,
onClose
:
function
(
_instance
)
{
// todo 可以用组件Mixin改写,或者直接挂载到Router原型上
_that
.
$router
.
replace
(
'
/refresh
'
);
loading
.
close
();
}
});
});
}
});
},
openSelectParentNodeLayer
()
{
this
.
selParentDialogVisible
=
true
;
},
openSelectRelationFunctionLayer
()
{
this
.
selFuncDialogVisible
=
true
;
}
}
};
</
script
>
<
style
lang=
"scss"
scoped
>
.sp-transfer_editor--two
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
stretch
;
margin
:
10px
;
min-height
:
84vh
;
max-height
:
84vh
;
}
%sp-side_panel--common
{
flex-grow
:
1
;
flex-shrink
:
1
;
flex-basis
:
0%
;
box-shadow
:
2px
2px
6px
1px
#aaa
;
padding
:
10px
;
margin
:
0
10px
;
}
.sp-side_panel--left
{
@extend
%sp-side_panel--common
;
overflow-y
:
scroll
;
}
.sp-side_panel--right
{
@extend
%sp-side_panel--common
;
}
.sp-tree_node
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
width
:
100%
;
padding-left
:
6px
;
border-radius
:
5px
;
}
%sp-tree_node_type
{
box-shadow
:
1px
1px
1px
1px
#e8f4ff
;
}
.sp-tree_node_type--MENU_S
{
@extend
%sp-tree_node_type
;
background
:
linear-gradient
(
to
right
,
#ff0303
5e
,
transparent
);
}
.sp-tree_node_type--MENU_N
{
@extend
%sp-tree_node_type
;
background
:
linear-gradient
(
to
right
,
#fff503
5e
,
transparent
);
}
.sp-tree_node_type--MENU_M
{
@extend
%sp-tree_node_type
;
background
:
linear-gradient
(
to
right
,
#033cff
5e
,
transparent
);
}
</
style
>
<
style
lang=
"scss"
>
.el-tree-node
{
margin-top
:
5px
;
}
</
style
>
ve-admin/admin-web/src/views/menus/select_dialog.vue
0 → 100644
View file @
875339d5
<!--
* @Author: 一日看尽长安花
* @since: 2020-05-30 12:53:38
* @LastEditTime: 2020-06-14 15:24:13
* @LastEditors: 一日看尽长安花
* @Description:
-->
<
template
>
<el-dialog
id=
"sel-menu-dialog"
title=
"菜单选择"
:visible=
"visible"
@
update:visible=
"$emit('update:visible', $event)"
>
<el-input
v-model=
"filterText"
placeholder=
"输入关键字进行过滤"
>
</el-input>
<el-tree
ref=
"tree"
:data=
"treeData"
node-key=
"id"
:label=
"label"
:show-checkbox=
"true"
default-expand-all
:check-strictly=
"true"
:expand-on-click-node=
"false"
:filter-node-method=
"filterNode"
>
<template
v-slot=
"
{ node: node, data: data }">
<div
:class=
"['sp-tree_node', 'sp-tree_node_type--' + data.type]"
>
<span>
{{
data
.
name
}}
</span>
</div>
</
template
>
</el-tree>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
type=
"primary"
@
click=
"saveSelect"
>
确 定
</el-button>
</div>
</el-dialog>
</template>
<
script
>
export
default
{
name
:
'
SelMenuDialog
'
,
components
:
{},
model
:
{
prop
:
'
value
'
,
event
:
'
updateValue
'
},
props
:
{
visible
:
{
type
:
Boolean
,
default
:
false
},
treeData
:
{
type
:
Array
,
default
:
function
()
{
return
[];
}
},
label
:
{
type
:
String
,
default
:
'
name
'
},
perLevelLabel
:
{
type
:
Array
,
required
:
true
},
value
:
{
type
:
Object
,
required
:
true
}
},
data
()
{
return
{
filterText
:
''
};
},
watch
:
{
filterText
(
nv
)
{
this
.
$refs
.
tree
.
filter
(
nv
);
}
},
methods
:
{
filterNode
(
value
,
data
)
{
if
(
!
value
)
return
true
;
return
data
.
name
.
indexOf
(
value
)
!==
-
1
;
},
saveSelect
()
{
// 包括半选节点
const
selNodes
=
this
.
$refs
.
tree
.
getCheckedNodes
(
false
,
true
);
if
(
selNodes
&&
selNodes
.
length
===
0
)
{
this
.
$emit
(
'
update:visible
'
,
false
);
}
if
(
selNodes
&&
selNodes
.
length
!==
1
)
{
this
.
$message
({
message
:
'
只能选择一个节点
'
,
type
:
'
warning
'
});
return
;
}
let
_node
=
this
.
$refs
.
tree
.
getNode
(
selNodes
[
0
]);
let
resObj
=
{};
for
(
let
i
=
this
.
perLevelLabel
.
length
-
1
;
i
>=
0
;
i
--
)
{
const
_label
=
this
.
perLevelLabel
[
i
];
this
.
$lodash
.
set
(
resObj
,
_label
,
_node
.
data
);
_node
=
_node
.
parent
;
}
const
updateValue
=
this
.
$lodash
.
assignIn
({},
this
.
value
,
resObj
);
this
.
$emit
(
'
updateValue
'
,
updateValue
);
this
.
$emit
(
'
update:visible
'
,
false
);
}
}
};
</
script
>
<
style
lang=
"scss"
scoped
>
.sp-tree_node
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
width
:
100%
;
padding-left
:
6px
;
border-radius
:
5px
;
}
%sp-tree_node_type
{
box-shadow
:
1px
1px
1px
1px
#e8f4ff
;
}
.sp-tree_node_type--MENU_S
{
@extend
%sp-tree_node_type
;
background
:
linear-gradient
(
to
right
,
#ff0303
5e
,
transparent
);
}
.sp-tree_node_type--MENU_N
{
@extend
%sp-tree_node_type
;
background
:
linear-gradient
(
to
right
,
#fff503
5e
,
transparent
);
}
.sp-tree_node_type--MENU_M
{
@extend
%sp-tree_node_type
;
background
:
linear-gradient
(
to
right
,
#033cff
5e
,
transparent
);
}
</
style
>
<
style
lang=
"scss"
>
.el-dialog
{
height
:
90%
;
overflow-y
:
scroll
;
top
:
-10vh
;
margin-bottom
:
-5vh
;
}
.el-tree-node
{
margin-top
:
5px
;
}
</
style
>
Write
Preview
Supports
Markdown
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