lrl 2 vuotta sitten
vanhempi
commit
114d5427cc

+ 3 - 29
src/layout/components/navbar.vue

@@ -1,52 +1,26 @@
 <script setup lang="ts">
-import { useI18n } from "vue-i18n";
 import { useNav } from "../hooks/nav";
-import { useRoute } from "vue-router";
 import Search from "./search/index.vue";
 import Notice from "./notice/index.vue";
 import mixNav from "./sidebar/mixNav.vue";
 import avatars from "/@/assets/avatars.jpg";
-import { watch, getCurrentInstance } from "vue";
 import Breadcrumb from "./sidebar/breadCrumb.vue";
 import { deviceDetection } from "@pureadmin/utils";
 import screenfull from "../components/screenfull/index.vue";
+import useTranslationLang from "../hooks/useTranslationLang";
 import globalization from "/@/assets/svg/globalization.svg?component";
 
-const route = useRoute();
-const { locale, t } = useI18n();
-const instance =
-  getCurrentInstance().appContext.config.globalProperties.$storage;
 const {
   logout,
   onPanel,
-  changeTitle,
   pureApp,
   username,
   avatarsStyle,
   getDropdownItemStyle,
-  getDropdownItemClass,
-  changeWangeditorLanguage
+  getDropdownItemClass
 } = useNav();
 
-watch(
-  () => locale.value,
-  () => {
-    changeTitle(route.meta);
-    locale.value === "en"
-      ? changeWangeditorLanguage(locale.value)
-      : changeWangeditorLanguage("zh-CN");
-  }
-);
-
-function translationCh() {
-  instance.locale = { locale: "zh" };
-  locale.value = "zh";
-}
-
-function translationEn() {
-  instance.locale = { locale: "en" };
-  locale.value = "en";
-}
+const { t, locale, translationCh, translationEn } = useTranslationLang();
 </script>
 
 <template>

+ 12 - 113
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<Array<themeColorsType>>([
-  /* 道奇蓝(默认) */
-  { 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<HTMLElement | null>("mixRef", null);
 const verticalRef = templateRef<HTMLElement | null>("verticalRef", null);
 const horizontalRef = templateRef<HTMLElement | null>("horizontalRef", null);
 
-let layoutTheme =
-  ref(storageLocal.getItem<StorageConfigs>("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<boolean>(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 &&

+ 120 - 0
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<Array<themeColorsType>>([
+    /* 道奇蓝(默认) */
+    { 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<boolean>(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
+  };
+}

+ 61 - 0
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
+  };
+}

+ 38 - 0
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
+  };
+}

+ 3 - 53
src/layout/index.vue

@@ -1,25 +1,16 @@
 <script setup lang="ts">
-import {
-  h,
-  reactive,
-  computed,
-  onMounted,
-  defineComponent,
-  getCurrentInstance
-} from "vue";
 import { setType } from "./types";
-import { useI18n } from "vue-i18n";
-import { routerArrays } from "./types";
 import { emitter } from "/@/utils/mitt";
 import { useAppStoreHook } from "/@/store/modules/app";
 import { deviceDetection, useDark } from "@pureadmin/utils";
-import { useMultiTagsStore } from "/@/store/modules/multiTags";
 import { useSettingStoreHook } from "/@/store/modules/settings";
+import { h, reactive, computed, onMounted, defineComponent } from "vue";
 
 import backTop from "/@/assets/svg/back_top.svg?component";
 import fullScreen from "/@/assets/svg/full_screen.svg?component";
 import exitScreen from "/@/assets/svg/exit_screen.svg?component";
 
+import useLayout from "./hooks/useLayout";
 import navbar from "./components/navbar.vue";
 import tag from "./components/tag/index.vue";
 import appMain from "./components/appMain.vue";
@@ -30,49 +21,8 @@ import Horizontal from "./components/sidebar/horizontal.vue";
 const { isDark } = useDark();
 const isMobile = deviceDetection();
 const pureSetting = useSettingStoreHook();
-const instance = getCurrentInstance().appContext.app.config.globalProperties;
 
-// 清空缓存后从serverConfig.json读取默认配置并赋值到storage中
-const layout = computed(() => {
-  // 路由
-  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
-    };
-  }
-  return instance.$storage?.layout.layout;
-});
+const { instance, layout } = useLayout();
 
 const set: setType = reactive({
   sidebar: computed(() => {

+ 56 - 1
src/views/login/index.vue

@@ -7,15 +7,23 @@ import qrCode from "./components/qrCode.vue";
 import regist from "./components/regist.vue";
 import update from "./components/update.vue";
 import { initRouter } from "/@/router/utils";
+import { useNav } from "/@/layout/hooks/nav";
 import { message } from "@pureadmin/components";
 import type { FormInstance } from "element-plus";
+import useLayout from "/@/layout/hooks/useLayout";
 import { storageSession } from "@pureadmin/utils";
-import { ref, reactive, watch, computed, getCurrentInstance } from "vue";
 import { operates, thirdParty } from "./utils/enums";
 import { useUserStoreHook } from "/@/store/modules/user";
 import { bg, avatar, currentWeek } from "./utils/static";
 import { ReImageVerify } from "/@/components/ReImageVerify";
 import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
+import useDataThemeChange from "/@/layout/hooks/useDataThemeChange";
+import useTranslationLang from "/@/layout/hooks/useTranslationLang";
+import { ref, reactive, watch, computed, getCurrentInstance } from "vue";
+
+import dayIcon from "/@/assets/svg/day.svg?component";
+import darkIcon from "/@/assets/svg/dark.svg?component";
+import globalization from "/@/assets/svg/globalization.svg?component";
 
 defineOptions({
   name: "Login"
@@ -31,6 +39,13 @@ const currentPage = computed(() => {
   return useUserStoreHook().currentPage;
 });
 
+const { initStorage } = useLayout();
+initStorage();
+
+const { dataTheme, dataThemeChange } = useDataThemeChange();
+const { getDropdownItemStyle, getDropdownItemClass } = useNav();
+const { locale, translationCh, translationEn } = useTranslationLang();
+
 const ruleForm = reactive({
   username: "admin",
   password: "admin123",
@@ -70,6 +85,46 @@ watch(imgCode, value => {
 </script>
 
 <template>
+  <div class="flex-c absolute right-5">
+    <!-- 主题 -->
+    <el-switch
+      v-model="dataTheme"
+      inline-prompt
+      :active-icon="dayIcon"
+      :inactive-icon="darkIcon"
+      @change="dataThemeChange"
+    />
+    <!-- 国际化 -->
+    <el-dropdown trigger="click">
+      <globalization class="w-40px h-48px p-11px cursor-pointer outline-none" />
+      <template #dropdown>
+        <el-dropdown-menu class="translation">
+          <el-dropdown-item
+            :style="getDropdownItemStyle(locale, 'zh')"
+            :class="['!dark:color-white', getDropdownItemClass(locale, 'zh')]"
+            @click="translationCh"
+          >
+            <IconifyIconOffline
+              class="check-zh"
+              v-show="locale === 'zh'"
+              icon="check"
+            />
+            简体中文
+          </el-dropdown-item>
+          <el-dropdown-item
+            :style="getDropdownItemStyle(locale, 'en')"
+            :class="['!dark:color-white', getDropdownItemClass(locale, 'en')]"
+            @click="translationEn"
+          >
+            <span class="check-en" v-show="locale === 'en'">
+              <IconifyIconOffline icon="check" />
+            </span>
+            English
+          </el-dropdown-item>
+        </el-dropdown-menu>
+      </template>
+    </el-dropdown>
+  </div>
   <img :src="bg" class="wave" />
   <div class="login-container">
     <div class="img">