Browse Source

⚗ 重写登录逻辑

master
wangxiang 3 years ago
parent
commit
61adba1a82
  1. 6
      kicc-system/kicc-system-biz/src/main/java/com/cloud/kicc/admin/controller/MenuController.java
  2. 7
      kicc-ui/src/api/sys/menu.ts
  3. 2
      kicc-ui/src/router/guard/paramMenuGuard.ts
  4. 3
      kicc-ui/src/router/guard/permissionGuard.ts
  5. 4
      kicc-ui/src/router/helper/menuHelper.ts
  6. 90
      kicc-ui/src/router/helper/routeHelper.ts
  7. 3
      kicc-ui/src/router/index.ts
  8. 51
      kicc-ui/src/store/modules/permission.ts
  9. 7
      kicc-ui/src/store/modules/user.ts
  10. 8
      kicc-ui/src/utils/helper/treeHelper.ts

6
kicc-system/kicc-system-biz/src/main/java/com/cloud/kicc/admin/controller/MenuController.java

@ -65,7 +65,7 @@ public class MenuController {
@SysLog("菜单新增") @SysLog("菜单新增")
@PostMapping("/save") @PostMapping("/save")
//@PreAuthorize("@pms.hasPermission('menu_add')") @PreAuthorize("@pms.hasPermission('menu_add')")
public R save(@RequestBody Menu menu) { public R save(@RequestBody Menu menu) {
menuService.save(menu); menuService.save(menu);
return R.ok(); return R.ok();
@ -73,7 +73,7 @@ public class MenuController {
@SysLog("菜单修改") @SysLog("菜单修改")
@PutMapping("/update") @PutMapping("/update")
//@PreAuthorize("@pms.hasPermission('menu_edit')") @PreAuthorize("@pms.hasPermission('menu_edit')")
public R update(@RequestBody Menu menu) { public R update(@RequestBody Menu menu) {
menuService.updateById(menu); menuService.updateById(menu);
return R.ok(); return R.ok();
@ -81,7 +81,7 @@ public class MenuController {
@SysLog("菜单删除") @SysLog("菜单删除")
@DeleteMapping("/remove/{id:\\w+}") @DeleteMapping("/remove/{id:\\w+}")
//@PreAuthorize("@pms.hasPermission('menu_del')") @PreAuthorize("@pms.hasPermission('menu_del')")
public R remove(@PathVariable String id) { public R remove(@PathVariable String id) {
if (menuService.count(new QueryWrapper<Menu>().eq("parent_id", id)) > 0) { if (menuService.count(new QueryWrapper<Menu>().eq("parent_id", id)) > 0) {
return R.error("存在子菜单,不允许删除"); return R.error("存在子菜单,不允许删除");

7
kicc-ui/src/api/sys/menu.ts

@ -2,13 +2,10 @@ import { defHttp } from '/@/utils/http/axios';
import { getMenuListResultModel } from './model/menuModel'; import { getMenuListResultModel } from './model/menuModel';
enum Api { enum Api {
GetMenuList = '/system/menu/tree', GetMenuList = '/admin/system/menu/menus',
} }
/** /** 获取用户菜单 */
* @description: Get user menu based on id
*/
export const getMenuList = () => { export const getMenuList = () => {
return defHttp.get<getMenuListResultModel>({ url: Api.GetMenuList }); return defHttp.get<getMenuListResultModel>({ url: Api.GetMenuList });
}; };

2
kicc-ui/src/router/guard/paramMenuGuard.ts

@ -19,7 +19,7 @@ export function createParamMenuGuard(router: Router) {
next(); next();
return; return;
} }
// 菜单已建立 // 检测是否菜单已建立
if (!permissionStore.getIsDynamicAddedRoute) { if (!permissionStore.getIsDynamicAddedRoute) {
next(); next();
return; return;

3
kicc-ui/src/router/guard/permissionGuard.ts

@ -79,13 +79,10 @@ export function createPermissionGuard(router: Router) {
} }
const routes = await permissionStore.buildRoutesAction(); const routes = await permissionStore.buildRoutesAction();
routes.forEach((route) => { routes.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw); router.addRoute(route as unknown as RouteRecordRaw);
}); });
router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw); router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
permissionStore.setDynamicAddedRoute(true); permissionStore.setDynamicAddedRoute(true);
if (to.name === PAGE_NOT_FOUND_ROUTE.name) { if (to.name === PAGE_NOT_FOUND_ROUTE.name) {

4
kicc-ui/src/router/helper/menuHelper.ts

@ -69,9 +69,7 @@ export function transformRouteToMenu(routeModList: AppRouteModule[], routerMappi
return cloneDeep(list); return cloneDeep(list);
} }
/** /** 带有给定参数的配置菜单 */
*
*/
const menuParamRegex = /(?::)([\s\S]+?)((?=\/)|$)/g; const menuParamRegex = /(?::)([\s\S]+?)((?=\/)|$)/g;
export function configureDynamicParamsMenu(menu: Menu, params: RouteParams) { export function configureDynamicParamsMenu(menu: Menu, params: RouteParams) {
const { path, paramPath } = toRaw(menu); const { path, paramPath } = toRaw(menu);

90
kicc-ui/src/router/helper/routeHelper.ts

@ -7,20 +7,14 @@
*/ */
import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types'; import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types';
import type { Router, RouteRecordNormalized } from 'vue-router';
import { getParentLayout, LAYOUT } from '/@/router/constant'; import { getParentLayout, LAYOUT } from '/@/router/constant';
import { cloneDeep, omit } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import { warn } from '/@/utils/log'; import { warn } from '/@/utils/log';
import { createRouter, createWebHashHistory } from 'vue-router';
const IFRAME = () => import('/@/views/sys/iframe/FrameBlank.vue'); const IFRAME = () => import('/@/views/sys/iframe/FrameBlank.vue');
const LayoutMap = new Map<string, () => Promise<typeof import('*.vue')>>(); const LayoutMap = new Map<string, () => Promise<typeof import('*.vue')>>();
LayoutMap.set('LAYOUT', LAYOUT); LayoutMap.set('LAYOUT', LAYOUT);
LayoutMap.set('IFRAME', IFRAME); LayoutMap.set('IFRAME', IFRAME);
let dynamicViewsModules: Record<string, () => Promise<Recordable>>; let dynamicViewsModules: Record<string, () => Promise<Recordable>>;
function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) { function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
@ -46,10 +40,7 @@ function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
}); });
} }
function dynamicImport( function dynamicImport(dynamicViewsModules: Record<string, () => Promise<Recordable>>, component: string) {
dynamicViewsModules: Record<string, () => Promise<Recordable>>,
component: string
) {
const keys = Object.keys(dynamicViewsModules); const keys = Object.keys(dynamicViewsModules);
const matchKeys = keys.filter((key) => { const matchKeys = keys.filter((key) => {
let k = key.replace('../../views', ''); let k = key.replace('../../views', '');
@ -62,14 +53,12 @@ function dynamicImport(
return dynamicViewsModules[matchKey]; return dynamicViewsModules[matchKey];
} }
if (matchKeys?.length > 1) { if (matchKeys?.length > 1) {
warn( warn('Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure');
'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure'
);
return; return;
} }
} }
// 将菜单对象变成路由对象 /** 将菜单对象变成路由对象 */
export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModule[]): T[] { export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModule[]): T[] {
routeList.forEach((route) => { routeList.forEach((route) => {
const component = route.component as string; const component = route.component as string;
@ -91,74 +80,3 @@ export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModul
}); });
return routeList as unknown as T[]; return routeList as unknown as T[];
} }
/**
* 2
*/
export function flatMultiLevelRoutes(routeModules: AppRouteModule[]) {
const modules: AppRouteModule[] = cloneDeep(routeModules);
for (let index = 0; index < modules.length; index++) {
const routeModule = modules[index];
if (!isMultipleRoute(routeModule)) {
continue;
}
promoteRouteLevel(routeModule);
}
return modules;
}
// 路由等级升级
function promoteRouteLevel(routeModule: AppRouteModule) {
// 使用vue-router拼接菜单
let router: Router | null = createRouter({
routes: [routeModule as unknown as RouteRecordNormalized],
history: createWebHashHistory(),
});
const routes = router.getRoutes();
addToChildren(routes, routeModule.children || [], routeModule);
router = null;
routeModule.children = routeModule.children?.map((item) => omit(item, 'children'));
}
// 将所有子路由添加到二级路由
function addToChildren(
routes: RouteRecordNormalized[],
children: AppRouteRecordRaw[],
routeModule: AppRouteModule
) {
for (let index = 0; index < children.length; index++) {
const child = children[index];
const route = routes.find((item) => item.name === child.name);
if (!route) {
continue;
}
routeModule.children = routeModule.children || [];
if (!routeModule.children.find((item) => item.name === route.name)) {
routeModule.children?.push(route as unknown as AppRouteModule);
}
if (child.children?.length) {
addToChildren(routes, child.children, routeModule);
}
}
}
// 判断级别是否超过2级
function isMultipleRoute(routeModule: AppRouteModule) {
if (!routeModule || !Reflect.has(routeModule, 'children') || !routeModule.children?.length) {
return false;
}
const children = routeModule.children;
let flag = false;
for (let index = 0; index < children.length; index++) {
const child = children[index];
if (child.children?.length) {
flag = true;
break;
}
}
return flag;
}

3
kicc-ui/src/router/index.ts

@ -22,8 +22,7 @@ getRouteNames(basicRoutes);
// 应用路由器 // 应用路由器
export const router = createRouter({ export const router = createRouter({
// @ts-ignore history: createWebHashHistory(import.meta.env.VITE_PUBLIC_PATH as string),
history: createWebHashHistory(import.meta.env.VITE_PUBLIC_PATH),
routes: basicRoutes as unknown as RouteRecordRaw[], routes: basicRoutes as unknown as RouteRecordRaw[],
strict: true, strict: true,
scrollBehavior: () => ({ left: 0, top: 0 }), scrollBehavior: () => ({ left: 0, top: 0 }),

51
kicc-ui/src/store/modules/permission.ts

@ -11,7 +11,7 @@ import { defineStore } from 'pinia';
import { store } from '/@/store'; import { store } from '/@/store';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { useUserStore } from './user'; import { useUserStore } from './user';
import { transformObjToRoute, flatMultiLevelRoutes } from '/@/router/helper/routeHelper'; import { transformObjToRoute } from '/@/router/helper/routeHelper';
import { transformRouteToMenu } from '/@/router/helper/menuHelper'; import { transformRouteToMenu } from '/@/router/helper/menuHelper';
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
import { filter } from '/@/utils/helper/treeHelper'; import { filter } from '/@/utils/helper/treeHelper';
@ -75,9 +75,7 @@ export const usePermissionStore = defineStore({
return !ignoreRoute; return !ignoreRoute;
}; };
/** /** 根据设置的首页path,修正routes中的affix标记(固定首页) */
* pathroutes中的affix标记
*/
const patchHomeAffix = (routes: AppRouteRecordRaw[]) => { const patchHomeAffix = (routes: AppRouteRecordRaw[]) => {
if (!routes || routes.length === 0) return; if (!routes || routes.length === 0) return;
let homePath: string = userStore.getUserInfo.homePath || PageEnum.BASE_HOME; let homePath: string = userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
@ -88,7 +86,7 @@ export const usePermissionStore = defineStore({
const currentPath = path.startsWith('/') ? path : parentPath + path; const currentPath = path.startsWith('/') ? path : parentPath + path;
if (currentPath === homePath) { if (currentPath === homePath) {
if (redirect) { if (redirect) {
homePath = route.redirect! as string; homePath = route.redirect as string;
} else { } else {
route.meta = Object.assign({}, route.meta, { affix: true }); route.meta = Object.assign({}, route.meta, { affix: true });
throw new Error('end'); throw new Error('end');
@ -100,42 +98,33 @@ export const usePermissionStore = defineStore({
try { try {
patcher(routes); patcher(routes);
} catch (e) { } catch (e) {
// 已处理完毕跳出循环 // 固定首页已处理完毕跳出循环
return;
} }
return;
}; };
// 如果确定不需要做后台动态权限,请在下方评论整个判断 /** 提示菜单正在加载中 */
const { createMessage } = useMessage(); const { createMessage } = useMessage();
createMessage.loading({ createMessage.loading({
content: t('sys.app.menuLoading'), content: t('sys.app.menuLoading'),
duration: 1, duration: 1,
}); });
// !模拟从后台获取权限码, /** 构建菜单与路由 */
// 这个功能可能只需要执行一次,实际项目可以自己放在合适的时间 return (await getMenuList().then(data=> {
let routeList: AppRouteRecordRaw[] = []; let routeList = <AppRouteRecordRaw[]>data;
try { // 将菜单对象变成路由对象
routeList = (await getMenuList()) as AppRouteRecordRaw[]; routeList = transformObjToRoute(routeList);
} catch (error) { const menuList = transformRouteToMenu(routeList);
this.setMenuList(menuList);
// 过滤忽略路由配置项,只构建菜单不构建路由
routeList = filter(routeList, routeRemoveIgnoreFilter);
routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
patchHomeAffix(routes);
return routes;
}).catch(error => {
console.error(error); console.error(error);
} })) as AppRouteRecordRaw[];
// 动态引入组件
routeList = transformObjToRoute(routeList);
// 后台路由到菜单结构
const menuList = transformRouteToMenu(routeList);
this.setMenuList(menuList);
// 删除 meta.ignoreRoute 项目
routeList = filter(routeList, routeRemoveIgnoreFilter);
routeList = routeList.filter(routeRemoveIgnoreFilter);
routeList = flatMultiLevelRoutes(routeList);
routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
patchHomeAffix(routes);
return routes;
}, },
}, },
}); });

7
kicc-ui/src/store/modules/user.ts

@ -103,16 +103,16 @@ export const useUserStore = defineStore({
const { access_token, refresh_token } = data; const { access_token, refresh_token } = data;
this.setAccessToken(access_token); this.setAccessToken(access_token);
this.setRefreshToken(refresh_token); this.setRefreshToken(refresh_token);
// 获取用户信息 // 获取用户信息
const userInfo = await this.getUserInfoAction(); const userInfo = await this.getUserInfoAction();
const sessionTimeout = this.sessionTimeout; const sessionTimeout = this.sessionTimeout;
if (sessionTimeout) { if (sessionTimeout) {
this.setSessionTimeout(false); this.setSessionTimeout(false);
} else if (goHome) { } else if (goHome) {
// 处理路由与菜单的构建,并且进行缓存
const permissionStore = usePermissionStore(); const permissionStore = usePermissionStore();
// 使用isDynamicAddedRoute字段做菜单路由缓存功能
if (!permissionStore.isDynamicAddedRoute) { if (!permissionStore.isDynamicAddedRoute) {
const routes = await permissionStore.buildRoutesAction(); const routes = await permissionStore.buildRoutesAction();
routes.forEach((route) => { routes.forEach((route) => {
@ -122,7 +122,6 @@ export const useUserStore = defineStore({
permissionStore.setDynamicAddedRoute(true); permissionStore.setDynamicAddedRoute(true);
} }
await router.replace(userInfo.homePath || PageEnum.BASE_HOME); await router.replace(userInfo.homePath || PageEnum.BASE_HOME);
} }
return userInfo; return userInfo;
} catch (error) { } catch (error) {

8
kicc-ui/src/utils/helper/treeHelper.ts

@ -8,12 +8,12 @@
interface TreeHelperConfig { interface TreeHelperConfig {
id: string; id: string;
children: string; children: string;
pid: string; parentId: string;
} }
const DEFAULT_CONFIG: TreeHelperConfig = { const DEFAULT_CONFIG: TreeHelperConfig = {
id: 'id', id: 'id',
children: 'children', children: 'children',
pid: 'pid', parentId: 'parentId',
}; };
const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config); const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config);
@ -23,14 +23,14 @@ export function listToTree<T = any>(list: any[], config: Partial<TreeHelperConfi
const conf = getConfig(config) as TreeHelperConfig; const conf = getConfig(config) as TreeHelperConfig;
const nodeMap = new Map(); const nodeMap = new Map();
const result: T[] = []; const result: T[] = [];
const { id, children, pid } = conf; const { id, children, parentId } = conf;
for (const node of list) { for (const node of list) {
node[children] = node[children] || []; node[children] = node[children] || [];
nodeMap.set(node[id], node); nodeMap.set(node[id], node);
} }
for (const node of list) { for (const node of list) {
const parent = nodeMap.get(node[pid]); const parent = nodeMap.get(node[parentId]);
(parent ? parent.children : result).push(node); (parent ? parent.children : result).push(node);
} }
return result; return result;

Loading…
Cancel
Save