diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5463de4b..11a18ad5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,7 +16,7 @@
- 🎯 优化 去掉开发环境 i18n 控制台警告,页面代码:[i18n/index.ts](https://gitee.com/lyt-top/vue-next-admin/blob/master/src/i18n/index.ts)
- 🎯 优化 `NextLoading.start()` 方法,防止第一次进入界面时出现短暂空白
- 🎯 优化 地址栏有参数退出登录,再次登录不跳之前界面问题 `src/layout/navBars/breadcrumb/user.vue`
-- 🎯 优化 `SvgIcon` 组件,防止 `开启 Tagsview 图标` 时,`tagsView 右键菜单关闭` 报错问题
+- 🎯 优化 `SvgIcon` 组件,防止 `开启 Tagsview 图标` 时,`tagsView 右键菜单关闭` 报错问题,工作流不可连线问题
- 🎯 优化 [wangEditor](https://www.wangeditor.com/) 更新到 v5,[vue3 版本线上示例中 wangeditor 富文本编辑器 demo 实例,无法换行#I5565B](https://gitee.com/lyt-top/vue-next-admin/issues/I5565B),感谢@[jenchih](https://gitee.com/jenchih)
- 🎯 优化 [在关闭 tagview 时,高度刷新时会会变化,出现滚动条](https://gitee.com/lyt-top/vue-next-admin/issues/I55FHM),感谢[张松](https://gitee.com/zs310071113)
- 🎉 新增 [vuex](https://vuex.vuejs.org/) 替换成 [pinia](https://pinia.vuejs.org/getting-started.html)
@@ -31,6 +31,7 @@
- 🐞 修复 `开启 Tagsview 图标` 时,`tagsView 右键菜单关闭` 报错问题
- 🐞 修复 `router.push` 路径找不到时报错问题,`404、401 界面` 已移入到 `main` 主布局里(之前全屏)
- 🐞 修复 [全局修改组件大小失效了](https://gitee.com/lyt-top/vue-next-admin/issues/I551RP),感谢[lg_boy](https://gitee.com/lg_boy)
+- 🌈 重构 路由(`/src/router/index.ts`)解决 No match found for location with path "xxx"(前端控制,后端控制未解决) 问题
## 2.0.2
diff --git a/src/components/svgIcon/index.vue b/src/components/svgIcon/index.vue
index 430d2426..74b101a8 100644
--- a/src/components/svgIcon/index.vue
+++ b/src/components/svgIcon/index.vue
@@ -1,11 +1,9 @@
-
-
-
-
-
-
-
+
+
+
+
+
-
-
diff --git a/src/i18n/lang/en.ts b/src/i18n/lang/en.ts
index 6647f957..46ae8302 100644
--- a/src/i18n/lang/en.ts
+++ b/src/i18n/lang/en.ts
@@ -105,7 +105,6 @@ export default {
logOutConfirm: 'determine',
logOutCancel: 'cancel',
logOutExit: 'Exiting',
- logOutSuccess: 'Exit successfully!',
},
tagsView: {
refresh: 'refresh',
diff --git a/src/i18n/lang/zh-cn.ts b/src/i18n/lang/zh-cn.ts
index 38fc84a4..79ef328d 100644
--- a/src/i18n/lang/zh-cn.ts
+++ b/src/i18n/lang/zh-cn.ts
@@ -105,7 +105,6 @@ export default {
logOutConfirm: '确定',
logOutCancel: '取消',
logOutExit: '退出中',
- logOutSuccess: '安全退出成功!',
},
tagsView: {
refresh: '刷新',
diff --git a/src/i18n/lang/zh-tw.ts b/src/i18n/lang/zh-tw.ts
index 18edb1cd..d900abb5 100644
--- a/src/i18n/lang/zh-tw.ts
+++ b/src/i18n/lang/zh-tw.ts
@@ -105,7 +105,6 @@ export default {
logOutConfirm: '確定',
logOutCancel: '取消',
logOutExit: '退出中',
- logOutSuccess: '安全退出成功!',
},
tagsView: {
refresh: '重繪',
diff --git a/src/layout/navBars/breadcrumb/user.vue b/src/layout/navBars/breadcrumb/user.vue
index ac1fe5d2..b307311b 100644
--- a/src/layout/navBars/breadcrumb/user.vue
+++ b/src/layout/navBars/breadcrumb/user.vue
@@ -82,7 +82,6 @@ import { useRouter } from 'vue-router';
import { ElMessageBox, ElMessage } from 'element-plus';
import screenfull from 'screenfull';
import { useI18n } from 'vue-i18n';
-import { resetRoute } from '/@/router/index';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '/@/stores/userInfo';
import { useThemeConfig } from '/@/stores/themeConfig';
@@ -162,8 +161,7 @@ export default defineComponent({
})
.then(async () => {
Session.clear(); // 清除缓存/token等
- await resetRoute(); // 删除/重置路由
- ElMessage.success(t('message.user.logOutSuccess'));
+ // 使用 reload 时,不需要调用 resetRoute() 重置路由
window.location.reload();
})
.catch(() => {});
diff --git a/src/router/backEnd.ts b/src/router/backEnd.ts
index fcae0055..5355fb84 100644
--- a/src/router/backEnd.ts
+++ b/src/router/backEnd.ts
@@ -1,15 +1,23 @@
+import { RouteRecordRaw } from 'vue-router';
+import { storeToRefs } from 'pinia';
+import pinia from '/@/stores/index';
import { useUserInfo } from '/@/stores/userInfo';
import { useRequestOldRoutes } from '/@/stores/requestOldRoutes';
import { Session } from '/@/utils/storage';
import { NextLoading } from '/@/utils/loading';
-import { setAddRoute, setFilterMenuAndCacheTagsViewRoutes } from '/@/router/index';
-import { dynamicRoutes } from '/@/router/route';
+import { dynamicRoutes, notFoundAndNoPower } from '/@/router/route';
+import { formatTwoStageRoutes, formatFlatteningRoutes, router } from '/@/router/index';
+import { useRoutesList } from '/@/stores/routesList';
+import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { useMenuApi } from '/@/api/menu/index';
const menuApi = useMenuApi();
const layouModules: any = import.meta.glob('../layout/routerView/*.{vue,tsx}');
const viewsModules: any = import.meta.glob('../views/**/*.{vue,tsx}');
+
+// 后端控制路由
+
/**
* 获取目录下的 .vue、.tsx 全部文件
* @method import.meta.glob
@@ -21,7 +29,7 @@ const dynamicViewsModules: Record = Object.assign({}, { ...lay
* 后端控制路由:初始化方法,防止刷新时路由丢失
* @method NextLoading 界面 loading 动画开始执行
* @method useUserInfo().setUserInfos() 触发初始化用户信息 pinia
- * @method useRequestOldRoutes().setCacheKeepAlive() 存储接口原始路由(未处理component),根据需求选择使用
+ * @method useRequestOldRoutes().setRequestOldRoutes() 存储接口原始路由(未处理component),根据需求选择使用
* @method setAddRoute 添加动态路由
* @method setFilterMenuAndCacheTagsViewRoutes 设置递归过滤有权限的路由到 vuex routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
*/
@@ -36,13 +44,59 @@ export async function initBackEndControlRoutes() {
// 获取路由菜单数据
const res = await getBackEndControlRoutes();
// 存储接口原始路由(未处理component),根据需求选择使用
- useRequestOldRoutes().setCacheKeepAlive(JSON.parse(JSON.stringify(res.data)));
+ useRequestOldRoutes().setRequestOldRoutes(JSON.parse(JSON.stringify(res.data)));
// 处理路由(component),替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
dynamicRoutes[0].children = await backEndComponent(res.data);
// 添加动态路由
await setAddRoute();
- // 设置递归过滤有权限的路由到 vuex routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
- setFilterMenuAndCacheTagsViewRoutes();
+ // // 设置递归过滤有权限的路由到 vuex routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
+ await setFilterMenuAndCacheTagsViewRoutes();
+}
+
+/**
+ * 设置递归过滤有权限的路由到 vuex routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
+ * @description 用于左侧菜单、横向菜单的显示
+ * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
+ */
+export function setFilterMenuAndCacheTagsViewRoutes() {
+ const storesRoutesList = useRoutesList(pinia);
+ storesRoutesList.setRoutesList(dynamicRoutes[0].children as any);
+ setCacheTagsViewRoutes();
+}
+
+/**
+ * 缓存多级嵌套数组处理后的一维数组
+ * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
+ */
+export function setCacheTagsViewRoutes() {
+ // 获取有权限的路由,否则 tagsView、菜单搜索中无权限的路由也将显示
+ const storesTagsView = useTagsViewRoutes(pinia);
+ // 添加到 pinia setTagsViewRoutes 中
+ storesTagsView.setTagsViewRoutes(formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes))[0].children);
+}
+
+/**
+ * 获取有当前用户权限标识的路由数组,进行对原路由的替换
+ * @description 替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
+ * @returns 返回替换后的路由数组
+ */
+export function setFilterRouteEnd() {
+ // console.log(dynamicRoutes);
+ let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
+ filterRouteEnd[0].children = [...filterRouteEnd[0].children, ...notFoundAndNoPower];
+ return filterRouteEnd;
+}
+
+/**
+ * 添加动态路由
+ * @method router.addRoute
+ * @description 此处循环为 dynamicRoutes(/@/router/route)第一个顶级 children 的路由一维数组,非多级嵌套
+ * @link 参考:https://next.router.vuejs.org/zh/api/#addroute
+ */
+export async function setAddRoute() {
+ await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
+ router.addRoute(route);
+ });
}
/**
@@ -52,8 +106,9 @@ export async function initBackEndControlRoutes() {
*/
export function getBackEndControlRoutes() {
// 模拟 admin 与 test
- const stores = useUserInfo();
- const auth = stores.userInfos.roles[0];
+ const stores = useUserInfo(pinia);
+ const { userInfos } = storeToRefs(stores);
+ const auth = userInfos.value.roles[0];
// 管理员 admin
if (auth === 'admin') return menuApi.getMenuAdmin();
// 其它用户 test
diff --git a/src/router/frontEnd.ts b/src/router/frontEnd.ts
index 52941f53..8877514a 100644
--- a/src/router/frontEnd.ts
+++ b/src/router/frontEnd.ts
@@ -1,8 +1,15 @@
+import { RouteRecordRaw } from 'vue-router';
+import { storeToRefs } from 'pinia';
+import { formatTwoStageRoutes, formatFlatteningRoutes, router } from '/@/router/index';
+import { dynamicRoutes, notFoundAndNoPower } from '/@/router/route';
import pinia from '/@/stores/index';
-import { useUserInfo } from '/@/stores/userInfo';
import { Session } from '/@/utils/storage';
+import { useUserInfo } from '/@/stores/userInfo';
+import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
+import { useRoutesList } from '/@/stores/routesList';
import { NextLoading } from '/@/utils/loading';
-import { setAddRoute, setFilterMenuAndCacheTagsViewRoutes } from '/@/router/index';
+
+// 前端控制路由
/**
* 前端控制路由:初始化方法,防止刷新时路由丢失
@@ -23,3 +30,118 @@ export async function initFrontEndControlRoutes() {
// 设置递归过滤有权限的路由到 vuex routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
await setFilterMenuAndCacheTagsViewRoutes();
}
+
+/**
+ * 添加动态路由
+ * @method router.addRoute
+ * @description 此处循环为 dynamicRoutes(/@/router/route)第一个顶级 children 的路由一维数组,非多级嵌套
+ * @link 参考:https://next.router.vuejs.org/zh/api/#addroute
+ */
+export async function setAddRoute() {
+ await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
+ router.addRoute(route);
+ });
+}
+
+/**
+ * 删除/重置路由
+ * @method router.removeRoute
+ * @description 此处循环为 dynamicRoutes(/@/router/route)第一个顶级 children 的路由一维数组,非多级嵌套
+ * @link 参考:https://next.router.vuejs.org/zh/api/#push
+ */
+export async function frontEndsResetRoute() {
+ await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
+ const routeName: any = route.name;
+ router.hasRoute(routeName) && router.removeRoute(routeName);
+ });
+}
+
+/**
+ * 获取有当前用户权限标识的路由数组,进行对原路由的替换
+ * @description 替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
+ * @returns 返回替换后的路由数组
+ */
+export function setFilterRouteEnd() {
+ let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
+ filterRouteEnd[0].children = [...setFilterRoute(filterRouteEnd[0].children), ...notFoundAndNoPower];
+ return filterRouteEnd;
+}
+
+/**
+ * 获取当前用户权限标识去比对路由表(未处理成多级嵌套路由)
+ * @description 这里主要用于动态路由的添加,router.addRoute
+ * @link 参考:https://next.router.vuejs.org/zh/api/#addroute
+ * @param chil dynamicRoutes(/@/router/route)第一个顶级 children 的下路由集合
+ * @returns 返回有当前用户权限标识的路由数组
+ */
+export function setFilterRoute(chil: any) {
+ const stores = useUserInfo(pinia);
+ const { userInfos } = storeToRefs(stores);
+ let filterRoute: any = [];
+ chil.forEach((route: any) => {
+ if (route.meta.roles) {
+ route.meta.roles.forEach((metaRoles: any) => {
+ userInfos.value.roles.forEach((roles: any) => {
+ if (metaRoles === roles) filterRoute.push({ ...route });
+ });
+ });
+ }
+ });
+ return filterRoute;
+}
+
+/**
+ * 缓存多级嵌套数组处理后的一维数组
+ * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
+ */
+export function setCacheTagsViewRoutes() {
+ // 获取有权限的路由,否则 tagsView、菜单搜索中无权限的路由也将显示
+ const stores = useUserInfo(pinia);
+ const storesTagsView = useTagsViewRoutes(pinia);
+ const { userInfos } = storeToRefs(stores);
+ let rolesRoutes = setFilterHasRolesMenu(dynamicRoutes, userInfos.value.roles);
+ // 添加到 pinia setTagsViewRoutes 中
+ storesTagsView.setTagsViewRoutes(formatTwoStageRoutes(formatFlatteningRoutes(rolesRoutes))[0].children);
+}
+
+/**
+ * 设置递归过滤有权限的路由到 vuex routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
+ * @description 用于左侧菜单、横向菜单的显示
+ * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
+ */
+export function setFilterMenuAndCacheTagsViewRoutes() {
+ const stores = useUserInfo(pinia);
+ const storesRoutesList = useRoutesList(pinia);
+ const { userInfos } = storeToRefs(stores);
+ storesRoutesList.setRoutesList(setFilterHasRolesMenu(dynamicRoutes[0].children, userInfos.value.roles));
+ setCacheTagsViewRoutes();
+}
+
+/**
+ * 判断路由 `meta.roles` 中是否包含当前登录用户权限字段
+ * @param roles 用户权限标识,在 userInfos(用户信息)的 roles(登录页登录时缓存到浏览器)数组
+ * @param route 当前循环时的路由项
+ * @returns 返回对比后有权限的路由项
+ */
+export function hasRoles(roles: any, route: any) {
+ if (route.meta && route.meta.roles) return roles.some((role: any) => route.meta.roles.includes(role));
+ else return true;
+}
+
+/**
+ * 获取当前用户权限标识去比对路由表,设置递归过滤有权限的路由
+ * @param routes 当前路由 children
+ * @param roles 用户权限标识,在 userInfos(用户信息)的 roles(登录页登录时缓存到浏览器)数组
+ * @returns 返回有权限的路由数组 `meta.roles` 中控制
+ */
+export function setFilterHasRolesMenu(routes: any, roles: any) {
+ const menu: any = [];
+ routes.forEach((route: any) => {
+ const item = { ...route };
+ if (hasRoles(roles, item)) {
+ if (item.children) item.children = setFilterHasRolesMenu(item.children, roles);
+ menu.push(item);
+ }
+ });
+ return menu;
+}
diff --git a/src/router/index.ts b/src/router/index.ts
index e7ed858d..4a51bb61 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -1,53 +1,41 @@
-import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
+import { createRouter, createWebHashHistory } from 'vue-router';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import pinia from '/@/stores/index';
import { storeToRefs } from 'pinia';
-import { useUserInfo } from '/@/stores/userInfo';
import { useKeepALiveNames } from '/@/stores/keepAliveNames';
-import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { useRoutesList } from '/@/stores/routesList';
import { useThemeConfig } from '/@/stores/themeConfig';
import { Session } from '/@/utils/storage';
-import { staticRoutes, dynamicRoutes } from '/@/router/route';
+import { staticRoutes } from '/@/router/route';
import { initFrontEndControlRoutes } from '/@/router/frontEnd';
import { initBackEndControlRoutes } from '/@/router/backEnd';
+/**
+ * 1、前端控制路由时:isRequestRoutes 为 false,需要写 roles,需要走 setFilterRoute 方法。
+ * 2、后端控制路由时:isRequestRoutes 为 true,不需要写 roles,不需要走 setFilterRoute 方法),
+ * 相关方法已拆解到对应的 `backEnd.ts` 与 `frontEnd.ts`(他们互不影响,不需要同时改 2 个文件)。
+ * 特别说明:
+ * 1、前端控制:路由菜单由前端去写(无菜单管理界面,有角色管理界面),角色管理中有 roles 属性,需返回到 userInfo 中。
+ * 2、后端控制:路由菜单由后端返回(有菜单管理界面、有角色管理界面)
+ */
+
+// 读取 `/src/stores/themeConfig.ts` 是否开启后端控制路由配置
+const storesThemeConfig = useThemeConfig(pinia);
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const { isRequestRoutes } = themeConfig.value;
+if (isRequestRoutes) staticRoutes.splice(0, 1);
+
/**
* 创建一个可以被 Vue 应用程序使用的路由实例
* @method createRouter(options: RouterOptions): Router
* @link 参考:https://next.router.vuejs.org/zh/api/#createrouter
*/
-const router = createRouter({
+export const router = createRouter({
history: createWebHashHistory(),
routes: staticRoutes,
});
-/**
- * 定义404、401界面
- * @link 参考:https://next.router.vuejs.org/zh/guide/essentials/history-mode.html#netlify
- */
-const notFoundAndNoPower = [
- {
- path: '/:path(.*)*',
- name: 'notFound',
- component: () => import('/@/views/error/404.vue'),
- meta: {
- title: 'message.staticRoutes.notFound',
- isHide: true,
- },
- },
- {
- path: '/401',
- name: 'noPower',
- component: () => import('/@/views/error/401.vue'),
- meta: {
- title: 'message.staticRoutes.noPower',
- isHide: true,
- },
- },
-];
-
/**
* 路由多级嵌套数组处理成一维数组
* @param arr 传入路由菜单数据数组
@@ -97,127 +85,7 @@ export function formatTwoStageRoutes(arr: any) {
return newArr;
}
-/**
- * 缓存多级嵌套数组处理后的一维数组
- * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
- */
-export function setCacheTagsViewRoutes() {
- // 获取有权限的路由,否则 tagsView、菜单搜索中无权限的路由也将显示
- const stores = useUserInfo(pinia);
- const storesTagsView = useTagsViewRoutes(pinia);
- const { userInfos } = storeToRefs(stores);
- let rolesRoutes = setFilterHasRolesMenu(dynamicRoutes, userInfos.value.roles);
- // 添加到 pinia setTagsViewRoutes 中
- storesTagsView.setTagsViewRoutes(formatTwoStageRoutes(formatFlatteningRoutes(rolesRoutes))[0].children);
-}
-
-/**
- * 判断路由 `meta.roles` 中是否包含当前登录用户权限字段
- * @param roles 用户权限标识,在 userInfos(用户信息)的 roles(登录页登录时缓存到浏览器)数组
- * @param route 当前循环时的路由项
- * @returns 返回对比后有权限的路由项
- */
-export function hasRoles(roles: any, route: any) {
- if (route.meta && route.meta.roles) return roles.some((role: any) => route.meta.roles.includes(role));
- else return true;
-}
-
-/**
- * 获取当前用户权限标识去比对路由表,设置递归过滤有权限的路由
- * @param routes 当前路由 children
- * @param roles 用户权限标识,在 userInfos(用户信息)的 roles(登录页登录时缓存到浏览器)数组
- * @returns 返回有权限的路由数组 `meta.roles` 中控制
- */
-export function setFilterHasRolesMenu(routes: any, roles: any) {
- const menu: any = [];
- routes.forEach((route: any) => {
- const item = { ...route };
- if (hasRoles(roles, item)) {
- if (item.children) item.children = setFilterHasRolesMenu(item.children, roles);
- menu.push(item);
- }
- });
- return menu;
-}
-
-/**
- * 设置递归过滤有权限的路由到 vuex routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
- * @description 用于左侧菜单、横向菜单的显示
- * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
- */
-export function setFilterMenuAndCacheTagsViewRoutes() {
- const stores = useUserInfo(pinia);
- const storesRoutesList = useRoutesList(pinia);
- const { userInfos } = storeToRefs(stores);
- storesRoutesList.setRoutesList(setFilterHasRolesMenu(dynamicRoutes[0].children, userInfos.value.roles));
- setCacheTagsViewRoutes();
-}
-
-/**
- * 获取当前用户权限标识去比对路由表(未处理成多级嵌套路由)
- * @description 这里主要用于动态路由的添加,router.addRoute
- * @link 参考:https://next.router.vuejs.org/zh/api/#addroute
- * @param chil dynamicRoutes(/@/router/route)第一个顶级 children 的下路由集合
- * @returns 返回有当前用户权限标识的路由数组
- */
-export function setFilterRoute(chil: any) {
- const stores = useUserInfo(pinia);
- const { userInfos } = storeToRefs(stores);
- let filterRoute: any = [];
- chil.forEach((route: any) => {
- if (route.meta.roles) {
- route.meta.roles.forEach((metaRoles: any) => {
- userInfos.value.roles.forEach((roles: any) => {
- if (metaRoles === roles) filterRoute.push({ ...route });
- });
- });
- }
- });
- return filterRoute;
-}
-
-/**
- * 获取有当前用户权限标识的路由数组,进行对原路由的替换
- * @description 替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
- * @returns 返回替换后的路由数组
- */
-export function setFilterRouteEnd() {
- let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
- filterRouteEnd[0].children = [...setFilterRoute(filterRouteEnd[0].children), ...notFoundAndNoPower];
- return filterRouteEnd;
-}
-
-/**
- * 添加动态路由
- * @method router.addRoute
- * @description 此处循环为 dynamicRoutes(/@/router/route)第一个顶级 children 的路由一维数组,非多级嵌套
- * @link 参考:https://next.router.vuejs.org/zh/api/#addroute
- */
-export async function setAddRoute() {
- await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
- const routeName: any = route.name;
- if (!router.hasRoute(routeName)) router.addRoute(route);
- });
-}
-
-/**
- * 删除/重置路由
- * @method router.removeRoute
- * @description 此处循环为 dynamicRoutes(/@/router/route)第一个顶级 children 的路由一维数组,非多级嵌套
- * @link 参考:https://next.router.vuejs.org/zh/api/#push
- */
-export async function resetRoute() {
- await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
- const routeName: any = route.name;
- router.hasRoute(routeName) && router.removeRoute(routeName);
- });
-}
-
// isRequestRoutes 为 true,则开启后端控制路由,路径:`/src/stores/themeConfig.ts`
-const storesThemeConfig = useThemeConfig(pinia);
-const { themeConfig } = storeToRefs(storesThemeConfig);
-const { isRequestRoutes } = themeConfig.value;
-// 前端控制路由:初始化方法,防止刷新时路由丢失
if (!isRequestRoutes) initFrontEndControlRoutes();
// 路由加载前
@@ -232,7 +100,6 @@ router.beforeEach(async (to, from, next) => {
if (!token) {
next(`/login?redirect=${to.path}¶ms=${JSON.stringify(to.query ? to.query : to.params)}`);
Session.clear();
- resetRoute();
NProgress.done();
} else if (token && to.path === '/login') {
next('/home');
diff --git a/src/router/route.ts b/src/router/route.ts
index 6aaefa1f..1d3c8d3a 100644
--- a/src/router/route.ts
+++ b/src/router/route.ts
@@ -16,6 +16,7 @@ import { RouteRecordRaw } from 'vue-router';
/**
* 定义动态路由
+ * 前端添加路由,请在顶级节点的 `children 数组` 里添加
* @description 未开启 isRequestRoutes 为 true 时使用(前端控制路由),开启时第一个顶级 children 的路由将被替换成接口请求回来的路由数据
* @description 各字段请查看 `/@/views/system/menu/component/addMenu.vue 下的 ruleForm`
* @returns 返回路由菜单数据
@@ -1132,11 +1133,49 @@ export const dynamicRoutes: Array = [
];
/**
- * 定义静态路由
+ * 定义404、401界面
+ * @link 参考:https://next.router.vuejs.org/zh/guide/essentials/history-mode.html#netlify
+ */
+export const notFoundAndNoPower = [
+ {
+ path: '/:path(.*)*',
+ name: 'notFound',
+ component: () => import('/@/views/error/404.vue'),
+ meta: {
+ title: 'message.staticRoutes.notFound',
+ isHide: true,
+ },
+ },
+ {
+ path: '/401',
+ name: 'noPower',
+ component: () => import('/@/views/error/401.vue'),
+ meta: {
+ title: 'message.staticRoutes.noPower',
+ isHide: true,
+ },
+ },
+];
+
+/**
+ * 定义静态路由(默认路由)
+ * 此路由不要动,前端添加路由的话,请在 `dynamicRoutes 数组` 中添加
* @description 前端控制直接改 dynamicRoutes 中的路由,后端控制不需要修改,请求接口路由数据时,会覆盖 dynamicRoutes 第一个顶级 children 的内容(全屏,不包含 layout 中的路由出口)
* @returns 返回路由菜单数据
*/
export const staticRoutes: Array = [
+ {
+ path: '/',
+ name: '/',
+ component: () => import('/@/layout/index.vue'),
+ meta: {
+ title: '布局界面',
+ },
+ children: [
+ // 请不要往这里 `children` 中添加内容,此内容为了防止 No match found for location with path "xxx" 问题
+ ...notFoundAndNoPower,
+ ],
+ },
{
path: '/login',
name: 'login',
diff --git a/src/stores/requestOldRoutes.ts b/src/stores/requestOldRoutes.ts
index 31eb3d1b..be9b5cd4 100644
--- a/src/stores/requestOldRoutes.ts
+++ b/src/stores/requestOldRoutes.ts
@@ -10,7 +10,7 @@ export const useRequestOldRoutes = defineStore('requestOldRoutes', {
requestOldRoutes: [],
}),
actions: {
- async setCacheKeepAlive(routes: Array) {
+ async setRequestOldRoutes(routes: Array) {
this.requestOldRoutes = routes;
},
},
diff --git a/src/theme/media/error.scss b/src/theme/media/error.scss
index 727b7c41..f35015fd 100644
--- a/src/theme/media/error.scss
+++ b/src/theme/media/error.scss
@@ -33,3 +33,13 @@
}
}
}
+
+/* 页面宽度小于1200px
+------------------------------- */
+@media screen and (max-width: $lg) {
+ .error {
+ .error-flex {
+ padding: 0 30px;
+ }
+ }
+}
diff --git a/src/theme/mixins/index.scss b/src/theme/mixins/index.scss
index 31667af2..61f3c6bd 100644
--- a/src/theme/mixins/index.scss
+++ b/src/theme/mixins/index.scss
@@ -7,6 +7,7 @@
margin-right: 5px;
width: 24px;
text-align: center;
+ justify-content: center;
}
/* 文本不换行
diff --git a/src/views/limits/frontEnd/page/index.vue b/src/views/limits/frontEnd/page/index.vue
index c61c8f4d..c77c4ded 100644
--- a/src/views/limits/frontEnd/page/index.vue
+++ b/src/views/limits/frontEnd/page/index.vue
@@ -26,7 +26,7 @@
import { toRefs, reactive, onMounted, defineComponent } from 'vue';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '/@/stores/userInfo';
-import { resetRoute, setAddRoute, setFilterMenuAndCacheTagsViewRoutes } from '/@/router/index';
+import { frontEndsResetRoute, setAddRoute, setFilterMenuAndCacheTagsViewRoutes } from '/@/router/frontEnd';
import { Session } from '/@/utils/storage';
export default defineComponent({
@@ -45,7 +45,7 @@ export default defineComponent({
// 用户权限改变时
const onRadioChange = async () => {
// 模拟数据
- resetRoute();
+ frontEndsResetRoute();
let defaultRoles: string[] = [];
let defaultAuthBtnList: string[] = [];
// admin 页面权限标识,对应路由 meta.roles,用于控制路由的显示/隐藏
diff --git a/src/views/visualizing/demo1.vue b/src/views/visualizing/demo1.vue
index 871b7b10..8e6a00e4 100644
--- a/src/views/visualizing/demo1.vue
+++ b/src/views/visualizing/demo1.vue
@@ -93,6 +93,7 @@ import { toRefs, reactive, onMounted, onUnmounted, getCurrentInstance, defineCom
import * as echarts from 'echarts';
import 'echarts/extension/bmap/bmap';
import { formatDate } from '/@/utils/formatTime';
+import { NextLoading } from '/@/utils/loading';
import { echartsMapList, echartsMapData, echartsMapImgs } from './mock/demo1';
// 定义接口来定义对象的类型
@@ -934,6 +935,7 @@ export default defineComponent({
};
// 页面加载时
onMounted(async () => {
+ NextLoading.done();
initTime();
await initEchartsMap();
await initVisualizingContentLeftTop();
diff --git a/src/views/visualizing/demo2.vue b/src/views/visualizing/demo2.vue
index 284064b6..89eb40c7 100644
--- a/src/views/visualizing/demo2.vue
+++ b/src/views/visualizing/demo2.vue
@@ -233,6 +233,7 @@ import { toRefs, reactive, onMounted, onUnmounted, getCurrentInstance, defineCom
import * as echarts from 'echarts';
import 'echarts-gl';
import { formatDate } from '/@/utils/formatTime';
+import { NextLoading } from '/@/utils/loading';
import { dropdownList, skyList, dBtnList, earth3DBtnList, chartData4List } from './mock/demo2';
import worldImg from './images/world.jpg';
import bathymetryImg from './images/bathymetry.jpg';
@@ -765,6 +766,7 @@ export default defineComponent({
};
// 页面加载时
onMounted(async () => {
+ NextLoading.done();
initTime();
await initRightChartData1();
await initRightChartData4();