功能描述
1:通过接口获取当前应用的所有菜单基本信息及路由信息
2:vuex-oidc为可以检测当前是否获取登录信息,如果没有,则会跳转到登录页面
3:通过接口拿到的路由信息辅助指定到对应vue页面,完成页面及路由的一一绑定
store.js
1:完成oidc相应配置 详细参见
2:建立储存方法及获取接口动态菜单
import { createStore } from 'vuex'
import { vuexOidcCreateStoreModule } from 'vuex-oidc'
import gql from "graphql-tag";//graphQL语法标签,axios可删除
import apolloProvider from "@/assets/js/apolloclient.js";//接口发起client 可按需换成axios
let g = window.Global;
let oidcSettings = {};
//window.Global会携带所有可用信息,此处为了方便本地调试加
//oidc相关配置参见1参考链接
if (!g) {
g = {
oauth2_uri: 'https://devel.ketanyun.cn/sso/oauth2',
oauth2_logout_uri: 'https://devel.ketanyun.cn/sso/logout',
};
}
window.Global = {...g }
let authority = g.oauth2_uri;
let silentRedirectUri = (window.location.origin + g.contextpath + "/oidc-silent")
//oidc登录配置相关信息,按需取舍
oidcSettings = {
authority: authority,
metadata: {
issuer: authority,
authorization_endpoint: authority + "/authorize",
userinfo_endpoint: authority + "/userinfo",
end_session_endpoint: g.oauth2_logout_uri + "?redirect_uri=" + window.location.origin + g.contextpath,
jwks_uri: authority + "/jwks.json"
},
clientId: g.client_id,
redirectUri: window.location.origin + g.contextpath + "/oidc-callback",
responseType: "id_token token",
scope: "data openid ",
automaticSilentRenew: true,
silentRedirectUri: silentRedirectUri,
silentRequestTimeout: 1000
};
export default createStore({
state: {
canvasmenus: [], //非树型结构
menulist: [], //树型结构
asyncRoutestMark: false,
},
mutations: {
// 单层级菜单,没有父子结构,取决于接口返回信息,按需取舍
setCanvasmenus(state, data) {
state.canvasmenus = data
},
// 树型菜单
setMenulist(state, data) {
state.menulist = data
},
// 标记是否已经发起过菜单获取动作,避免二次发起
setAsyncRoutestMark(state, data) {
state.asyncRoutestMark = data
},
},
getters: {
//本处做一次些菜单字段处理,可以按照自己项目做调整,可忽略
menuList(state) {
let list = state.menulist ? (JSON.parse(JSON.stringify(state.menulist))) : [];
list.map((item) => {
const arr = item.path.split('/');
arr.splice(1, 1);
item.routerpath = arr.join('/');
})
list = list && list.length ? list : '';
return list
},
getterStorecanvasmenu(state) {
return state.canvasmenus
}
},
actions: {
//异步获取菜单信息,本处使用的granphQL-apolloclient,可以按需将其换成axios
//简而言之,此处的action发起一个请求获取动态菜单信息
async getMenuList({ state }) {
return apolloProvider.clients.builtinclient.query({
client: 'builtinclient',
fetchPolicy: "no-cache",
query: gql `query canvasmenus{
canvasmenus {
parent
name
text
description
uri
icon
visible
}
}`
})
}
},
modules: {
//oidc 相关配置,各种登录状态及相应返回,详细说明见1参考链接
oidcStore: vuexOidcCreateStoreModule(
oidcSettings, {
namespaced: true,
dispatchEventsOnWindow: true
}, {
userLoaded: (user) => console.log('OIDC user is loaded:', user),
userUnloaded: () => console.log('OIDC user is unloaded'),
accessTokenExpiring: () => console.log('Access token will expire'),
accessTokenExpired: () => console.log('Access token did expire'),
silentRenewError: () => console.log('OIDC user is unloaded'),
userSignedOut: () => console.log('OIDC user is signed out'),
oidcError: (payload) => console.log('OIDC error', payload)
}
)
}
})
router.js
import { createRouter, createWebHistory } from 'vue-router'
import { vuexOidcCreateRouterMiddleware } from 'vuex-oidc'
import store from "@/store/index";//引入store
import { formSideTree } from "@/utils/index.js";//将单层菜单整理层树结构,可忽略
const publicRoutes = [{
path: '/oidc-callback',//oidc登录后回调,可忽略
name: 'OidcCallback',
component: () =>
import ('@/views/oidc/OidcCallback.vue')
},
{
path: '/oidc-silent',//oidc静态登录,可忽略
name: 'Oidcsilent',
component: () =>
import ('@/views/oidc/OidcRenew.vue')
},
{
path: '/',
name: "viewindex",
component: () =>
import ('@/views/view.vue'),//项目主入口模板
meta: {
requiresAuth: true
},
}
]
const router = createRouter({
history: createWebHistory(contentPath),
routes: publicRoutes, //静态路由
});
// 动态路由获取到数据后加入routes
const routerData = (result) => {
let currenRoutes = router.options.routes;
// 获取组件中所有vue文件
let modules =
import.meta.glob('../views/**/*.vue');
if (result) {
result.forEach((item, index) => {
// has用于判断当前路由中是否已经具有,避免重复
let has = currenRoutes.some((it) => it.path == item.path);
if (!has && item.routerpath) {
//多语言
let menutitlei18n = 'contact.menu.menu' + index; //多语言
if (item.description && item.description.indexOf(',') >= 0) {
let mitems = item.description.split(',');
if (mitems[0]) {
menutitlei18n = 'contact.menu.' + mitems[0]
}
}
// 多语言end
// 仅作为viewindex子组件
router.addRoute("viewindex", {
path: `${item.routerpath}`,
name: item.name,
meta: {
title: item.name,
requiresAuth: true,
menutitlei18n,
},
component: modules[`../views${item.path}.vue`]
});
}
if (item.children && item.children.length) {
routerData(item.children);
}
});
}
};
// 动态路由获取
router.beforeEach((to, from, next) => {
if (!(to.matched && to.matched.length)) {
if (to.path !== '/') {
next({ path: '/' });
return
}
}
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
if (requiresAuth) {
vuexOidcCreateRouterMiddleware(store, 'oidcStore')(to, from, async() => {
if (!store.state.asyncRoutestMark) { //是否已完成路由添加
let navigationList = [];
store.commit('setCanvasmenus', [])
await store.dispatch('getMenuList').then((res) => {
if (res ? .data ? .canvasmenus) {
res ? .data ? .canvasmenus ? .map((item) => {
if (item.uri) {
if (item.uri && item.uri.split("vue://")[1] && item.uri.split("vue://")[1].indexOf("@") >= 0) {
item.path = item.uri.split("vue://")[1].split("@")[0];
let arr = item.path.split('/');
arr.splice(1, 1);
item.routerpath = arr.join('/')
}
}
});
//存入store,菜单不必再二次请求
store.commit('setCanvasmenus', res ? .data ? .canvasmenus);
navigationList = formSideTree(res ? .data ? .canvasmenus);
}
})
routerData(navigationList)
store.commit('setAsyncRoutestMark', true) // 添加路由后更改标识为true
next({...to, replace: true }) //路由进行重定向放行
} else {
next();
}
})
} else {
next();
}
})
export default router
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。