mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-24 07:49:47 +08:00
refactor(projects): 精简版+动态路由权限初步
This commit is contained in:
@ -1,5 +0,0 @@
|
||||
export * from './route';
|
||||
export * from './router';
|
||||
export * from './system';
|
||||
export * from './layout';
|
||||
export * from './theme';
|
@ -1,82 +0,0 @@
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import type { ScrollbarInst } from 'naive-ui';
|
||||
import { useThemeStore, useAppStore } from '@/store';
|
||||
import { useRouteProps } from './route';
|
||||
|
||||
export function useLayoutConfig() {
|
||||
const theme = useThemeStore();
|
||||
const app = useAppStore();
|
||||
const { setScrollbarInstance } = useAppStore();
|
||||
const routeProps = useRouteProps();
|
||||
|
||||
/** 反转sider */
|
||||
const siderInverted = computed(() => theme.navStyle.theme !== 'light');
|
||||
|
||||
/** 侧边菜单宽度 */
|
||||
const siderMenuWidth = computed(() => {
|
||||
const { collapsed } = app.menu;
|
||||
const { collapsedWidth, width } = theme.menuStyle;
|
||||
return collapsed ? collapsedWidth : width;
|
||||
});
|
||||
|
||||
/** 反转header */
|
||||
const headerInverted = computed(() => (theme.navStyle.theme !== 'dark' ? siderInverted.value : !siderInverted.value));
|
||||
|
||||
/** 头部定位 */
|
||||
const headerPosition = computed(() => (theme.fixedHeaderAndTab ? 'absolute' : 'static'));
|
||||
|
||||
/** 全局头部的高度(px) */
|
||||
const headerHeight = computed(() => `${theme.headerStyle.height}px`);
|
||||
|
||||
/** 多页签Tab的高度(px) */
|
||||
const multiTabHeight = computed(() => `${theme.multiTabStyle.height}px`);
|
||||
|
||||
/** 全局头部和多页签的总高度 */
|
||||
const headerAndMultiTabHeight = computed(() => {
|
||||
const {
|
||||
multiTabStyle: { visible, height: tabHeight },
|
||||
headerStyle: { height: headerHeight }
|
||||
} = theme;
|
||||
const height = visible ? headerHeight + tabHeight : headerHeight;
|
||||
return `${height}px`;
|
||||
});
|
||||
|
||||
/** 全局侧边栏的样式 */
|
||||
const globalSiderClassAndStyle = {
|
||||
class: 'transition-all duration-300 ease-in-out',
|
||||
style: 'z-index:12;box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);'
|
||||
};
|
||||
|
||||
/** 纵向flex布局样式 */
|
||||
const flexColumnStyle = 'display:flex;flex-direction:column;height:100%;';
|
||||
|
||||
/** scrollbar的content的样式 */
|
||||
const scrollbarContentStyle = computed(() => {
|
||||
const { fullPage } = routeProps.value;
|
||||
const height = fullPage ? '100%' : 'auto';
|
||||
return `display:flex;flex-direction:column;height:${height};min-height:100%;`;
|
||||
});
|
||||
|
||||
/** 滚动条实例 */
|
||||
const scrollbar = ref<ScrollbarInst | null>(null);
|
||||
|
||||
watch(scrollbar, newValue => {
|
||||
if (newValue) {
|
||||
setScrollbarInstance(newValue);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
siderInverted,
|
||||
siderMenuWidth,
|
||||
headerInverted,
|
||||
headerPosition,
|
||||
headerHeight,
|
||||
multiTabHeight,
|
||||
headerAndMultiTabHeight,
|
||||
globalSiderClassAndStyle,
|
||||
flexColumnStyle,
|
||||
scrollbarContentStyle,
|
||||
scrollbar
|
||||
};
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
import { computed, watch } from 'vue';
|
||||
import type { WatchOptions } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { routeName } from '@/router';
|
||||
import type { RouteKey } from '@/interface';
|
||||
|
||||
/**
|
||||
* 路由属性
|
||||
*/
|
||||
export function useRouteProps() {
|
||||
const route = useRoute();
|
||||
const props = computed(() => {
|
||||
/** 路由名称 */
|
||||
const name = route.name as string;
|
||||
/** 缓存页面 */
|
||||
const keepAlive = Boolean(route.meta?.keepAlive);
|
||||
/** 视高100% */
|
||||
const fullPage = Boolean(route.meta?.fullPage);
|
||||
|
||||
return {
|
||||
name,
|
||||
keepAlive,
|
||||
fullPage
|
||||
};
|
||||
});
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由查询参数
|
||||
*/
|
||||
export function useRouteQuery() {
|
||||
const route = useRoute();
|
||||
|
||||
/** 登录跳转链接 */
|
||||
const loginRedirect = computed(() => {
|
||||
let url: string | undefined;
|
||||
if (route.name === routeName('login')) {
|
||||
url = (route.query?.redirect as string) || '';
|
||||
}
|
||||
return url;
|
||||
});
|
||||
|
||||
return {
|
||||
loginRedirect
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由名称变化后的回调
|
||||
* @param callback
|
||||
*/
|
||||
export function routeNameWatcher(callback: (name: RouteKey) => void, options?: WatchOptions) {
|
||||
const route = useRoute();
|
||||
watch(
|
||||
() => route.name,
|
||||
newValue => {
|
||||
callback(newValue as RouteKey);
|
||||
},
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由全路径变化后的回调
|
||||
* @param callback
|
||||
*/
|
||||
export function routeFullPathWatcher(callback: (fullPath: string) => void, options?: WatchOptions) {
|
||||
const route = useRoute();
|
||||
watch(
|
||||
() => route.fullPath,
|
||||
newValue => {
|
||||
callback(newValue);
|
||||
},
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由路径变化后的回调
|
||||
* @param callback - 回调函数
|
||||
* @param options - 监听配置
|
||||
*/
|
||||
export function routePathWatcher(callback: (path: string) => void, options?: WatchOptions) {
|
||||
const route = useRoute();
|
||||
watch(
|
||||
() => route.path,
|
||||
newValue => {
|
||||
callback(newValue);
|
||||
},
|
||||
options
|
||||
);
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
import { unref } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import type { RouteLocationRaw } from 'vue-router';
|
||||
import { router as globalRouter, routeName, ROUTE_HOME } from '@/router';
|
||||
import type { LoginModuleType } from '@/interface';
|
||||
|
||||
/**
|
||||
* 路由跳转
|
||||
* @param inSetup - 是否在vue页面/组件的setup里面调用
|
||||
*/
|
||||
export function useRouterPush(inSetup: boolean = true) {
|
||||
const router = inSetup ? useRouter() : globalRouter;
|
||||
const route = inSetup ? useRoute() : unref(globalRouter.currentRoute);
|
||||
|
||||
/**
|
||||
* 路由跳转
|
||||
* @param to - 路由
|
||||
* @param newTab - 在新的浏览器标签打开
|
||||
*/
|
||||
function routerPush(to: RouteLocationRaw, newTab = false) {
|
||||
if (newTab) {
|
||||
const routerData = router.resolve(to);
|
||||
window.open(routerData.href, '_blank');
|
||||
} else {
|
||||
router.push(to);
|
||||
}
|
||||
}
|
||||
|
||||
/** 返回上一级路由 */
|
||||
function routerBack() {
|
||||
router.go(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转首页
|
||||
* @param newTab - 在新的浏览器标签打开
|
||||
*/
|
||||
function toHome(newTab = false) {
|
||||
routerPush(ROUTE_HOME.path, newTab);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重定向地址
|
||||
* - current: 取当前的path作为重定向地址
|
||||
*/
|
||||
type LoginRedirect = 'current' | string;
|
||||
|
||||
/**
|
||||
* 跳转登录页面(通过vue路由)
|
||||
* @param module - 展示的登录模块
|
||||
* @param redirect - 重定向地址(登录成功后跳转的地址)
|
||||
* @param newTab - 在新的浏览器标签打开
|
||||
*/
|
||||
function toLogin(module: LoginModuleType = 'pwd-login', redirect: LoginRedirect = 'current', newTab = false) {
|
||||
const routeLocation: RouteLocationRaw = {
|
||||
name: routeName('login'),
|
||||
params: { module }
|
||||
};
|
||||
if (redirect) {
|
||||
let url = redirect;
|
||||
if (redirect === 'current') {
|
||||
url = route.fullPath;
|
||||
}
|
||||
Object.assign(routeLocation, { query: { redirect: url } });
|
||||
}
|
||||
routerPush(routeLocation, newTab);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登陆页跳转登陆页(登录模块切换)
|
||||
* @param module - 展示的登录模块
|
||||
* @param newTab - 在新的浏览器标签打开
|
||||
*/
|
||||
function toCurrentLogin(module: LoginModuleType, newTab = false) {
|
||||
const { query } = route;
|
||||
routerPush({ name: routeName('login'), params: { module }, query: { ...query } }, newTab);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录成功后跳转重定向的地址
|
||||
* @param redirect - 重定向地址
|
||||
*/
|
||||
function toLoginRedirect(redirect?: string) {
|
||||
if (redirect) {
|
||||
routerPush(redirect);
|
||||
} else {
|
||||
toHome();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
routerPush,
|
||||
routerBack,
|
||||
toHome,
|
||||
toLogin,
|
||||
toCurrentLogin,
|
||||
toLoginRedirect
|
||||
};
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
import { useBreakpoints, breakpointsTailwind } from '@vueuse/core';
|
||||
|
||||
interface AppInfo {
|
||||
/** 项目名称 */
|
||||
name: string;
|
||||
/** 项目标题 */
|
||||
title: string;
|
||||
/** 项目描述 */
|
||||
desc: string;
|
||||
}
|
||||
|
||||
/** 项目信息 */
|
||||
export function useAppInfo(): AppInfo {
|
||||
const { VITE_APP_NAME: name, VITE_APP_TITLE: title, VITE_APP_DESC: desc } = import.meta.env;
|
||||
|
||||
return {
|
||||
name,
|
||||
title,
|
||||
desc
|
||||
};
|
||||
}
|
||||
|
||||
/** 是否是移动端 */
|
||||
export function useIsMobile() {
|
||||
const breakpoints = useBreakpoints(breakpointsTailwind);
|
||||
const isMobile = breakpoints.smaller('lg');
|
||||
return isMobile;
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
import { computed, watch } from 'vue';
|
||||
import { darkTheme } from 'naive-ui';
|
||||
import { useDark } from '@vueuse/core';
|
||||
import { useThemeStore } from '@/store';
|
||||
|
||||
/** 系统暗黑模式 */
|
||||
export function useDarkMode() {
|
||||
const osDark = useDark();
|
||||
const theme = useThemeStore();
|
||||
const { handleDarkMode } = useThemeStore();
|
||||
|
||||
/** naive-ui暗黑主题 */
|
||||
const naiveTheme = computed(() => (theme.darkMode ? darkTheme : undefined));
|
||||
|
||||
// windicss 暗黑模式
|
||||
const DARK_CLASS = 'dark';
|
||||
function getHtmlElement() {
|
||||
return document.querySelector('html');
|
||||
}
|
||||
function addDarkClass() {
|
||||
const html = getHtmlElement();
|
||||
if (html) {
|
||||
html.classList.add(DARK_CLASS);
|
||||
}
|
||||
}
|
||||
function removeDarkClass() {
|
||||
const html = getHtmlElement();
|
||||
if (html) {
|
||||
html.classList.remove(DARK_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
// 监听操作系统主题模式
|
||||
watch(
|
||||
osDark,
|
||||
newValue => {
|
||||
handleDarkMode(newValue);
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
// 监听主题的暗黑模式
|
||||
watch(
|
||||
() => theme.darkMode,
|
||||
newValue => {
|
||||
if (newValue) {
|
||||
addDarkClass();
|
||||
} else {
|
||||
removeDarkClass();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
return {
|
||||
naiveTheme
|
||||
};
|
||||
}
|
||||
|
||||
/** 更改html样式 */
|
||||
export function useHtmlStyle() {
|
||||
const HIDE_SCROLL_CLASS = 'overflow-hidden';
|
||||
|
||||
function getHtmlElement() {
|
||||
return document.querySelector('html');
|
||||
}
|
||||
|
||||
function handleHideScroll() {
|
||||
const html = getHtmlElement();
|
||||
if (html) {
|
||||
html.classList.add(HIDE_SCROLL_CLASS);
|
||||
}
|
||||
}
|
||||
function handleAutoScroll() {
|
||||
const html = getHtmlElement();
|
||||
if (html) {
|
||||
html.classList.remove(HIDE_SCROLL_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
handleHideScroll,
|
||||
handleAutoScroll
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user