mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-24 07:49:47 +08:00
refactor(hooks): 状态管理模块拆分
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<n-config-provider :locale="zhCN" :date-locale="dateZhCN" :theme="theme" :theme-overrides="app.themeOverrids">
|
||||
<n-config-provider :locale="zhCN" :date-locale="dateZhCN" :theme="dark" :theme-overrides="theme.themeOverrids">
|
||||
<n-loading-bar-provider>
|
||||
<n-dialog-provider>
|
||||
<n-notification-provider>
|
||||
@ -26,9 +26,9 @@ import {
|
||||
NMessageProvider
|
||||
} from 'naive-ui';
|
||||
import { AppProviderContent } from '@/components';
|
||||
import { useAppStore } from '@/store';
|
||||
import { useThemeStore } from '@/store';
|
||||
|
||||
const app = useAppStore();
|
||||
const theme = computed(() => (app.themeSettings.darkMode ? darkTheme : undefined));
|
||||
const theme = useThemeStore();
|
||||
const dark = computed(() => (theme.darkMode ? darkTheme : undefined));
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
||||
@ -5,13 +5,14 @@
|
||||
<script lang="ts" setup>
|
||||
import { useLoadingBar, useDialog, useMessage, useNotification } from 'naive-ui';
|
||||
|
||||
function registerNaiveTool() {
|
||||
// 挂载naive组件的方法至window, 以便在路由钩子函数和请求函数里面调用
|
||||
function registerNaiveUiTools() {
|
||||
window.$loadingBar = useLoadingBar();
|
||||
window.$dialog = useDialog();
|
||||
window.$message = useMessage();
|
||||
window.$notification = useNotification();
|
||||
}
|
||||
|
||||
registerNaiveTool();
|
||||
registerNaiveUiTools();
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import AppProviderContent from './AppProviderContent/index.vue';
|
||||
import ColorBlock from './ColorBlock/index.vue';
|
||||
|
||||
export { AppProviderContent, ColorBlock };
|
||||
export { AppProviderContent };
|
||||
|
||||
@ -1 +1 @@
|
||||
export { AppProviderContent, ColorBlock } from './common';
|
||||
export { AppProviderContent } from './common';
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
export { UserInfo } from './business';
|
||||
export { ThemeSettings, NavMode } from './app';
|
||||
export { ThemeSettings, NavMode } from './theme';
|
||||
|
||||
@ -35,6 +35,7 @@ interface OtherColor {
|
||||
}
|
||||
|
||||
export type NavMode = keyof typeof EnumNavMode;
|
||||
|
||||
type NavTheme = keyof typeof EnumNavTheme;
|
||||
|
||||
interface NavStyle {
|
||||
@ -56,8 +57,6 @@ interface HeaderStyle {
|
||||
}
|
||||
|
||||
interface MenuStyle {
|
||||
/** 折叠菜单 */
|
||||
collapsed: boolean;
|
||||
/** 菜单宽度 */
|
||||
width: number;
|
||||
/** 菜单折叠时的宽度 */
|
||||
@ -10,7 +10,7 @@ import { computed } from 'vue';
|
||||
import { useAppStore } from '@/store';
|
||||
|
||||
const app = useAppStore();
|
||||
const showTitle = computed(() => !app.themeSettings.menuStyle.collapsed);
|
||||
const showTitle = computed(() => !app.menu.collapsed);
|
||||
const title = import.meta.env.VITE_APP_TITLE as string;
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<n-divider title-placement="center">深色主题</n-divider>
|
||||
<div class="flex-center">
|
||||
<n-switch :value="app.themeSettings.darkMode" @update:value="handleDarkMode">
|
||||
<n-switch :value="theme.darkMode" @update:value="handleDarkMode">
|
||||
<template #checked>
|
||||
<icon-mdi-white-balance-sunny class="text-14px text-primary" />
|
||||
</template>
|
||||
@ -14,10 +14,10 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { NDivider, NSwitch } from 'naive-ui';
|
||||
import { useAppStore } from '@/store';
|
||||
import { useThemeStore } from '@/store';
|
||||
|
||||
const app = useAppStore();
|
||||
const { handleDarkMode } = useAppStore();
|
||||
const theme = useThemeStore();
|
||||
const { handleDarkMode } = useThemeStore();
|
||||
</script>
|
||||
<style scoped>
|
||||
:deep(.n-switch__rail) {
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
v-for="item in modeList"
|
||||
:key="item.mode"
|
||||
:mode="item.mode"
|
||||
:checked="app.themeSettings.navStyle.mode === item.mode"
|
||||
:checked="theme.navStyle.mode === item.mode"
|
||||
@click="setNavMode(item.mode)"
|
||||
/>
|
||||
</n-space>
|
||||
@ -16,15 +16,15 @@ import { NDivider, NSpace } from 'naive-ui';
|
||||
import { EnumNavMode } from '@/enum';
|
||||
import type { NavMode } from '@/interface';
|
||||
import { NavType } from './components';
|
||||
import { useAppStore } from '@/store';
|
||||
import { useThemeStore } from '@/store';
|
||||
|
||||
interface ModeList {
|
||||
mode: NavMode;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const app = useAppStore();
|
||||
const { setNavMode } = useAppStore();
|
||||
const theme = useThemeStore();
|
||||
const { setNavMode } = useThemeStore();
|
||||
|
||||
const modeList: ModeList[] = [
|
||||
{ mode: 'vertical', label: EnumNavMode.vertical },
|
||||
|
||||
@ -3,20 +3,20 @@
|
||||
<n-space vertical size="large">
|
||||
<div class="flex-y-center justify-between">
|
||||
<span>分割菜单</span>
|
||||
<n-switch :value="app.themeSettings.menuStyle.splitMenu" @update:value="handleSplitMenu" />
|
||||
<n-switch :value="theme.menuStyle.splitMenu" @update:value="handleSplitMenu" />
|
||||
</div>
|
||||
<div class="flex-y-center justify-between">
|
||||
<span>固定头部</span>
|
||||
<n-switch :value="app.themeSettings.headerStyle.fixed" @update:value="handleFixedHeader" />
|
||||
<n-switch :value="theme.headerStyle.fixed" @update:value="handleFixedHeader" />
|
||||
</div>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { NDivider, NSpace, NSwitch } from 'naive-ui';
|
||||
import { useAppStore } from '@/store';
|
||||
import { useThemeStore } from '@/store';
|
||||
|
||||
const app = useAppStore();
|
||||
const { handleSplitMenu, handleFixedHeader } = useAppStore();
|
||||
const theme = useThemeStore();
|
||||
const { handleSplitMenu, handleFixedHeader } = useThemeStore();
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<n-divider title-placement="center">系统主题</n-divider>
|
||||
<n-grid :cols="8">
|
||||
<n-grid-item v-for="color in app.themeSettings.themeColorList" :key="color">
|
||||
<color-block :color="color" :checked="color === app.themeSettings.themeColor" @click="setThemeColor(color)" />
|
||||
<n-grid-item v-for="color in theme.themeColorList" :key="color">
|
||||
<color-block :color="color" :checked="color === theme.themeColor" @click="setThemeColor(color)" />
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { NDivider, NGrid, NGridItem } from 'naive-ui';
|
||||
import { useAppStore } from '@/store';
|
||||
import { ColorBlock } from '@/components';
|
||||
import { useThemeStore } from '@/store';
|
||||
import { ColorBlock } from '../common';
|
||||
|
||||
const app = useAppStore();
|
||||
const { setThemeColor } = useAppStore();
|
||||
const theme = useThemeStore();
|
||||
const { setThemeColor } = useThemeStore();
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
import ColorBlock from './ColorBlock.vue';
|
||||
|
||||
export { ColorBlock };
|
||||
@ -5,8 +5,8 @@
|
||||
:native-scrollbar="false"
|
||||
:inverted="inverted"
|
||||
collapse-mode="width"
|
||||
:collapsed="app.themeSettings.menuStyle.collapsed"
|
||||
:collapsed-width="app.themeSettings.menuStyle.collapsedWidth"
|
||||
:collapsed="app.menu.collapsed"
|
||||
:collapsed-width="theme.menuStyle.collapsedWidth"
|
||||
:width="menuWidth"
|
||||
@collapse="handleMenuCollapse(true)"
|
||||
@expand="handleMenuCollapse(false)"
|
||||
@ -30,27 +30,27 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { NLayout, NLayoutSider, NLayoutHeader, NLayoutContent, NLayoutFooter } from 'naive-ui';
|
||||
import { useAppStore } from '@/store';
|
||||
import { useThemeStore, useAppStore } from '@/store';
|
||||
import { GlobalHeader, GlobalLogo, GlobalMenu, SettingDrawer } from './components';
|
||||
|
||||
const theme = useThemeStore();
|
||||
const app = useAppStore();
|
||||
const { handleMenuCollapse } = useAppStore();
|
||||
|
||||
const position = computed(() => (app.themeSettings.headerStyle.fixed ? 'absolute' : 'static'));
|
||||
const position = computed(() => (theme.headerStyle.fixed ? 'absolute' : 'static'));
|
||||
const menuWidth = computed(() => {
|
||||
const { collapsed, collapsedWidth, width } = app.themeSettings.menuStyle;
|
||||
const { collapsed } = app.menu;
|
||||
const { collapsedWidth, width } = theme.menuStyle;
|
||||
return collapsed ? collapsedWidth : width;
|
||||
});
|
||||
const inverted = computed(() => {
|
||||
const { theme } = app.themeSettings.navStyle;
|
||||
return theme !== 'light';
|
||||
return theme.navStyle.theme !== 'light';
|
||||
});
|
||||
const headerInverted = computed(() => {
|
||||
const { theme } = app.themeSettings.navStyle;
|
||||
return theme !== 'dark' ? inverted.value : !inverted.value;
|
||||
return theme.navStyle.theme !== 'dark' ? inverted.value : !inverted.value;
|
||||
});
|
||||
const headerHeight = computed(() => {
|
||||
const { height } = app.themeSettings.headerStyle;
|
||||
const { height } = theme.headerStyle;
|
||||
return `${height}px`;
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -25,6 +25,7 @@ async function setupApp() {
|
||||
|
||||
app.mount('#app', true);
|
||||
|
||||
// 配置windicss暗黑主题
|
||||
setupWindicssDarkMode();
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { watch } from 'vue';
|
||||
import { useAppStore } from '@/store';
|
||||
import { useThemeStore } from '@/store';
|
||||
|
||||
export default function setupWindicssDarkMode() {
|
||||
const app = useAppStore();
|
||||
const theme = useThemeStore();
|
||||
|
||||
const DARK_CLASS = 'dark';
|
||||
|
||||
@ -19,7 +19,7 @@ export default function setupWindicssDarkMode() {
|
||||
}
|
||||
|
||||
watch(
|
||||
() => app.themeSettings.darkMode,
|
||||
() => theme.darkMode,
|
||||
newValue => {
|
||||
if (newValue) {
|
||||
addDarkClass();
|
||||
|
||||
@ -7,4 +7,4 @@ export function setupStore(app: App) {
|
||||
app.use(store);
|
||||
}
|
||||
|
||||
export { useAppStore, useAuthStore } from './modules';
|
||||
export { useThemeStore, useAppStore, useAuthStore } from './modules';
|
||||
|
||||
@ -1,77 +1,42 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import type { GlobalThemeOverrides } from 'naive-ui';
|
||||
import { themeSettings } from '@/settings';
|
||||
import { store } from '@/store';
|
||||
import type { ThemeSettings, NavMode } from '@/interface';
|
||||
import { getHoverAndPressedColor } from './helpers';
|
||||
|
||||
/** app状态 */
|
||||
interface AppState {
|
||||
/** 主题配置 */
|
||||
themeSettings: ThemeSettings;
|
||||
/** 主题配置抽屉 */
|
||||
menu: MenuState;
|
||||
settingDrawer: SettingDrawer;
|
||||
}
|
||||
|
||||
/** 菜单状态 */
|
||||
interface MenuState {
|
||||
/** 菜单折叠 */
|
||||
collapsed: boolean;
|
||||
}
|
||||
|
||||
/** 设置抽屉的状态 */
|
||||
interface SettingDrawer {
|
||||
/** 设置抽屉可见性 */
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
const appStore = defineStore({
|
||||
id: 'app-store',
|
||||
state: (): AppState => ({
|
||||
themeSettings,
|
||||
menu: {
|
||||
collapsed: false
|
||||
},
|
||||
settingDrawer: {
|
||||
visible: false
|
||||
}
|
||||
}),
|
||||
getters: {
|
||||
/** naive UI主题配置 */
|
||||
themeOverrids(): GlobalThemeOverrides {
|
||||
const {
|
||||
themeColor: primaryColor,
|
||||
otherColor: { info: infoColor, success: successColor, warning: warningColor, error: errorColor }
|
||||
} = this.themeSettings;
|
||||
|
||||
const { hover: primaryColorHover, pressed: primaryColorPressed } = getHoverAndPressedColor(primaryColor);
|
||||
const { hover: infoColorHover, pressed: infoColorPressed } = getHoverAndPressedColor(infoColor);
|
||||
const { hover: successColorHover, pressed: successColorPressed } = getHoverAndPressedColor(successColor);
|
||||
const { hover: warningColorHover, pressed: warningColorPressed } = getHoverAndPressedColor(warningColor);
|
||||
const { hover: errorColorHover, pressed: errorColorPressed } = getHoverAndPressedColor(errorColor);
|
||||
|
||||
const colorLoading = primaryColor;
|
||||
|
||||
return {
|
||||
common: {
|
||||
primaryColor,
|
||||
primaryColorHover,
|
||||
primaryColorPressed,
|
||||
infoColor,
|
||||
infoColorHover,
|
||||
infoColorPressed,
|
||||
successColor,
|
||||
successColorHover,
|
||||
successColorPressed,
|
||||
warningColor,
|
||||
warningColorHover,
|
||||
warningColorPressed,
|
||||
errorColor,
|
||||
errorColorHover,
|
||||
errorColorPressed
|
||||
},
|
||||
LoadingBar: {
|
||||
colorLoading
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
/** 折叠/展开菜单 */
|
||||
handleMenuCollapse(collapsed: boolean) {
|
||||
this.themeSettings.menuStyle.collapsed = collapsed;
|
||||
this.menu.collapsed = collapsed;
|
||||
},
|
||||
/** 切换折叠/展开菜单 */
|
||||
toggleMenu() {
|
||||
this.themeSettings.menuStyle.collapsed = !this.themeSettings.menuStyle.collapsed;
|
||||
this.menu.collapsed = !this.menu.collapsed;
|
||||
},
|
||||
/** 打开配置抽屉 */
|
||||
openSettingDrawer() {
|
||||
@ -80,26 +45,6 @@ const appStore = defineStore({
|
||||
/** 关闭配置抽屉 */
|
||||
closeSettingDrawer() {
|
||||
this.settingDrawer.visible = false;
|
||||
},
|
||||
/** 设置暗黑模式 */
|
||||
handleDarkMode(isDark: boolean) {
|
||||
this.themeSettings.darkMode = isDark;
|
||||
},
|
||||
/** 设置系统主题颜色 */
|
||||
setThemeColor(color: string) {
|
||||
this.themeSettings.themeColor = color;
|
||||
},
|
||||
/** 设置导航栏模式 */
|
||||
setNavMode(mode: NavMode) {
|
||||
this.themeSettings.navStyle.mode = mode;
|
||||
},
|
||||
/** 折叠菜单 */
|
||||
handleSplitMenu(isSplit: boolean) {
|
||||
this.themeSettings.menuStyle.splitMenu = isSplit;
|
||||
},
|
||||
/** 固定头部 */
|
||||
handleFixedHeader(isFixed: boolean) {
|
||||
this.themeSettings.headerStyle.fixed = isFixed;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import useThemeStore from './theme';
|
||||
import useAppStore from './app';
|
||||
import useAuthStore from './auth';
|
||||
|
||||
export { useAppStore, useAuthStore };
|
||||
export { useThemeStore, useAppStore, useAuthStore };
|
||||
|
||||
8
src/store/modules/theme/helpers.ts
Normal file
8
src/store/modules/theme/helpers.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { brightenColor, darkenColor } from '@/utils';
|
||||
|
||||
export function getHoverAndPressedColor(color: string) {
|
||||
return {
|
||||
hover: brightenColor(color),
|
||||
pressed: darkenColor(color)
|
||||
};
|
||||
}
|
||||
81
src/store/modules/theme/index.ts
Normal file
81
src/store/modules/theme/index.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import type { GlobalThemeOverrides } from 'naive-ui';
|
||||
import { themeSettings } from '@/settings';
|
||||
import { store } from '@/store';
|
||||
import type { ThemeSettings, NavMode } from '@/interface';
|
||||
import { getHoverAndPressedColor } from './helpers';
|
||||
|
||||
type ThemeState = ThemeSettings;
|
||||
|
||||
const themeStore = defineStore({
|
||||
id: 'theme-store',
|
||||
state: (): ThemeState => ({
|
||||
...themeSettings
|
||||
}),
|
||||
getters: {
|
||||
/** naive UI主题配置 */
|
||||
themeOverrids(): GlobalThemeOverrides {
|
||||
const {
|
||||
themeColor: primaryColor,
|
||||
otherColor: { info: infoColor, success: successColor, warning: warningColor, error: errorColor }
|
||||
} = this;
|
||||
|
||||
const { hover: primaryColorHover, pressed: primaryColorPressed } = getHoverAndPressedColor(primaryColor);
|
||||
const { hover: infoColorHover, pressed: infoColorPressed } = getHoverAndPressedColor(infoColor);
|
||||
const { hover: successColorHover, pressed: successColorPressed } = getHoverAndPressedColor(successColor);
|
||||
const { hover: warningColorHover, pressed: warningColorPressed } = getHoverAndPressedColor(warningColor);
|
||||
const { hover: errorColorHover, pressed: errorColorPressed } = getHoverAndPressedColor(errorColor);
|
||||
|
||||
const colorLoading = primaryColor;
|
||||
|
||||
return {
|
||||
common: {
|
||||
primaryColor,
|
||||
primaryColorHover,
|
||||
primaryColorPressed,
|
||||
infoColor,
|
||||
infoColorHover,
|
||||
infoColorPressed,
|
||||
successColor,
|
||||
successColorHover,
|
||||
successColorPressed,
|
||||
warningColor,
|
||||
warningColorHover,
|
||||
warningColorPressed,
|
||||
errorColor,
|
||||
errorColorHover,
|
||||
errorColorPressed
|
||||
},
|
||||
LoadingBar: {
|
||||
colorLoading
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
/** 设置暗黑模式 */
|
||||
handleDarkMode(isDark: boolean) {
|
||||
this.darkMode = isDark;
|
||||
},
|
||||
/** 设置系统主题颜色 */
|
||||
setThemeColor(color: string) {
|
||||
this.themeColor = color;
|
||||
},
|
||||
/** 设置导航栏模式 */
|
||||
setNavMode(mode: NavMode) {
|
||||
this.navStyle.mode = mode;
|
||||
},
|
||||
/** 折叠菜单 */
|
||||
handleSplitMenu(isSplit: boolean) {
|
||||
this.menuStyle.splitMenu = isSplit;
|
||||
},
|
||||
/** 固定头部 */
|
||||
handleFixedHeader(isFixed: boolean) {
|
||||
this.headerStyle.fixed = isFixed;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default function useThemeStore() {
|
||||
return themeStore(store);
|
||||
}
|
||||
Reference in New Issue
Block a user