修改菜单逻辑.
This commit is contained in:
@@ -30,6 +30,9 @@
|
||||
const openKeys = ref<string[]>([]);
|
||||
const selectedKey = ref<string[]>([]);
|
||||
|
||||
/**
|
||||
* 跳转
|
||||
*/
|
||||
const goto = (item: RouteRecordRaw) => {
|
||||
// 打开外链
|
||||
if (regexUrl.test(item.path)) {
|
||||
@@ -48,6 +51,7 @@
|
||||
name: item.name,
|
||||
});
|
||||
};
|
||||
|
||||
const findMenuOpenKeys = (target: string) => {
|
||||
const result: string[] = [];
|
||||
let isFind = false;
|
||||
@@ -69,9 +73,14 @@
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 监听路由 设置打开的 key
|
||||
*/
|
||||
listenerRouteChange((newRoute) => {
|
||||
const { requiresAuth, activeMenu, hideInMenu } = newRoute.meta;
|
||||
if (requiresAuth && (!hideInMenu || activeMenu)) {
|
||||
// TODO
|
||||
const { activeMenu, hideInMenu } = newRoute.meta;
|
||||
if (!hideInMenu || activeMenu) {
|
||||
const menuOpenKeys = findMenuOpenKeys(
|
||||
(activeMenu || newRoute.name) as string
|
||||
);
|
||||
@@ -84,11 +93,14 @@
|
||||
];
|
||||
}
|
||||
}, true);
|
||||
|
||||
// 展开菜单
|
||||
const setCollapse = (val: boolean) => {
|
||||
if (appStore.device === 'desktop')
|
||||
appStore.updateSettings({ menuCollapse: val });
|
||||
};
|
||||
|
||||
// 渲染菜单
|
||||
const renderSubMenu = () => {
|
||||
function travel(_route: RouteRecordRaw[], nodes = []) {
|
||||
if (_route) {
|
||||
@@ -103,7 +115,8 @@
|
||||
key={element?.name}
|
||||
v-slots={{
|
||||
icon,
|
||||
title: () => h(compile(t(element?.meta?.locale || ''))),
|
||||
// 去除国际化 title: () => h(compile(t(element?.meta?.locale || ''))),
|
||||
title: () => h(compile(element?.meta?.locale || '')),
|
||||
}}
|
||||
>
|
||||
{travel(element?.children)}
|
||||
@@ -114,7 +127,7 @@
|
||||
v-slots={{ icon }}
|
||||
onClick={() => goto(element)}
|
||||
>
|
||||
{t(element?.meta?.locale || '')}
|
||||
{element?.meta?.locale || ''}
|
||||
</a-menu-item>
|
||||
);
|
||||
nodes.push(node as never);
|
||||
@@ -158,5 +171,14 @@
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.arco-menu-icon {
|
||||
margin-right: 10px !important;
|
||||
}
|
||||
|
||||
.arco-menu-indent-list {
|
||||
width: 28px;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="tab-bar-box">
|
||||
<div class="tab-bar-scroll">
|
||||
<div class="tags-wrap">
|
||||
<tab-item
|
||||
<TabItem
|
||||
v-for="(tag, index) in tagList"
|
||||
:key="tag.fullPath"
|
||||
:index="index"
|
||||
@@ -19,14 +19,11 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, watch, onUnmounted } from 'vue';
|
||||
import { computed, onUnmounted, ref, watch } from 'vue';
|
||||
import type { RouteLocationNormalized } from 'vue-router';
|
||||
import {
|
||||
listenerRouteChange,
|
||||
removeRouteListener,
|
||||
} from '@/utils/route-listener';
|
||||
import { listenerRouteChange, removeRouteListener, } from '@/utils/route-listener';
|
||||
import { useAppStore, useTabBarStore } from '@/store';
|
||||
import tabItem from './tab-item.vue';
|
||||
import TabItem from './tab-item.vue';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const tabBarStore = useTabBarStore();
|
||||
@@ -45,11 +42,19 @@
|
||||
affixRef.value.updatePosition();
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 监听路由变化
|
||||
*/
|
||||
// TODO
|
||||
listenerRouteChange((route: RouteLocationNormalized) => {
|
||||
console.log(route);
|
||||
console.log(!route.meta.noAffix);
|
||||
if (
|
||||
!route.meta.noAffix &&
|
||||
!route.meta.noAffix && // todo 改一下
|
||||
!tagList.value.some((tag) => tag.fullPath === route.fullPath)
|
||||
) {
|
||||
console.log('updateTabList', route);
|
||||
tabBarStore.updateTabList(route);
|
||||
}
|
||||
}, true);
|
||||
@@ -66,7 +71,7 @@
|
||||
|
||||
.tab-bar-box {
|
||||
display: flex;
|
||||
padding: 0 0 0 20px;
|
||||
padding: 0 0 0 6px;
|
||||
background-color: var(--color-bg-2);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
|
||||
|
||||
@@ -2,20 +2,17 @@
|
||||
<a-dropdown
|
||||
trigger="contextMenu"
|
||||
:popup-max-height="false"
|
||||
@select="actionSelect"
|
||||
>
|
||||
@select="actionSelect">
|
||||
<span
|
||||
class="arco-tag arco-tag-size-medium arco-tag-checked"
|
||||
:class="{ 'link-activated': itemData.fullPath === $route.fullPath }"
|
||||
@click="goto(itemData)"
|
||||
>
|
||||
@click="goto(itemData)">
|
||||
<span class="tag-link">
|
||||
{{ $t(itemData.title) }}
|
||||
{{ itemData.title }}
|
||||
</span>
|
||||
<span
|
||||
class="arco-icon-hover arco-tag-icon-hover arco-icon-hover-size-medium arco-tag-close-btn"
|
||||
@click.stop="tagClose(itemData, index)"
|
||||
>
|
||||
@click.stop="tagClose(itemData, index)">
|
||||
<icon-close />
|
||||
</span>
|
||||
</span>
|
||||
@@ -27,8 +24,7 @@
|
||||
<a-doption
|
||||
class="sperate-line"
|
||||
:disabled="disabledCurrent"
|
||||
:value="Eaction.current"
|
||||
>
|
||||
:value="Eaction.current">
|
||||
<icon-close />
|
||||
<span>关闭当前标签页</span>
|
||||
</a-doption>
|
||||
@@ -39,8 +35,7 @@
|
||||
<a-doption
|
||||
class="sperate-line"
|
||||
:disabled="disabledRight"
|
||||
:value="Eaction.right"
|
||||
>
|
||||
:value="Eaction.right">
|
||||
<icon-to-right />
|
||||
<span>关闭右侧标签页</span>
|
||||
</a-doption>
|
||||
@@ -113,6 +108,9 @@
|
||||
return props.index === tagList.value.length - 1;
|
||||
});
|
||||
|
||||
/**
|
||||
* 关闭 tag
|
||||
*/
|
||||
const tagClose = (tag: TagProps, idx: number) => {
|
||||
tabBarStore.deleteTab(idx, tag);
|
||||
if (props.itemData.fullPath === route.fullPath) {
|
||||
@@ -124,12 +122,15 @@
|
||||
const findCurrentRouteIndex = () => {
|
||||
return tagList.value.findIndex((el) => el.fullPath === route.fullPath);
|
||||
};
|
||||
|
||||
const actionSelect = async (value: any) => {
|
||||
const { itemData, index } = props;
|
||||
const copyTagList = [...tagList.value];
|
||||
if (value === Eaction.current) {
|
||||
// 关闭当前
|
||||
tagClose(itemData, index);
|
||||
} else if (value === Eaction.left) {
|
||||
// 关闭左侧
|
||||
const currentRouteIdx = findCurrentRouteIndex();
|
||||
copyTagList.splice(1, props.index - 1);
|
||||
|
||||
@@ -138,6 +139,7 @@
|
||||
router.push({ name: itemData.name });
|
||||
}
|
||||
} else if (value === Eaction.right) {
|
||||
// 关闭右侧
|
||||
const currentRouteIdx = findCurrentRouteIndex();
|
||||
copyTagList.splice(props.index + 1);
|
||||
|
||||
@@ -146,14 +148,15 @@
|
||||
router.push({ name: itemData.name });
|
||||
}
|
||||
} else if (value === Eaction.others) {
|
||||
// 关闭其他
|
||||
const filterList = tagList.value.filter((el, idx) => {
|
||||
return idx === 0 || idx === props.index;
|
||||
});
|
||||
tabBarStore.freshTabList(filterList);
|
||||
router.push({ name: itemData.name });
|
||||
} else if (value === Eaction.reload) {
|
||||
// 重新加载
|
||||
tabBarStore.deleteCache(itemData);
|
||||
console.log(route.fullPath);
|
||||
await router.push({
|
||||
name: REDIRECT_ROUTE_NAME,
|
||||
params: {
|
||||
@@ -162,6 +165,7 @@
|
||||
});
|
||||
tabBarStore.addCache(itemData.name);
|
||||
} else {
|
||||
// 关闭全部
|
||||
tabBarStore.resetTabList();
|
||||
router.push({ name: DEFAULT_ROUTE_NAME });
|
||||
}
|
||||
|
||||
@@ -4,26 +4,46 @@ import { useUserStore } from '@/store';
|
||||
export default function usePermission() {
|
||||
const userStore = useUserStore();
|
||||
return {
|
||||
// TODO test
|
||||
/**
|
||||
* 是否可访问路由
|
||||
*/
|
||||
accessRouter(route: RouteLocationNormalized | RouteRecordRaw) {
|
||||
return (
|
||||
!route.meta?.requiresAuth ||
|
||||
!route.meta?.permission ||
|
||||
userStore.permission?.includes(route.meta?.permission)
|
||||
);
|
||||
// route.name
|
||||
// TODO
|
||||
},
|
||||
findFirstPermissionRoute(_routers: any, permission: string) {
|
||||
const cloneRouters = [..._routers];
|
||||
while (cloneRouters.length) {
|
||||
const firstElement = cloneRouters.shift();
|
||||
if (firstElement?.meta?.permission === permission) {
|
||||
return { name: firstElement.name };
|
||||
}
|
||||
if (firstElement?.children) {
|
||||
cloneRouters.push(...firstElement.children);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
/**
|
||||
* 是否有权限
|
||||
*/
|
||||
hasPermission(permission: string) {
|
||||
return userStore.permission?.includes('*') ||
|
||||
userStore.permission?.includes(permission);
|
||||
},
|
||||
|
||||
/**
|
||||
* 是否有权限
|
||||
*/
|
||||
hasAnyPermission(permission: string[]) {
|
||||
return userStore.permission?.includes('*') ||
|
||||
permission.map(s => userStore.permission?.includes(s))
|
||||
.filter(Boolean).length > 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* 是否有角色
|
||||
*/
|
||||
hasRole(role: string) {
|
||||
return userStore.roles?.includes('admin') ||
|
||||
userStore.roles?.includes(role);
|
||||
},
|
||||
|
||||
/**
|
||||
* 是否有角色
|
||||
*/
|
||||
hasAnyRole(role: string[]) {
|
||||
return userStore.roles?.includes('*') ||
|
||||
role.map(s => userStore.roles?.includes(s))
|
||||
.filter(Boolean).length > 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { RouteLocationNormalized } from 'vue-router';
|
||||
import { TagProps } from '@/store/modules/tab-bar/types';
|
||||
|
||||
export const REDIRECT_ROUTE_NAME = 'redirect';
|
||||
|
||||
export const LOGIN_ROUTE_NAME = 'login';
|
||||
@@ -10,15 +13,6 @@ export const DEFAULT_ROUTE_NAME = 'workplace';
|
||||
|
||||
export const DEFAULT_ROUTE_FULL_PATH = '/dashboard/workplace';
|
||||
|
||||
/**
|
||||
* 默认 tab 页面
|
||||
*/
|
||||
export const DEFAULT_TAB = {
|
||||
title: 'menu.dashboard.workplace',
|
||||
name: DEFAULT_ROUTE_NAME,
|
||||
fullPath: DEFAULT_ROUTE_FULL_PATH,
|
||||
};
|
||||
|
||||
/**
|
||||
* 路由白名单
|
||||
*/
|
||||
@@ -28,3 +22,29 @@ export const WHITE_ROUTER_LIST = [
|
||||
{ name: FORBIDDEN_ROUTER_NAME, children: [] },
|
||||
{ name: REDIRECT_ROUTE_NAME, children: [] },
|
||||
];
|
||||
|
||||
/**
|
||||
* 默认 tab 页面
|
||||
*/
|
||||
export const DEFAULT_TAB = {
|
||||
title: '工作台',
|
||||
name: DEFAULT_ROUTE_NAME,
|
||||
fullPath: DEFAULT_ROUTE_FULL_PATH,
|
||||
};
|
||||
|
||||
/**
|
||||
* router 转 tag
|
||||
*/
|
||||
// TODO 获取后端meta
|
||||
export const routerToTag = (route: RouteLocationNormalized): TagProps => {
|
||||
console.log(route);
|
||||
// TODO 还是得需要 name 和 meta 的映射
|
||||
const { name, meta, fullPath, query } = route;
|
||||
return {
|
||||
title: meta.locale || 'me',
|
||||
name: String(name),
|
||||
fullPath,
|
||||
query,
|
||||
ignoreCache: meta.ignoreCache,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
import type { Router, RouteRecordNormalized } from 'vue-router';
|
||||
import NProgress from 'nprogress';
|
||||
import usePermission from '@/hooks/permission';
|
||||
import { useAppStore } from '@/store';
|
||||
import { WHITE_ROUTER_LIST, NOT_FOUND_ROUTER_NAME, FORBIDDEN_ROUTER_NAME } from '../constants';
|
||||
import { NOT_FOUND_ROUTER_NAME, WHITE_ROUTER_LIST } from '../constants';
|
||||
|
||||
export default function setupPermissionGuard(router: Router) {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
const appStore = useAppStore();
|
||||
const permission = usePermission();
|
||||
|
||||
// 未加载菜单 并且 未从白名单中找到 to.name
|
||||
// 未加载菜单 并且 不在白名单内 则加载菜单
|
||||
if (
|
||||
!appStore.appAsyncMenus.length &&
|
||||
!appStore.menuFetched &&
|
||||
!WHITE_ROUTER_LIST.find((el) => el.name === to.name)
|
||||
) {
|
||||
// 加载菜单
|
||||
await appStore.fetchMenuConfig();
|
||||
}
|
||||
// 检查路由是否存在
|
||||
// 检查路由是否存在于授权路由中
|
||||
const menuConfig = [...appStore.appAsyncMenus, ...WHITE_ROUTER_LIST];
|
||||
let exist = false;
|
||||
while (menuConfig.length && !exist) {
|
||||
@@ -30,14 +28,9 @@ export default function setupPermissionGuard(router: Router) {
|
||||
);
|
||||
}
|
||||
}
|
||||
// 检查是否有权限
|
||||
const permissionsAllow = permission.accessRouter(to);
|
||||
if (!exist) {
|
||||
// 页面不存在
|
||||
next({ name: NOT_FOUND_ROUTER_NAME });
|
||||
} else if (!permissionsAllow) {
|
||||
// 无权限
|
||||
next({ name: FORBIDDEN_ROUTER_NAME });
|
||||
} else {
|
||||
// 正常跳转
|
||||
next();
|
||||
|
||||
@@ -43,6 +43,7 @@ export const REDIRECT_ROUTER: RouteRecordRaw = {
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
hideInMenu: true,
|
||||
noAffix: true
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -3,11 +3,12 @@ import { AppRouteRecordRaw } from '../types';
|
||||
|
||||
const DASHBOARD: AppRouteRecordRaw = {
|
||||
name: 'dashboard',
|
||||
path: '/dashboard',
|
||||
component: DEFAULT_LAYOUT,
|
||||
children: [
|
||||
{
|
||||
path: '/dashboard/workplace',
|
||||
name: 'workplace',
|
||||
path: '/dashboard/workplace',
|
||||
component: () => import('@/views/dashboard/workplace/index.vue'),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -3,6 +3,7 @@ import { AppRouteRecordRaw } from '../types';
|
||||
|
||||
const USER: AppRouteRecordRaw = {
|
||||
name: 'user',
|
||||
path: '/user',
|
||||
component: DEFAULT_LAYOUT,
|
||||
children: [
|
||||
{
|
||||
@@ -14,6 +15,9 @@ const USER: AppRouteRecordRaw = {
|
||||
path: '/user/userChild2',
|
||||
name: 'userChild2',
|
||||
component: () => import('@/views/user/child2/index.vue'),
|
||||
meta: {
|
||||
noAffix: true
|
||||
}
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
19
orion-ops-ui/src/router/typings.d.ts
vendored
19
orion-ops-ui/src/router/typings.d.ts
vendored
@@ -1,22 +1,25 @@
|
||||
import 'vue-router';
|
||||
|
||||
/**
|
||||
* 前端覆盖后端
|
||||
*/
|
||||
declare module 'vue-router' {
|
||||
interface RouteMeta {
|
||||
// 后端赋值
|
||||
// 图标
|
||||
icon?: string;
|
||||
// 后端赋值
|
||||
// 名称
|
||||
locale?: string;
|
||||
// 后端赋值
|
||||
// 排序
|
||||
order?: number;
|
||||
// 后端赋值 是否隐藏菜单
|
||||
// 是否隐藏菜单
|
||||
hideInMenu?: boolean;
|
||||
// 后端赋值 是否隐藏子菜单
|
||||
// 是否隐藏子菜单
|
||||
hideChildrenInMenu?: boolean;
|
||||
// 后端赋值 是否添加到 tab
|
||||
// 是否添加到 tab
|
||||
noAffix?: boolean;
|
||||
// 前端赋值 是否忽略缓存
|
||||
// 是否忽略缓存
|
||||
ignoreCache?: boolean;
|
||||
// 不赋值
|
||||
// 是否活跃
|
||||
activeMenu?: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,15 @@ import { defineStore } from 'pinia';
|
||||
import { Notification } from '@arco-design/web-vue';
|
||||
import type { RouteRecordNormalized } from 'vue-router';
|
||||
import defaultSettings from '@/config/settings.json';
|
||||
import { getMenuList } from '@/api/user';
|
||||
import { getMenuList } from '@/api/user/auth';
|
||||
import { AppState } from './types';
|
||||
import router from '@/router';
|
||||
|
||||
const useAppStore = defineStore('app', {
|
||||
state: (): AppState => ({ ...defaultSettings }),
|
||||
state: (): AppState => ({
|
||||
...defaultSettings,
|
||||
menuFetched: false,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
appCurrentSetting(state: AppState): AppState {
|
||||
@@ -62,7 +66,54 @@ const useAppStore = defineStore('app', {
|
||||
async fetchMenuConfig() {
|
||||
try {
|
||||
const { data } = await getMenuList();
|
||||
this.serverMenu = data;
|
||||
// @ts-ignore
|
||||
this.serverMenu = (data as Array<any>).map(s => {
|
||||
// 转换
|
||||
const convert = (item: any) => {
|
||||
// 设置路由属性
|
||||
const meta = {
|
||||
locale: item.name,
|
||||
icon: item.icon,
|
||||
order: item.sort,
|
||||
hideInMenu: item.visible === 0,
|
||||
hideChildrenInMenu: item.visible === 0,
|
||||
noAffix: item.visible === 0,
|
||||
ignoreCache: item.cache === 0,
|
||||
};
|
||||
// 获取 router
|
||||
const route = router.getRoutes().find(r => {
|
||||
return r.name === item.component;
|
||||
});
|
||||
// 设置 router meta
|
||||
if (route) {
|
||||
// 路由配置覆盖菜单配置
|
||||
route.meta = { ...meta, ...route.meta };
|
||||
}
|
||||
// 返回
|
||||
return {
|
||||
name: item.component,
|
||||
path: item.path,
|
||||
meta: meta,
|
||||
children: undefined as unknown
|
||||
};
|
||||
};
|
||||
// 构建父目录
|
||||
const menu = convert(s);
|
||||
// 构建子目录
|
||||
if (s.children) {
|
||||
menu.children = (s.children as Array<any>).map(convert);
|
||||
}
|
||||
return menu;
|
||||
});
|
||||
// 是否已加载过
|
||||
this.menuFetched = true;
|
||||
// 未配置菜单
|
||||
if (this.serverMenu.length === 0) {
|
||||
Notification.error({
|
||||
content: '该用户未配置菜单, 请先配置',
|
||||
closable: true,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
Notification.error({
|
||||
content: '加载菜单失败',
|
||||
@@ -76,6 +127,7 @@ const useAppStore = defineStore('app', {
|
||||
*/
|
||||
clearMenu() {
|
||||
this.serverMenu = [];
|
||||
this.menuFetched = false;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { RouteLocationNormalized } from 'vue-router';
|
||||
import { defineStore } from 'pinia';
|
||||
import { DEFAULT_TAB, DEFAULT_ROUTE_NAME, BAN_TAB_LIST, routerToTag } from '@/router/constants';
|
||||
import { DEFAULT_TAB, DEFAULT_ROUTE_NAME, routerToTag } from '@/router/constants';
|
||||
import { isString } from '@/utils/is';
|
||||
import { TabBarState, TagProps } from './types';
|
||||
|
||||
@@ -24,7 +24,6 @@ const useTabBarStore = defineStore('tabBar', {
|
||||
* 添加 tab
|
||||
*/
|
||||
updateTabList(route: RouteLocationNormalized) {
|
||||
if (BAN_TAB_LIST.includes(route.name as string)) return;
|
||||
this.tagList.push(routerToTag(route));
|
||||
if (!route.meta.ignoreCache) {
|
||||
this.cacheTabList.add(route.name as string);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { getUserInfo } from '@/api/user';
|
||||
import { login as userLogin, LoginRequest, logout as userLogout, } from '@/api/user/auth';
|
||||
import { getUserPermission, login as userLogin, LoginRequest, logout as userLogout } from '@/api/user/auth';
|
||||
import { clearToken, setToken } from '@/utils/auth';
|
||||
import { md5 } from '@/utils';
|
||||
import { removeRouteListener } from '@/utils/route-listener';
|
||||
@@ -13,8 +12,8 @@ const useUserStore = defineStore('user', {
|
||||
username: undefined,
|
||||
nickname: undefined,
|
||||
avatar: undefined,
|
||||
permission: undefined,
|
||||
roles: undefined,
|
||||
permission: undefined,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
@@ -35,13 +34,14 @@ const useUserStore = defineStore('user', {
|
||||
* 获取用户信息
|
||||
*/
|
||||
async info() {
|
||||
const res = await getUserInfo();
|
||||
const { data } = await getUserPermission();
|
||||
this.setInfo({
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
nickname: '管理员',
|
||||
permission: ['*'],
|
||||
roles: ['admin'],
|
||||
id: data.user.id,
|
||||
username: data.user.username,
|
||||
nickname: data.user.nickname,
|
||||
avatar: data.user.avatar,
|
||||
roles: data.roles,
|
||||
permission: data.permissions,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -54,7 +54,9 @@ const useUserStore = defineStore('user', {
|
||||
username: loginForm.username,
|
||||
password: md5(loginForm.password),
|
||||
};
|
||||
// 执行登陆
|
||||
const res = await userLogin(loginRequest);
|
||||
// 设置登陆 token
|
||||
setToken(res.data.token);
|
||||
} catch (err) {
|
||||
clearToken();
|
||||
@@ -69,6 +71,7 @@ const useUserStore = defineStore('user', {
|
||||
try {
|
||||
await userLogout();
|
||||
} finally {
|
||||
// 登出回调
|
||||
this.logoutCallBack();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Listening to routes alone would waste rendering performance. Use the publish-subscribe model for distribution management
|
||||
* 单独监听路由会浪费渲染性能。使用发布订阅模式去进行分发管理。
|
||||
*/
|
||||
import mitt, { Handler } from 'mitt';
|
||||
import type { RouteLocationNormalized } from 'vue-router';
|
||||
|
||||
@@ -13,9 +9,14 @@ let latestRoute: RouteLocationNormalized;
|
||||
|
||||
export function setRouteEmitter(to: RouteLocationNormalized) {
|
||||
emitter.emit(key, to);
|
||||
// TODO 这里寻找
|
||||
latestRoute = to;
|
||||
console.log('change', to);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加路由跳转监听器
|
||||
*/
|
||||
export function listenerRouteChange(
|
||||
handler: (route: RouteLocationNormalized) => void,
|
||||
immediate = true
|
||||
@@ -26,6 +27,9 @@ export function listenerRouteChange(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除路由跳转监听器
|
||||
*/
|
||||
export function removeRouteListener() {
|
||||
emitter.off(key);
|
||||
}
|
||||
|
||||
@@ -81,7 +81,9 @@
|
||||
if (!errors) {
|
||||
setLoading(true);
|
||||
try {
|
||||
// 执行登陆
|
||||
await userStore.login(values as LoginData);
|
||||
// 跳转路由
|
||||
const { redirect, ...othersQuery } = router.currentRoute.value.query;
|
||||
router.push({
|
||||
name: (redirect as string) || 'workplace',
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
<div>
|
||||
<p>UserChild 2</p>
|
||||
<h1 v-permission="['admin']">123</h1>
|
||||
<button @click="red">red</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UserChild2',
|
||||
};
|
||||
<script lang="ts" setup>
|
||||
import router from '@/router';
|
||||
|
||||
function red() {
|
||||
router.push({ name: 'workplace' });
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user