diff --git a/src/layout/components/navbar.vue b/src/layout/components/navbar.vue index 40912354c..9d705c7d6 100644 --- a/src/layout/components/navbar.vue +++ b/src/layout/components/navbar.vue @@ -1,52 +1,26 @@ diff --git a/src/layout/components/setting/index.vue b/src/layout/components/setting/index.vue index 74ba8c264..65a1e9e0c 100644 --- a/src/layout/components/setting/index.vue +++ b/src/layout/components/setting/index.vue @@ -6,33 +6,25 @@ import { reactive, computed, nextTick, - useCssModule, - getCurrentInstance + useCssModule } from "vue"; -import { find } from "lodash-unified"; import { getConfig } from "/@/config"; import { useRouter } from "vue-router"; import panel from "../panel/index.vue"; import { emitter } from "/@/utils/mitt"; import { templateRef } from "@vueuse/core"; -import { TinyColor } from "@ctrl/tinycolor"; -import { themeColorsType } from "../../types"; import { routerArrays } from "/@/layout/types"; -import type { StorageConfigs } from "/#/index"; import { useAppStoreHook } from "/@/store/modules/app"; import { useEpThemeStoreHook } from "/@/store/modules/epTheme"; import { useMultiTagsStoreHook } from "/@/store/modules/multiTags"; +import useDataThemeChange from "/@/layout/hooks/useDataThemeChange"; import { useDark, debounce, storageLocal, storageSession } from "@pureadmin/utils"; -import { - darken, - lighten, - toggleTheme -} from "@pureadmin/theme/dist/browser-utils"; +import { toggleTheme } from "@pureadmin/theme/dist/browser-utils"; import dayIcon from "/@/assets/svg/day.svg?component"; import darkIcon from "/@/assets/svg/dark.svg?component"; @@ -40,44 +32,20 @@ import darkIcon from "/@/assets/svg/dark.svg?component"; const router = useRouter(); const { isDark } = useDark(); const { isSelect } = useCssModule(); -const body = document.documentElement as HTMLElement; -const instance = - getCurrentInstance().appContext.app.config.globalProperties.$storage; - -const instanceConfig = - getCurrentInstance().appContext.app.config.globalProperties.$config; - -let themeColors = ref>([ - /* 道奇蓝(默认) */ - { color: "#1b2a47", themeColor: "default" }, - /* 亮白色 */ - { color: "#ffffff", themeColor: "light" }, - /* 猩红色 */ - { color: "#f5222d", themeColor: "dusk" }, - /* 橙红色 */ - { color: "#fa541c", themeColor: "volcano" }, - /* 金色 */ - { color: "#fadb14", themeColor: "yellow" }, - /* 绿宝石 */ - { color: "#13c2c2", themeColor: "mingQing" }, - /* 酸橙绿 */ - { color: "#52c41a", themeColor: "auroraGreen" }, - /* 深粉色 */ - { color: "#eb2f96", themeColor: "pink" }, - /* 深紫罗兰色 */ - { color: "#722ed1", themeColor: "saucePurple" } -]); const mixRef = templateRef("mixRef", null); const verticalRef = templateRef("verticalRef", null); const horizontalRef = templateRef("horizontalRef", null); -let layoutTheme = - ref(storageLocal.getItem("responsive-layout")) || - ref({ - layout: instanceConfig?.Layout ?? "vertical", - theme: instanceConfig?.Theme ?? "default" - }); +const { + body, + instance, + dataTheme, + layoutTheme, + themeColors, + dataThemeChange, + setLayoutThemeColor +} = useDataThemeChange(); /* body添加layout属性,作用于src/style/sidebar.scss */ if (unref(layoutTheme)) { @@ -245,75 +213,6 @@ function setLayoutModel(layout: string) { useAppStoreHook().setLayout(layout); } -/** 设置导航主题色 */ -function setLayoutThemeColor(theme: string) { - layoutTheme.value.theme = theme; - toggleTheme({ - scopeName: `layout-theme-${theme}` - }); - instance.layout = { - layout: useAppStoreHook().layout, - theme, - darkMode: dataTheme.value, - sidebarStatus: instance.layout.sidebarStatus, - epThemeColor: instance.layout.epThemeColor - }; - - if (theme === "default" || theme === "light") { - setEpThemeColor(getConfig().EpThemeColor); - } else { - const colors = find(themeColors.value, { themeColor: theme }); - setEpThemeColor(colors.color); - } -} - -/** - * @description 自动计算hover和active颜色 - * @see {@link https://element-plus.org/zh-CN/component/button.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A2%9C%E8%89%B2} - */ -const shadeBgColor = (color: string): string => { - return new TinyColor(color).shade(10).toString(); -}; - -/** 设置ep主题色 */ -const setEpThemeColor = (color: string) => { - useEpThemeStoreHook().setEpThemeColor(color); - body.style.setProperty("--el-color-primary-active", shadeBgColor(color)); - document.documentElement.style.setProperty("--el-color-primary", color); - for (let i = 1; i <= 9; i++) { - document.documentElement.style.setProperty( - `--el-color-primary-light-${i}`, - lighten(color, i / 10) - ); - } - for (let i = 1; i <= 2; i++) { - document.documentElement.style.setProperty( - `--el-color-primary-dark-${i}`, - darken(color, i / 10) - ); - } -}; - -let dataTheme = ref(instance.layout.darkMode); - -/** 日间、夜间主题切换 */ -function dataThemeChange() { - /* 如果当前是light夜间主题,默认切换到default主题 */ - if (useEpThemeStoreHook().epTheme === "light" && dataTheme.value) { - setLayoutThemeColor("default"); - } else { - setLayoutThemeColor(useEpThemeStoreHook().epTheme); - } - - if (dataTheme.value) { - instance.layout.darkMode = true; - document.documentElement.classList.add("dark"); - } else { - instance.layout.darkMode = false; - document.documentElement.classList.remove("dark"); - } -} - /* 初始化项目配置 */ nextTick(() => { settings.greyVal && diff --git a/src/layout/hooks/useDataThemeChange.ts b/src/layout/hooks/useDataThemeChange.ts new file mode 100644 index 000000000..cbae683f1 --- /dev/null +++ b/src/layout/hooks/useDataThemeChange.ts @@ -0,0 +1,120 @@ +import { getConfig } from "/@/config"; +import { find } from "lodash-unified"; +import useLayout from "./useLayout"; +import { themeColorsType } from "../types"; +import { TinyColor } from "@ctrl/tinycolor"; +import { ref, getCurrentInstance } from "vue"; +import { useAppStoreHook } from "/@/store/modules/app"; +import { useEpThemeStoreHook } from "/@/store/modules/epTheme"; +import { + darken, + lighten, + toggleTheme +} from "@pureadmin/theme/dist/browser-utils"; + +export default function useDataThemeChange() { + const { layoutTheme } = useLayout(); + const themeColors = ref>([ + /* 道奇蓝(默认) */ + { color: "#1b2a47", themeColor: "default" }, + /* 亮白色 */ + { color: "#ffffff", themeColor: "light" }, + /* 猩红色 */ + { color: "#f5222d", themeColor: "dusk" }, + /* 橙红色 */ + { color: "#fa541c", themeColor: "volcano" }, + /* 金色 */ + { color: "#fadb14", themeColor: "yellow" }, + /* 绿宝石 */ + { color: "#13c2c2", themeColor: "mingQing" }, + /* 酸橙绿 */ + { color: "#52c41a", themeColor: "auroraGreen" }, + /* 深粉色 */ + { color: "#eb2f96", themeColor: "pink" }, + /* 深紫罗兰色 */ + { color: "#722ed1", themeColor: "saucePurple" } + ]); + + const body = document.documentElement as HTMLElement; + const instance = + getCurrentInstance().appContext.app.config.globalProperties.$storage; + + /** 设置导航主题色 */ + function setLayoutThemeColor(theme = "default") { + layoutTheme.value.theme = theme; + toggleTheme({ + scopeName: `layout-theme-${theme}` + }); + instance.layout = { + layout: useAppStoreHook().layout, + theme, + darkMode: dataTheme.value, + sidebarStatus: instance.layout.sidebarStatus, + epThemeColor: instance.layout.epThemeColor + }; + + if (theme === "default" || theme === "light") { + setEpThemeColor(getConfig().EpThemeColor); + } else { + const colors = find(themeColors.value, { themeColor: theme }); + setEpThemeColor(colors.color); + } + } + + /** + * @description 自动计算hover和active颜色 + * @see {@link https://element-plus.org/zh-CN/component/button.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A2%9C%E8%89%B2} + */ + const shadeBgColor = (color: string): string => { + return new TinyColor(color).shade(10).toString(); + }; + + /** 设置ep主题色 */ + const setEpThemeColor = (color: string) => { + useEpThemeStoreHook().setEpThemeColor(color); + body.style.setProperty("--el-color-primary-active", shadeBgColor(color)); + document.documentElement.style.setProperty("--el-color-primary", color); + for (let i = 1; i <= 9; i++) { + document.documentElement.style.setProperty( + `--el-color-primary-light-${i}`, + lighten(color, i / 10) + ); + } + for (let i = 1; i <= 2; i++) { + document.documentElement.style.setProperty( + `--el-color-primary-dark-${i}`, + darken(color, i / 10) + ); + } + }; + const dataTheme = ref(instance?.layout?.darkMode); + + /** 日间、夜间主题切换 */ + function dataThemeChange() { + /* 如果当前是light夜间主题,默认切换到default主题 */ + if (useEpThemeStoreHook().epTheme === "light" && dataTheme.value) { + setLayoutThemeColor("default"); + } else { + setLayoutThemeColor(useEpThemeStoreHook().epTheme); + } + + if (dataTheme.value) { + instance.layout.darkMode = true; + document.documentElement.classList.add("dark"); + } else { + instance.layout.darkMode = false; + document.documentElement.classList.remove("dark"); + } + } + + return { + body, + instance, + dataTheme, + layoutTheme, + themeColors, + dataThemeChange, + setEpThemeColor, + setLayoutThemeColor + }; +} diff --git a/src/layout/hooks/useLayout.ts b/src/layout/hooks/useLayout.ts new file mode 100644 index 000000000..28795a16a --- /dev/null +++ b/src/layout/hooks/useLayout.ts @@ -0,0 +1,61 @@ +import { computed, getCurrentInstance } from "vue"; +import { useI18n } from "vue-i18n"; +import { routerArrays } from "../types"; +import { useMultiTagsStore } from "/@/store/modules/multiTags"; + +export default function useLayout() { + const instance = getCurrentInstance().appContext.app.config.globalProperties; + + const initStorage = () => { + // 路由 + if ( + useMultiTagsStore().multiTagsCache && + (!instance.$storage.tags || instance.$storage.tags.length === 0) + ) { + // eslint-disable-next-line vue/no-side-effects-in-computed-properties + instance.$storage.tags = routerArrays; + } + // 国际化 + if (!instance.$storage.locale) { + // eslint-disable-next-line + instance.$storage.locale = { locale: instance.$config?.Locale ?? "zh" }; + useI18n().locale.value = instance.$config?.Locale ?? "zh"; + } + // 导航 + if (!instance.$storage.layout) { + // eslint-disable-next-line vue/no-side-effects-in-computed-properties + instance.$storage.layout = { + layout: instance.$config?.Layout ?? "vertical", + theme: instance.$config?.Theme ?? "default", + darkMode: instance.$config?.DarkMode ?? false, + sidebarStatus: instance.$config?.SidebarStatus ?? true, + epThemeColor: instance.$config?.EpThemeColor ?? "#409EFF" + }; + } + // 灰色模式、色弱模式、隐藏标签页 + if (!instance.$storage.configure) { + // eslint-disable-next-line + instance.$storage.configure = { + grey: instance.$config?.Grey ?? false, + weak: instance.$config?.Weak ?? false, + hideTabs: instance.$config?.HideTabs ?? false, + showLogo: instance.$config?.ShowLogo ?? true, + showModel: instance.$config?.ShowModel ?? "smart", + multiTagsCache: instance.$config?.MultiTagsCache ?? false + }; + } + }; + // 清空缓存后从serverConfig.json读取默认配置并赋值到storage中 + const layout = computed(() => { + return instance.$storage?.layout.layout; + }); + const layoutTheme = computed(() => { + return instance.$storage.layout; + }); + return { + layout, + instance, + layoutTheme, + initStorage + }; +} diff --git a/src/layout/hooks/useTranslationLang.ts b/src/layout/hooks/useTranslationLang.ts new file mode 100644 index 000000000..65c087da5 --- /dev/null +++ b/src/layout/hooks/useTranslationLang.ts @@ -0,0 +1,38 @@ +import { useNav } from "./nav"; +import { useI18n } from "vue-i18n"; +import { useRoute } from "vue-router"; +import { watch, getCurrentInstance } from "vue"; + +export default function useTranslationLang() { + const { changeTitle, changeWangeditorLanguage } = useNav(); + const { locale, t } = useI18n(); + const route = useRoute(); + const instance = + getCurrentInstance().appContext.config.globalProperties.$storage; + + function translationCh() { + instance.locale = { locale: "zh" }; + locale.value = "zh"; + } + + function translationEn() { + instance.locale = { locale: "en" }; + locale.value = "en"; + } + + watch( + () => locale.value, + () => { + changeTitle(route.meta); + locale.value === "en" + ? changeWangeditorLanguage(locale.value) + : changeWangeditorLanguage("zh-CN"); + } + ); + return { + t, + locale, + translationCh, + translationEn + }; +} diff --git a/src/layout/index.vue b/src/layout/index.vue index 26e100c55..89c806005 100644 --- a/src/layout/index.vue +++ b/src/layout/index.vue @@ -1,25 +1,16 @@ + + + + + + + + + + + 简体中文 + + + + + + English + + + + +