新增:新增获取路由信息 API(默认前端动态路由处于关闭状态,可通过[页面配置]>[菜单来源于后台]开启)
1.在页面导航栏中通过[页面配置]>[菜单来源于后台]临时启用,刷新后配置失效 2.在前端项目 src/config/setting.json 中,可通过 menuFromServer 配置永久启用
This commit is contained in:
parent
fb0effed9a
commit
d8ceda4654
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.cnadmin.auth.model.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 元数据信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/2/26 22:51
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(description = "元数据信息")
|
||||
public class MetaVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 菜单标题
|
||||
*/
|
||||
@Schema(description = "菜单标题")
|
||||
private String locale;
|
||||
|
||||
/**
|
||||
* 菜单图标
|
||||
*/
|
||||
@Schema(description = "菜单图标")
|
||||
private String icon;
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.cnadmin.auth.model.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
/**
|
||||
* 路由信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/2/26 22:51
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(description = "路由信息")
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class RouteVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 路由地址
|
||||
*/
|
||||
@Schema(description = "路由地址")
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 组件名称
|
||||
*/
|
||||
@Schema(description = "组件名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 组件路径
|
||||
*/
|
||||
@Schema(description = "组件路径")
|
||||
private String component;
|
||||
|
||||
/**
|
||||
* 元数据
|
||||
*/
|
||||
@Schema(description = "元数据")
|
||||
private MetaVO meta;
|
||||
|
||||
/**
|
||||
* 子路由列表
|
||||
*/
|
||||
@Schema(description = "子路由列表")
|
||||
private List<RouteVO> children;
|
||||
}
|
@ -16,6 +16,10 @@
|
||||
|
||||
package top.charles7c.cnadmin.auth.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import top.charles7c.cnadmin.auth.model.vo.RouteVO;
|
||||
|
||||
/**
|
||||
* 登录业务接口
|
||||
*
|
||||
@ -34,4 +38,13 @@ public interface LoginService {
|
||||
* @return 令牌
|
||||
*/
|
||||
String login(String username, String password);
|
||||
|
||||
/**
|
||||
* 构建路由树
|
||||
*
|
||||
* @param userId
|
||||
* 用户 ID
|
||||
* @return 路由树
|
||||
*/
|
||||
List<RouteVO> buildRouteTree(Long userId);
|
||||
}
|
||||
|
@ -16,23 +16,39 @@
|
||||
|
||||
package top.charles7c.cnadmin.auth.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
||||
|
||||
import top.charles7c.cnadmin.auth.model.vo.MetaVO;
|
||||
import top.charles7c.cnadmin.auth.model.vo.RouteVO;
|
||||
import top.charles7c.cnadmin.auth.service.LoginService;
|
||||
import top.charles7c.cnadmin.auth.service.PermissionService;
|
||||
import top.charles7c.cnadmin.common.annotation.TreeField;
|
||||
import top.charles7c.cnadmin.common.constant.SysConsts;
|
||||
import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum;
|
||||
import top.charles7c.cnadmin.common.enums.MenuTypeEnum;
|
||||
import top.charles7c.cnadmin.common.model.dto.LoginUser;
|
||||
import top.charles7c.cnadmin.common.util.ExceptionUtils;
|
||||
import top.charles7c.cnadmin.common.util.SecureUtils;
|
||||
import top.charles7c.cnadmin.common.util.TreeUtils;
|
||||
import top.charles7c.cnadmin.common.util.helper.LoginHelper;
|
||||
import top.charles7c.cnadmin.common.util.validate.CheckUtils;
|
||||
import top.charles7c.cnadmin.system.model.entity.UserDO;
|
||||
import top.charles7c.cnadmin.system.model.query.MenuQuery;
|
||||
import top.charles7c.cnadmin.system.model.vo.MenuVO;
|
||||
import top.charles7c.cnadmin.system.service.DeptService;
|
||||
import top.charles7c.cnadmin.system.service.MenuService;
|
||||
import top.charles7c.cnadmin.system.service.RoleService;
|
||||
import top.charles7c.cnadmin.system.service.UserService;
|
||||
|
||||
@ -49,6 +65,7 @@ public class LoginServiceImpl implements LoginService {
|
||||
private final UserService userService;
|
||||
private final DeptService deptService;
|
||||
private final RoleService roleService;
|
||||
private final MenuService menuService;
|
||||
private final PermissionService permissionService;
|
||||
|
||||
@Override
|
||||
@ -70,4 +87,42 @@ public class LoginServiceImpl implements LoginService {
|
||||
// 返回令牌
|
||||
return StpUtil.getTokenValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RouteVO> buildRouteTree(Long userId) {
|
||||
Set<String> roleSet = permissionService.listRoleCodeByUserId(userId);
|
||||
if (CollUtil.isEmpty(roleSet)) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
|
||||
// 查询菜单列表
|
||||
List<MenuVO> menuList;
|
||||
if (roleSet.contains(SysConsts.ADMIN_ROLE_CODE)) {
|
||||
MenuQuery menuQuery = new MenuQuery();
|
||||
menuQuery.setStatus(DisEnableStatusEnum.ENABLE.getValue());
|
||||
menuList = menuService.list(menuQuery, null);
|
||||
} else {
|
||||
menuList = menuService.listByUserId(userId);
|
||||
}
|
||||
menuList.removeIf(m -> MenuTypeEnum.BUTTON.equals(m.getType()));
|
||||
|
||||
// 构建路由树
|
||||
TreeField treeField = MenuVO.class.getDeclaredAnnotation(TreeField.class);
|
||||
TreeNodeConfig treeNodeConfig = TreeUtils.genTreeNodeConfig(treeField);
|
||||
List<Tree<Long>> treeList = TreeUtils.build(menuList, treeNodeConfig, (m, tree) -> {
|
||||
tree.setId(m.getId());
|
||||
tree.setParentId(m.getParentId());
|
||||
tree.setName(m.getTitle());
|
||||
tree.setWeight(m.getSort());
|
||||
|
||||
tree.putExtra("path", m.getPath());
|
||||
tree.putExtra("name", m.getName());
|
||||
tree.putExtra("component", m.getComponent());
|
||||
MetaVO metaVO = new MetaVO();
|
||||
metaVO.setLocale(m.getTitle());
|
||||
metaVO.setIcon(m.getIcon());
|
||||
tree.putExtra("meta", metaVO);
|
||||
});
|
||||
return BeanUtil.copyToList(treeList, RouteVO.class);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package top.charles7c.cnadmin.system.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
@ -39,4 +40,13 @@ public interface MenuMapper extends BaseMapper<MenuDO> {
|
||||
* @return 权限码集合
|
||||
*/
|
||||
Set<String> selectPermissionByUserId(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 根据用户 ID 查询
|
||||
*
|
||||
* @param userId
|
||||
* 用户 ID
|
||||
* @return 菜单列表
|
||||
*/
|
||||
List<MenuDO> selectListByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package top.charles7c.cnadmin.system.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import top.charles7c.cnadmin.common.base.BaseService;
|
||||
@ -39,4 +40,13 @@ public interface MenuService extends BaseService<MenuVO, MenuVO, MenuQuery, Menu
|
||||
* @return 权限码集合
|
||||
*/
|
||||
Set<String> listPermissionByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 根据用户 ID 查询
|
||||
*
|
||||
* @param userId
|
||||
* 用户 ID
|
||||
* @return 菜单列表
|
||||
*/
|
||||
List<MenuVO> listByUserId(Long userId);
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
|
||||
import top.charles7c.cnadmin.common.base.BaseServiceImpl;
|
||||
import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum;
|
||||
import top.charles7c.cnadmin.common.util.validate.CheckUtils;
|
||||
@ -77,6 +79,14 @@ public class MenuServiceImpl extends BaseServiceImpl<MenuMapper, MenuDO, MenuVO,
|
||||
return baseMapper.selectPermissionByUserId(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MenuVO> listByUserId(Long userId) {
|
||||
List<MenuDO> menuList = baseMapper.selectListByUserId(userId);
|
||||
List<MenuVO> list = BeanUtil.copyToList(menuList, MenuVO.class);
|
||||
list.forEach(this::fill);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查名称是否存在
|
||||
*
|
||||
|
@ -13,4 +13,16 @@
|
||||
AND m.`status` = 1
|
||||
AND r.`status` = 1
|
||||
</select>
|
||||
|
||||
<select id="selectListByUserId" resultType="top.charles7c.cnadmin.system.model.entity.MenuDO">
|
||||
SELECT m.*
|
||||
FROM `sys_menu` as m
|
||||
LEFT JOIN `sys_role_menu` as rm ON rm.`menu_id` = m.`id`
|
||||
LEFT JOIN `sys_role` as r ON r.`id` = rm.`role_id`
|
||||
LEFT JOIN `sys_user_role` as sur ON sur.`role_id` = r.`id`
|
||||
LEFT JOIN `sys_user` as u ON u.`id` = sur.`user_id`
|
||||
WHERE u.`id` = #{userId}
|
||||
AND m.`status` = 1
|
||||
AND r.`status` = 1
|
||||
</select>
|
||||
</mapper>
|
@ -27,6 +27,6 @@ export function getUserInfo() {
|
||||
return axios.get<UserState>(`${BASE_URL}/user/info`);
|
||||
}
|
||||
|
||||
export function getMenuList() {
|
||||
return axios.get<RouteRecordNormalized[]>('/api/user/menu');
|
||||
export function listRoute() {
|
||||
return axios.get<RouteRecordNormalized[]>(`${BASE_URL}/route`);
|
||||
}
|
||||
|
@ -95,7 +95,7 @@
|
||||
_route.forEach((element) => {
|
||||
// This is demo, modify nodes as needed
|
||||
const icon = element?.meta?.icon
|
||||
? () => h(compile(`<${element?.meta?.icon}/>`))
|
||||
? () => h(compile(`<icon-${element?.meta?.icon}/>`))
|
||||
: null;
|
||||
const node =
|
||||
element?.children && element?.children.length !== 0 ? (
|
||||
|
@ -3,7 +3,7 @@ export default {
|
||||
name: 'ArcoWebsite',
|
||||
meta: {
|
||||
locale: 'menu.arcoWebsite',
|
||||
icon: 'icon-link',
|
||||
icon: 'link',
|
||||
requiresAuth: true,
|
||||
order: 106,
|
||||
},
|
||||
|
@ -3,7 +3,7 @@ export default {
|
||||
name: 'GitHub',
|
||||
meta: {
|
||||
locale: 'menu.github',
|
||||
icon: 'icon-github',
|
||||
icon: 'github',
|
||||
requiresAuth: true,
|
||||
order: 107,
|
||||
},
|
||||
|
@ -8,7 +8,7 @@ const EXCEPTION: AppRouteRecordRaw = {
|
||||
meta: {
|
||||
locale: 'menu.exception',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-exclamation-circle',
|
||||
icon: 'exclamation-circle',
|
||||
order: 104,
|
||||
},
|
||||
children: [
|
||||
|
@ -7,7 +7,7 @@ const FORM: AppRouteRecordRaw = {
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: 'menu.form',
|
||||
icon: 'icon-bookmark',
|
||||
icon: 'bookmark',
|
||||
requiresAuth: true,
|
||||
order: 101,
|
||||
},
|
||||
|
@ -8,7 +8,7 @@ const LIST: AppRouteRecordRaw = {
|
||||
meta: {
|
||||
locale: 'menu.list',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-list',
|
||||
icon: 'list',
|
||||
order: 100,
|
||||
},
|
||||
children: [
|
||||
|
@ -8,7 +8,7 @@ const PROFILE: AppRouteRecordRaw = {
|
||||
meta: {
|
||||
locale: 'menu.profile',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-file',
|
||||
icon: 'file',
|
||||
order: 102,
|
||||
},
|
||||
children: [
|
||||
|
@ -7,7 +7,7 @@ const RESULT: AppRouteRecordRaw = {
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: 'menu.result',
|
||||
icon: 'icon-check-circle',
|
||||
icon: 'check-circle',
|
||||
requiresAuth: true,
|
||||
order: 103,
|
||||
},
|
||||
|
@ -8,7 +8,7 @@ const VISUALIZATION: AppRouteRecordRaw = {
|
||||
meta: {
|
||||
locale: 'menu.visualization',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-bar-chart',
|
||||
icon: 'bar-chart',
|
||||
order: 105,
|
||||
},
|
||||
children: [
|
||||
|
@ -9,7 +9,7 @@ const DASHBOARD: AppRouteRecordRaw = {
|
||||
meta: {
|
||||
locale: 'menu.dashboard',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-dashboard',
|
||||
icon: 'dashboard',
|
||||
order: 0,
|
||||
hideChildrenInMenu: true,
|
||||
},
|
||||
|
@ -7,7 +7,7 @@ const Monitor: AppRouteRecordRaw = {
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: 'menu.monitor',
|
||||
icon: 'icon-computer',
|
||||
icon: 'computer',
|
||||
requiresAuth: true,
|
||||
order: 2,
|
||||
},
|
||||
|
@ -7,7 +7,7 @@ const System: AppRouteRecordRaw = {
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: 'menu.system',
|
||||
icon: 'icon-settings',
|
||||
icon: 'settings',
|
||||
requiresAuth: true,
|
||||
order: 1,
|
||||
},
|
||||
|
@ -7,7 +7,7 @@ const UserCenter: AppRouteRecordRaw = {
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: 'menu.user',
|
||||
icon: 'icon-user',
|
||||
icon: 'user',
|
||||
requiresAuth: true,
|
||||
},
|
||||
children: [
|
||||
|
@ -3,7 +3,7 @@ import { Notification } from '@arco-design/web-vue';
|
||||
import type { NotificationReturn } from '@arco-design/web-vue/es/notification/interface';
|
||||
import type { RouteRecordNormalized } from 'vue-router';
|
||||
import defaultSettings from '@/config/settings.json';
|
||||
import { getMenuList } from '@/api/auth/login';
|
||||
import { listRoute } from '@/api/auth/login';
|
||||
import { AppState } from './types';
|
||||
|
||||
const useAppStore = defineStore('app', {
|
||||
@ -52,7 +52,7 @@ const useAppStore = defineStore('app', {
|
||||
content: 'loading',
|
||||
closable: true,
|
||||
});
|
||||
const { data } = await getMenuList();
|
||||
const { data } = await listRoute();
|
||||
this.serverMenu = data;
|
||||
notifyInstance = Notification.success({
|
||||
id: 'menuNotice',
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package top.charles7c.cnadmin.webapi.controller.auth;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@ -32,6 +34,7 @@ import cn.hutool.core.bean.BeanUtil;
|
||||
|
||||
import top.charles7c.cnadmin.auth.model.request.LoginRequest;
|
||||
import top.charles7c.cnadmin.auth.model.vo.LoginVO;
|
||||
import top.charles7c.cnadmin.auth.model.vo.RouteVO;
|
||||
import top.charles7c.cnadmin.auth.model.vo.UserInfoVO;
|
||||
import top.charles7c.cnadmin.auth.service.LoginService;
|
||||
import top.charles7c.cnadmin.common.constant.CacheConsts;
|
||||
@ -93,4 +96,12 @@ public class LoginController {
|
||||
UserInfoVO userInfoVO = BeanUtil.copyProperties(loginUser, UserInfoVO.class);
|
||||
return R.ok(userInfoVO);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取路由信息", description = "获取登录用户的路由信息")
|
||||
@GetMapping("/route")
|
||||
public R<List<RouteVO>> listMenu() {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
List<RouteVO> routeTree = loginService.buildRouteTree(userId);
|
||||
return R.ok(routeTree);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user