feat: 升级前端框架,适配手机端

This commit is contained in:
xiaojunnuo
2025-03-06 21:11:07 +08:00
659 changed files with 37406 additions and 873 deletions
@@ -0,0 +1,35 @@
import type { ComponentRecordType, GenerateMenuAndRoutesOptions } from "/@/vben/types";
import { generateAccessible } from "/@/vben/access";
import { preferences } from "/@/vben/preferences";
import { BasicLayout, IFrameView } from "/@/vben/layouts";
const forbiddenComponent = () => import("#/views/_core/fallback/forbidden.vue");
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
const pageMap: ComponentRecordType = import.meta.glob("../views/**/*.vue");
const layoutMap: ComponentRecordType = {
BasicLayout,
IFrameView
} as any;
return await generateAccessible(preferences.app.accessMode, {
...options,
// fetchMenuListAsync: async () => {
// message.loading({
// content: `${$t("common.loadingMenu")}...`,
// duration: 1.5
// });
// return await getAllMenusApi();
// },
// 可以指定没有权限跳转403页面
forbiddenComponent,
// 如果 route.meta.menuVisibleWithForbidden = true
layoutMap,
pageMap
});
}
export { generateAccess };
@@ -0,0 +1,112 @@
import type { Router } from "vue-router";
import { DEFAULT_HOME_PATH, LOGIN_PATH } from "/@/vben/constants";
import { preferences } from "/@/vben/preferences";
import { useAccessStore } from "/@/vben/stores";
import { generateMenus, startProgress, stopProgress } from "/@/vben/utils";
import { frameworkRoutes } from "/@/router/resolve";
import { useSettingStore } from "/@/store/modules/settings";
/**
* 通用守卫配置
* @param router
*/
export function setupCommonGuard(router: Router) {
// 记录已经加载的页面
const loadedPaths = new Set<string>();
router.beforeEach(async (to) => {
const settingStore = useSettingStore();
await settingStore.initOnce();
to.meta.loaded = loadedPaths.has(to.path);
// 页面加载进度条
if (!to.meta.loaded && preferences.transition.progress) {
startProgress();
}
return true;
});
router.afterEach((to) => {
// 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行
loadedPaths.add(to.path);
// 关闭页面加载进度条
if (preferences.transition.progress) {
stopProgress();
}
});
}
/**
* 权限访问守卫配置
* @param router
*/
function setupAccessGuard(router: Router) {
router.beforeEach(async (to, from) => {
// 基本路由,这些路由不需要进入权限拦截
const needAuth = to.matched.some((r) => {
return r.meta?.auth || r.meta?.permission;
});
const accessStore = useAccessStore();
if (needAuth) {
if (!accessStore.accessToken) {
// 没有访问权限,跳转登录页面
if (to.fullPath !== LOGIN_PATH) {
return {
path: LOGIN_PATH,
// 如不需要,直接删除 query
query: to.fullPath === DEFAULT_HOME_PATH ? {} : { redirect: encodeURIComponent(to.fullPath) },
// 携带当前跳转的页面,登录后重新跳转该页面
replace: true
};
}
return true;
}
}
// 是否已经生成过动态路由
if (!accessStore.isAccessChecked) {
const accessibleMenus = await generateMenus(frameworkRoutes[0].children, router);
accessStore.setAccessRoutes(frameworkRoutes);
accessStore.setAccessMenus(accessibleMenus);
accessStore.setIsAccessChecked(true);
}
// 生成菜单和路由
// const { accessibleMenus, accessibleRoutes } = await generateAccess({
// roles: [],
// router,
// // 则会在菜单中显示,但是访问会被重定向到403
// routes: accessRoutes
// });
//
// // 保存菜单信息和路由信息
// accessStore.setAccessMenus(accessibleMenus);
// accessStore.setAccessRoutes(accessibleRoutes);
// const redirectPath = (from.query.redirect ?? (to.path === DEFAULT_HOME_PATH ? DEFAULT_HOME_PATH : to.fullPath)) as string;
//
// return {
// ...router.resolve(decodeURIComponent(redirectPath)),
// replace: true
// };
return true;
});
}
/**
* 项目守卫配置
* @param router
*/
function createRouterGuard(router: Router) {
/** 通用 */
setupCommonGuard(router);
/** 权限访问 */
setupAccessGuard(router);
}
export { createRouterGuard };
+61 -70
View File
@@ -1,82 +1,73 @@
import { createRouter, createWebHashHistory } from "vue-router";
// 进度条
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import { usePageStore } from "../store/modules/page";
import { site } from "../utils/util.site";
import { routes } from "./resolve";
import { useResourceStore } from "../store/modules/resource";
import { useUserStore } from "../store/modules/user";
import { useSettingStore } from "/@/store/modules/settings";
import { createRouterGuard } from "/@/router/guard";
const router = createRouter({
history: createWebHashHistory(),
routes
});
/**
* 路由拦截
*/
router.beforeEach(async (to, from, next) => {
// 进度条
NProgress.start();
const settingStore = useSettingStore();
await settingStore.initOnce();
const resourceStore = useResourceStore();
resourceStore.init();
// 修复三级以上路由页面无法缓存的问题
if (to.matched && to.matched.length > 2) {
to.matched.splice(1, to.matched.length - 2);
}
// 验证当前路由所有的匹配中是否需要有登录验证的
if (
to.matched.some((r) => {
return r.meta?.auth || r.meta?.permission;
})
) {
const userStore = useUserStore();
// 这里暂时将cookie里是否存有token作为验证是否登录的条件
// 请根据自身业务需要修改
const token = userStore.getToken;
if (token) {
next();
} else {
// 没有登录的时候跳转到登录界面
// 携带上登陆成功之后需要跳转的页面完整路径
resourceStore.clear();
next({
name: "login",
query: {
redirect: to.fullPath
}
});
// https://github.com/d2-projects/d2-admin/issues/138
NProgress.done();
}
} else {
// 不需要身份校验 直接通过
next();
}
});
router.afterEach((to: any) => {
// 进度条
NProgress.done();
// 多页控制 打开新的页面
const pageStore = usePageStore();
// for (const item of to.matched) {
// pageStore.keepAlivePush(item.name);
// }
pageStore.open(to);
// 更改标题
const settingStore = useSettingStore();
site.title(to.meta.title, settingStore.siteInfo.title);
//修改左侧边栏
const matched = to.matched;
if (matched.length > 0) {
const resourceStore = useResourceStore();
resourceStore.setCurrentTopMenuByCurrentRoute(matched);
}
});
createRouterGuard(router);
export default router;
//
// /**
// * 路由拦截
// */
// router.beforeEach(async (to, from, next) => {
// // 进度条
// NProgress.start();
// const settingStore = useSettingStore();
// await settingStore.initOnce();
// const resourceStore = useResourceStore();
// resourceStore.init();
// // 修复三级以上路由页面无法缓存的问题
// if (to.matched && to.matched.length > 2) {
// to.matched.splice(1, to.matched.length - 2);
// }
// // 验证当前路由所有的匹配中是否需要有登录验证的
// if (
// to.matched.some((r) => {
// return r.meta?.auth || r.meta?.permission;
// })
// ) {
// const userStore = useUserStore();
// // 这里暂时将cookie里是否存有token作为验证是否登录的条件
// // 请根据自身业务需要修改
// const token = userStore.getToken;
// if (token) {
// next();
// } else {
// // 没有登录的时候跳转到登录界面
// // 携带上登陆成功之后需要跳转的页面完整路径
// resourceStore.clear();
// next({
// name: "login",
// query: {
// redirect: to.fullPath
// }
// });
// // https://github.com/d2-projects/d2-admin/issues/138
// NProgress.done();
// }
// } else {
// // 不需要身份校验 直接通过
// next();
// }
// });
//
// router.afterEach((to: any) => {
// // 进度条
// NProgress.done();
// // 多页控制 打开新的页面
// const pageStore = usePageStore();
// // for (const item of to.matched) {
// // pageStore.keepAlivePush(item.name);
// // }
// pageStore.open(to);
// // 更改标题
// const settingStore = useSettingStore();
// site.title(to.meta.title, settingStore.siteInfo.title);
@@ -1,5 +1,5 @@
import LayoutPass from "/src/layout/layout-pass.vue";
import * as _ from "lodash-es";
import { cloneDeep } from "lodash-es";
import { outsideResource } from "./source/outside";
import { headerResource } from "./source/header";
import { frameworkResource } from "./source/framework";
@@ -19,7 +19,7 @@ function transformOneResource(resource: any, parent: any) {
if (meta.isMenu === false) {
menu = null;
} else {
menu = _.cloneDeep(resource);
menu = cloneDeep(resource);
delete menu.component;
if (menu.path?.startsWith("/")) {
menu.fullPath = menu.path;
@@ -28,11 +28,11 @@ function transformOneResource(resource: any, parent: any) {
}
}
let route;
if (meta.isRoute === false || resource.path == null || resource.path.startsWith("https://") || resource.path.startsWith("http://")) {
if (meta.isRoute === false || resource.path == null) {
//没有route
route = null;
} else {
route = _.cloneDeep(resource);
route = cloneDeep(resource);
if (route.component && typeof route.component === "string") {
const path = "/src/views" + route.component;
route.component = modules[path];
@@ -1,18 +1,24 @@
import LayoutFramework from "/src/layout/layout-framework.vue";
//import { crudResources } from "/@/router/source/modules/crud";
import { sysResources } from "/@/router/source/modules/sys";
import { certdResources } from "/@/router/source/modules/certd";
import LayoutBasic from "/@/layout/layout-basic.vue";
import type { RouteRecordRaw } from "vue-router";
import { mergeRouteModules } from "/@/vben/utils";
const dynamicRouteFiles = import.meta.glob("./modules/**/*.ts", {
eager: true
});
/** 动态路由 */
const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
export const frameworkResource = [
{
title: "框架",
name: "framework",
name: "root",
path: "/",
redirect: "/index",
component: LayoutFramework,
component: LayoutBasic,
meta: {
icon: "ion:accessibility",
auth: true
hideInBreadcrumb: true
},
children: [
{
@@ -23,12 +29,13 @@ export const frameworkResource = [
meta: {
fixedAside: true,
showOnHeader: false,
icon: "ion:home-outline"
icon: "ion:home-outline",
auth: true
}
},
//...crudResources,
...certdResources,
...sysResources
// @ts-ignore
...dynamicRoutes
]
}
];
@@ -0,0 +1,54 @@
import { IFrameView } from "/@/vben/layouts";
import { useSettingStore } from "/@/store/modules/settings";
export const aboutResource = [
{
title: "文档",
name: "about",
path: "/about",
redirect: "/about/doc",
meta: {
icon: "lucide:copyright",
order: 9999,
show: () => {
const settingStore = useSettingStore();
return !settingStore.isComm;
}
},
children: [
{
title: "文档",
name: "document",
path: "/about/doc",
component: IFrameView,
meta: {
icon: "lucide:book-open-text",
link: "https://certd.docmirror.cn",
title: "文档"
}
},
{
name: "Github",
path: "/about/github",
component: IFrameView,
meta: {
icon: "mdi:github",
link: "https://github.com/certd/certd",
title: "Github"
}
},
{
name: "Gitee",
path: "/about/gitee",
component: IFrameView,
meta: {
icon: "ion:logo-octocat",
link: "https://gitee.com/certd/certd",
title: "Gite"
}
}
]
}
];
export default aboutResource;
@@ -1,4 +1,5 @@
import { useSettingStore } from "/@/store/modules/settings";
import aboutResource from "/@/router/source/modules/about";
export const certdResources = [
{
@@ -8,7 +9,8 @@ export const certdResources = [
redirect: "/certd/pipeline",
meta: {
icon: "ion:key-outline",
auth: true
auth: true,
order: 0
},
children: [
{
@@ -220,3 +222,5 @@ export const certdResources = [
]
}
];
export default certdResources;
@@ -1,5 +1,6 @@
import LayoutPass from "/@/layout/layout-pass.vue";
import { useSettingStore } from "/@/store/modules/settings";
import aboutResource from "/@/router/source/modules/about";
export const sysResources = [
{
@@ -7,10 +8,10 @@ export const sysResources = [
name: "SysRoot",
path: "/sys",
redirect: "/sys/settings",
component: LayoutPass,
meta: {
icon: "ion:settings-outline",
permission: "sys:settings:view"
permission: "sys:settings:view",
order: 10
},
children: [
{
@@ -231,3 +232,5 @@ export const sysResources = [
]
}
];
export default sysResources;