diff --git a/README.md b/README.md index a6e6160..bacd184 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,68 @@ # resource-manage ## Project setup + ``` npm install ``` ### Compiles and hot-reloads for development + ``` npm run serve ``` ### Compiles and minifies for production + ``` npm run build ``` ### Lints and fixes files + ``` npm run lint ``` ### Customize configuration + See [Configuration Reference](https://cli.vuejs.org/config/). + +## 部分业务逻辑 + +### 登录流程 + +```mermaid +graph TD; + A[前置路由守卫] --> B{ query.token 是否存在?} + + %% TAPD 登录流程 + B -->|是| C[清除本地 token] + C --> D[调用 fetchToken] + D --> E{获取 token 成功?} + E -->|是| F[保存 token 到 localStorage
重定向并移除 URL token 参数] + E -->|否| G[处理登录失败] + + %% 无 token 流程 + B -->|否| H{检查 Vuex 和 localStorage
是否有 token?} + H -->|都没有| I[显示 token 错误
中断导航] + + %% 恢复 token 流程 + H -->|localStorage 有 Vuex 没有| J[恢复 token 到 Vuex] + J --> L + + %% 加载路由流程 + H -->|Vuex 有| L{检查动态路由是否为空?} + L -->|是| M[获取路由资源] + M --> N[生成动态路由] + N --> O{是否为管理员?} + O -->|是| P[添加系统设置路由] + O -->|否| Q[继续导航] + P --> Q + L -->|否| Q + + %% 登录失败处理 + G --> R{是否不在白名单?} + R -->|是| S[跳转到登录失败页面
中断导航] + R -->|否| T[提示点击TAPD导航栏刷新
中断导航] +``` diff --git a/src/index/router/index.js b/src/index/router/index.js index ca0b22d..f9f4bd1 100644 --- a/src/index/router/index.js +++ b/src/index/router/index.js @@ -3,7 +3,7 @@ import VueRouter from "vue-router"; import store from "@/index/store"; import { generateIndexRouter } from "./generateIndexRouter"; import systemSettings from './systemSettings' -// import { accessTokenError } from "@/index/utils/errorModal"; +import { accessTokenError } from "@/index/utils/errorModal"; // hack router push callback const originalPush = VueRouter.prototype.push; @@ -34,130 +34,86 @@ const router = new VueRouter({ let dynamicRoutes = []; -router.beforeEach(async(to, from, next)=>{ - // 1. 从tapd进来, 重定向路由参数带token - // if(to.query.token){ - // // 1.1 先删除本地存储 - // Vue.ls.remove('token') - // // 1.2 设置token - // const tmp_token = to.query.token - // let formData = new FormData() - // formData.append("tmp_token", tmp_token) - // await store.dispatch('user/getToken', formData) - // if(store.state.user.token){ - // // 1.2.1 能拿到正式token,保存token - // Vue.ls.set('token',store.state.user.token) - // // 跳转,去掉路由参数 - // next({ path: to.path }) - // }else{ - // // 1.2.2 拿不到token - // // 1.2.2.1 判断是不是因为没有添加进白名单 - // if(store.state.user.loginFailed){ - // next({path: '/loginFailed'}) - // }else{ - // // 1.2.2.2 判断是否已弹提示 - // if(!Vue.prototype.$closeModalFun){ - // Vue.prototype.$closeModalFun = accessTokenError('获取token失败,请点击左边导航栏应用“资源管理”重试。') - // } - // next(false) - // } - // } - // }else{ - // 2. 不是从tapd进来 - // 2.1 检查token - // if(!store.state.user.token && !store.state.user.loginFailed){ - // const token = Vue.ls.get('token') - // if(token){ - // store.commit('user/changeToken', token) - // }else { - // if(!Vue.prototype.$closeModalFun){ - // Vue.prototype.$closeModalFun = accessTokenError('获取token失败,请点击左边导航栏应用“资源管理”重试。') - // } - // // 拿不到token, 弹窗并停止 - // next(false) - // } - // } - store.commit('user/changeToken', '123456') - // 2.2 没有路由, 生成路由 - if ( store.state.user.token && dynamicRoutes.length === 0) { - // 获取用户信息 - await store.dispatch('user/getUserInfo') - store - .dispatch("user/getRoutesResource") - .then((routesResource) => { - dynamicRoutes = generateIndexRouter(routesResource) - router.addRoutes(dynamicRoutes) - // 是管理员, 添加设置页面路由 - if(store.state.user.isAdmin){ - router.addRoutes([systemSettings]); - } - }) - .catch((err) => { - Vue.prototype.$error("请求用户资源失败"); - console.log(err) - next(false) - }) +router.beforeEach(async (to, from, next) => { + const { token: queryToken } = to.query; + const userState = store.state.user; + // const storageToken = Vue.ls.get("token"); + const storageToken = Vue.ls.get("token")||'123test'; // 离线状态测试用 + + // 1. 从 TAPD 入口进来, 更新token并重定向 + if (queryToken) return handleTapdLogin(queryToken, to, next); + + // 2. Vuex 和本地存储都没有 token,处理登录失败情况, 结束导航 + if (!userState.token && !storageToken) return handleNoToken(next); + + // 3. Vuex 没有 token,但 localStorage 有,恢复 token + if (!userState.token && storageToken) restoreToken(storageToken); + + // 4. Vuex 有 token,但还没有动态路由,获取用户资源, 生成动态路由 + if (userState.token && dynamicRoutes.length === 0) loadRoutes(userState.isAdmin, next); + + // 5. 放行 + next(); +}); + +/** 处理从 TAPD 入口进来的情况 */ +async function handleTapdLogin(queryToken, to, next) { + Vue.ls.remove("token"); // 清除本地 token + + if (await fetchToken(queryToken)) { + Vue.ls.set("token", store.state.user.token); + return next({ path: to.path, query: {} }); // 移除 URL 中的 token 参数 + } + + return handleLoginFailure(next); +} + +/** 通过临时 token 获取正式 token */ +async function fetchToken(tmpToken) { + const formData = new FormData(); + formData.append("tmp_token", tmpToken); + await store.dispatch("user/getToken", formData); + return Boolean(store.state.user.token); +} + +/** 处理没有 token 的情况 */ +function handleNoToken(next) { + showTokenError(); + next(false); +} + +/** 从 localStorage 恢复 token */ +function restoreToken(token) { + store.commit("user/changeToken", token); +} + +/** 生成并加载动态路由 */ +async function loadRoutes(isAdmin, next) { + try { + const routesResource = await store.dispatch("user/getRoutesResource"); + dynamicRoutes = generateIndexRouter(routesResource); + router.addRoutes(dynamicRoutes); + + if (isAdmin) { + router.addRoutes([systemSettings]); } - // 2.4 已有路由 - next() - // } + } catch (err) { + Vue.prototype.$error("请求用户资源失败"); + console.error(err); + next(false); + } +} +/** 处理登录失败情况 */ +function handleLoginFailure(next) { + return store.state.user.loginFailed ? next({ path: "/loginFailed" }) : showTokenError(next); +} - // if(!store.state.token){ - // // if(false){ - // const CURRENT_USER = localStorage.getItem('uid') || to.query["CURRENT-USER"]; - // // debugger - // store.commit('saveUid', CURRENT_USER); - // localStorage.setItem('uid', CURRENT_USER); - - // const token = localStorage.getItem('token'); - // if(token){ - // store.commit('changeToken', token); - // localStorage.removeItem('token'); - // next({ path: to.path }); - // }else{ - // const tmp_token = to.query.token; - // if (tmp_token) { - // let formData = new FormData(); - // formData.append("tmp_token", tmp_token); - // await store.dispatch('getToken', formData); - // if(store.state.token){ - // // localStorage.setItem('token',store.state.token); - // next({ path: to.path }); - // }else{ - // if(!Vue.prototype.$closeModalFun){ - // Vue.prototype.$closeModalFun = accessTokenError('获取token失败,请点击左边导航栏应用“资源管理”重试。'); - // } - // next(false); - // } - // }else{ - // if(!Vue.prototype.$closeModalFun){ - // Vue.prototype.$closeModalFun = accessTokenError('获取临时token失败,请点击左边导航栏应用“资源管理”重试。'); - // } - // next(false); - // } - // } - // }else{ - // if (dynamicRoutes.length === 0) { - // store - // .dispatch("user/getRoutesResource") - // .then((routesResource) => { - // dynamicRoutes = generateIndexRouter(routesResource); - // router.addRoutes(dynamicRoutes); - // if(store.state.isAdmin){ - // router.addRoutes([systemSettings]); - // } - // next({ path: to.path, query: to.query }); - // }) - // .catch((err) => { - // Vue.prototype.$error("请求用户资源失败"); - // console.log(err); - // next(false); - // }); - // } else { - // next(); - // } - // } -}) +/** 显示 token 相关的错误提示 */ +function showTokenError() { + if (!Vue.prototype.$closeModalFun) { + Vue.prototype.$closeModalFun = accessTokenError("获取 token 失败,请点击左边导航栏应用“资源管理”重试。"); + } +} export default router;