mirror of
				https://github.com/pure-admin/vue-pure-admin.git
				synced 2025-11-03 13:44:47 +08:00 
			
		
		
		
	
						commit
						76f6a9df89
					
				@ -1,52 +1,26 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { useI18n } from "vue-i18n";
 | 
					 | 
				
			||||||
import { useNav } from "../hooks/nav";
 | 
					import { useNav } from "../hooks/nav";
 | 
				
			||||||
import { useRoute } from "vue-router";
 | 
					 | 
				
			||||||
import Search from "./search/index.vue";
 | 
					import Search from "./search/index.vue";
 | 
				
			||||||
import Notice from "./notice/index.vue";
 | 
					import Notice from "./notice/index.vue";
 | 
				
			||||||
import mixNav from "./sidebar/mixNav.vue";
 | 
					import mixNav from "./sidebar/mixNav.vue";
 | 
				
			||||||
import avatars from "/@/assets/avatars.jpg";
 | 
					import avatars from "/@/assets/avatars.jpg";
 | 
				
			||||||
import { watch, getCurrentInstance } from "vue";
 | 
					 | 
				
			||||||
import Breadcrumb from "./sidebar/breadCrumb.vue";
 | 
					import Breadcrumb from "./sidebar/breadCrumb.vue";
 | 
				
			||||||
import { deviceDetection } from "@pureadmin/utils";
 | 
					import { deviceDetection } from "@pureadmin/utils";
 | 
				
			||||||
import screenfull from "../components/screenfull/index.vue";
 | 
					import screenfull from "../components/screenfull/index.vue";
 | 
				
			||||||
 | 
					import { useTranslationLang } from "../hooks/useTranslationLang";
 | 
				
			||||||
import globalization from "/@/assets/svg/globalization.svg?component";
 | 
					import globalization from "/@/assets/svg/globalization.svg?component";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const route = useRoute();
 | 
					 | 
				
			||||||
const { locale, t } = useI18n();
 | 
					 | 
				
			||||||
const instance =
 | 
					 | 
				
			||||||
  getCurrentInstance().appContext.config.globalProperties.$storage;
 | 
					 | 
				
			||||||
const {
 | 
					const {
 | 
				
			||||||
  logout,
 | 
					  logout,
 | 
				
			||||||
  onPanel,
 | 
					  onPanel,
 | 
				
			||||||
  changeTitle,
 | 
					 | 
				
			||||||
  pureApp,
 | 
					  pureApp,
 | 
				
			||||||
  username,
 | 
					  username,
 | 
				
			||||||
  avatarsStyle,
 | 
					  avatarsStyle,
 | 
				
			||||||
  getDropdownItemStyle,
 | 
					  getDropdownItemStyle,
 | 
				
			||||||
  getDropdownItemClass,
 | 
					  getDropdownItemClass
 | 
				
			||||||
  changeWangeditorLanguage
 | 
					 | 
				
			||||||
} = useNav();
 | 
					} = useNav();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watch(
 | 
					const { t, locale, translationCh, translationEn } = useTranslationLang();
 | 
				
			||||||
  () => 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";
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { SearchModal } from "./components";
 | 
					import { SearchModal } from "./components";
 | 
				
			||||||
import useBoolean from "../../hooks/useBoolean";
 | 
					import { useBoolean } from "../../hooks/useBoolean";
 | 
				
			||||||
const { bool: show, toggle } = useBoolean();
 | 
					const { bool: show, toggle } = useBoolean();
 | 
				
			||||||
function handleSearch() {
 | 
					function handleSearch() {
 | 
				
			||||||
  toggle();
 | 
					  toggle();
 | 
				
			||||||
 | 
				
			|||||||
@ -6,33 +6,24 @@ import {
 | 
				
			|||||||
  reactive,
 | 
					  reactive,
 | 
				
			||||||
  computed,
 | 
					  computed,
 | 
				
			||||||
  nextTick,
 | 
					  nextTick,
 | 
				
			||||||
  useCssModule,
 | 
					  useCssModule
 | 
				
			||||||
  getCurrentInstance
 | 
					 | 
				
			||||||
} from "vue";
 | 
					} from "vue";
 | 
				
			||||||
import { find } from "lodash-unified";
 | 
					 | 
				
			||||||
import { getConfig } from "/@/config";
 | 
					import { getConfig } from "/@/config";
 | 
				
			||||||
import { useRouter } from "vue-router";
 | 
					import { useRouter } from "vue-router";
 | 
				
			||||||
import panel from "../panel/index.vue";
 | 
					import panel from "../panel/index.vue";
 | 
				
			||||||
import { emitter } from "/@/utils/mitt";
 | 
					import { emitter } from "/@/utils/mitt";
 | 
				
			||||||
import { templateRef } from "@vueuse/core";
 | 
					import { templateRef } from "@vueuse/core";
 | 
				
			||||||
import { TinyColor } from "@ctrl/tinycolor";
 | 
					 | 
				
			||||||
import { themeColorsType } from "../../types";
 | 
					 | 
				
			||||||
import { routerArrays } from "/@/layout/types";
 | 
					import { routerArrays } from "/@/layout/types";
 | 
				
			||||||
import type { StorageConfigs } from "/#/index";
 | 
					 | 
				
			||||||
import { useAppStoreHook } from "/@/store/modules/app";
 | 
					import { useAppStoreHook } from "/@/store/modules/app";
 | 
				
			||||||
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
 | 
					 | 
				
			||||||
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
 | 
					import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
 | 
				
			||||||
 | 
					import { useDataThemeChange } from "/@/layout/hooks/useDataThemeChange";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  useDark,
 | 
					  useDark,
 | 
				
			||||||
  debounce,
 | 
					  debounce,
 | 
				
			||||||
  storageLocal,
 | 
					  storageLocal,
 | 
				
			||||||
  storageSession
 | 
					  storageSession
 | 
				
			||||||
} from "@pureadmin/utils";
 | 
					} from "@pureadmin/utils";
 | 
				
			||||||
import {
 | 
					import { toggleTheme } from "@pureadmin/theme/dist/browser-utils";
 | 
				
			||||||
  darken,
 | 
					 | 
				
			||||||
  lighten,
 | 
					 | 
				
			||||||
  toggleTheme
 | 
					 | 
				
			||||||
} from "@pureadmin/theme/dist/browser-utils";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dayIcon from "/@/assets/svg/day.svg?component";
 | 
					import dayIcon from "/@/assets/svg/day.svg?component";
 | 
				
			||||||
import darkIcon from "/@/assets/svg/dark.svg?component";
 | 
					import darkIcon from "/@/assets/svg/dark.svg?component";
 | 
				
			||||||
@ -40,44 +31,21 @@ import darkIcon from "/@/assets/svg/dark.svg?component";
 | 
				
			|||||||
const router = useRouter();
 | 
					const router = useRouter();
 | 
				
			||||||
const { isDark } = useDark();
 | 
					const { isDark } = useDark();
 | 
				
			||||||
const { isSelect } = useCssModule();
 | 
					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 mixRef = templateRef<HTMLElement | null>("mixRef", null);
 | 
				
			||||||
const verticalRef = templateRef<HTMLElement | null>("verticalRef", null);
 | 
					const verticalRef = templateRef<HTMLElement | null>("verticalRef", null);
 | 
				
			||||||
const horizontalRef = templateRef<HTMLElement | null>("horizontalRef", null);
 | 
					const horizontalRef = templateRef<HTMLElement | null>("horizontalRef", null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let layoutTheme =
 | 
					const {
 | 
				
			||||||
  ref(storageLocal.getItem<StorageConfigs>("responsive-layout")) ||
 | 
					  body,
 | 
				
			||||||
  ref({
 | 
					  instance,
 | 
				
			||||||
    layout: instanceConfig?.Layout ?? "vertical",
 | 
					  dataTheme,
 | 
				
			||||||
    theme: instanceConfig?.Theme ?? "default"
 | 
					  layoutTheme,
 | 
				
			||||||
  });
 | 
					  themeColors,
 | 
				
			||||||
 | 
					  dataThemeChange,
 | 
				
			||||||
 | 
					  setEpThemeColor,
 | 
				
			||||||
 | 
					  setLayoutThemeColor
 | 
				
			||||||
 | 
					} = useDataThemeChange();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* body添加layout属性,作用于src/style/sidebar.scss */
 | 
					/* body添加layout属性,作用于src/style/sidebar.scss */
 | 
				
			||||||
if (unref(layoutTheme)) {
 | 
					if (unref(layoutTheme)) {
 | 
				
			||||||
@ -162,7 +130,7 @@ function onReset() {
 | 
				
			|||||||
  router.push("/login");
 | 
					  router.push("/login");
 | 
				
			||||||
  const { Grey, Weak, MultiTagsCache, EpThemeColor, Layout } = getConfig();
 | 
					  const { Grey, Weak, MultiTagsCache, EpThemeColor, Layout } = getConfig();
 | 
				
			||||||
  useAppStoreHook().setLayout(Layout);
 | 
					  useAppStoreHook().setLayout(Layout);
 | 
				
			||||||
  useEpThemeStoreHook().setEpThemeColor(EpThemeColor);
 | 
					  setEpThemeColor(EpThemeColor);
 | 
				
			||||||
  useMultiTagsStoreHook().multiTagsCacheChange(MultiTagsCache);
 | 
					  useMultiTagsStoreHook().multiTagsCacheChange(MultiTagsCache);
 | 
				
			||||||
  toggleClass(Grey, "html-grey", document.querySelector("html"));
 | 
					  toggleClass(Grey, "html-grey", document.querySelector("html"));
 | 
				
			||||||
  toggleClass(Weak, "html-weakness", document.querySelector("html"));
 | 
					  toggleClass(Weak, "html-weakness", document.querySelector("html"));
 | 
				
			||||||
@ -245,75 +213,6 @@ function setLayoutModel(layout: string) {
 | 
				
			|||||||
  useAppStoreHook().setLayout(layout);
 | 
					  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(() => {
 | 
					nextTick(() => {
 | 
				
			||||||
  settings.greyVal &&
 | 
					  settings.greyVal &&
 | 
				
			||||||
 | 
				
			|||||||
@ -173,8 +173,6 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.el-dropdown-menu {
 | 
					.el-dropdown-menu {
 | 
				
			||||||
  padding: 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  li {
 | 
					  li {
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { ref } from "vue";
 | 
					import { ref } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function useBoolean(initValue = false) {
 | 
					export function useBoolean(initValue = false) {
 | 
				
			||||||
  const bool = ref(initValue);
 | 
					  const bool = ref(initValue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function setBool(value: boolean) {
 | 
					  function setBool(value: boolean) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										120
									
								
								src/layout/hooks/useDataThemeChange.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/layout/hooks/useDataThemeChange.ts
									
									
									
									
									
										Normal file
									
								
							@ -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 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
									
								
								src/layout/hooks/useLayout.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/layout/hooks/useLayout.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					import { useI18n } from "vue-i18n";
 | 
				
			||||||
 | 
					import { routerArrays } from "../types";
 | 
				
			||||||
 | 
					import { computed, getCurrentInstance } from "vue";
 | 
				
			||||||
 | 
					import { useMultiTagsStore } from "/@/store/modules/multiTags";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export 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
									
								
								src/layout/hooks/useTranslationLang.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/layout/hooks/useTranslationLang.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					import { useNav } from "./nav";
 | 
				
			||||||
 | 
					import { useI18n } from "vue-i18n";
 | 
				
			||||||
 | 
					import { useRoute } from "vue-router";
 | 
				
			||||||
 | 
					import { watch, getCurrentInstance } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export 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
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,20 +1,11 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  h,
 | 
					 | 
				
			||||||
  reactive,
 | 
					 | 
				
			||||||
  computed,
 | 
					 | 
				
			||||||
  onMounted,
 | 
					 | 
				
			||||||
  defineComponent,
 | 
					 | 
				
			||||||
  getCurrentInstance
 | 
					 | 
				
			||||||
} from "vue";
 | 
					 | 
				
			||||||
import { setType } from "./types";
 | 
					import { setType } from "./types";
 | 
				
			||||||
import { useI18n } from "vue-i18n";
 | 
					 | 
				
			||||||
import { routerArrays } from "./types";
 | 
					 | 
				
			||||||
import { emitter } from "/@/utils/mitt";
 | 
					import { emitter } from "/@/utils/mitt";
 | 
				
			||||||
 | 
					import { useLayout } from "./hooks/useLayout";
 | 
				
			||||||
import { useAppStoreHook } from "/@/store/modules/app";
 | 
					import { useAppStoreHook } from "/@/store/modules/app";
 | 
				
			||||||
import { deviceDetection, useDark } from "@pureadmin/utils";
 | 
					import { deviceDetection, useDark } from "@pureadmin/utils";
 | 
				
			||||||
import { useMultiTagsStore } from "/@/store/modules/multiTags";
 | 
					 | 
				
			||||||
import { useSettingStoreHook } from "/@/store/modules/settings";
 | 
					import { useSettingStoreHook } from "/@/store/modules/settings";
 | 
				
			||||||
 | 
					import { h, reactive, computed, onMounted, defineComponent } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import backTop from "/@/assets/svg/back_top.svg?component";
 | 
					import backTop from "/@/assets/svg/back_top.svg?component";
 | 
				
			||||||
import fullScreen from "/@/assets/svg/full_screen.svg?component";
 | 
					import fullScreen from "/@/assets/svg/full_screen.svg?component";
 | 
				
			||||||
@ -30,49 +21,8 @@ import Horizontal from "./components/sidebar/horizontal.vue";
 | 
				
			|||||||
const { isDark } = useDark();
 | 
					const { isDark } = useDark();
 | 
				
			||||||
const isMobile = deviceDetection();
 | 
					const isMobile = deviceDetection();
 | 
				
			||||||
const pureSetting = useSettingStoreHook();
 | 
					const pureSetting = useSettingStoreHook();
 | 
				
			||||||
const instance = getCurrentInstance().appContext.app.config.globalProperties;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 清空缓存后从serverConfig.json读取默认配置并赋值到storage中
 | 
					const { instance, layout } = useLayout();
 | 
				
			||||||
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 set: setType = reactive({
 | 
					const set: setType = reactive({
 | 
				
			||||||
  sidebar: computed(() => {
 | 
					  sidebar: computed(() => {
 | 
				
			||||||
 | 
				
			|||||||
@ -25,7 +25,7 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.el-dropdown-menu {
 | 
					.el-dropdown-menu {
 | 
				
			||||||
  padding: 2px 0 !important;
 | 
					  padding: 0 !important;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.el-range-separator {
 | 
					.el-range-separator {
 | 
				
			||||||
 | 
				
			|||||||
@ -7,15 +7,23 @@ import qrCode from "./components/qrCode.vue";
 | 
				
			|||||||
import regist from "./components/regist.vue";
 | 
					import regist from "./components/regist.vue";
 | 
				
			||||||
import update from "./components/update.vue";
 | 
					import update from "./components/update.vue";
 | 
				
			||||||
import { initRouter } from "/@/router/utils";
 | 
					import { initRouter } from "/@/router/utils";
 | 
				
			||||||
 | 
					import { useNav } from "/@/layout/hooks/nav";
 | 
				
			||||||
import { message } from "@pureadmin/components";
 | 
					import { message } from "@pureadmin/components";
 | 
				
			||||||
import type { FormInstance } from "element-plus";
 | 
					import type { FormInstance } from "element-plus";
 | 
				
			||||||
import { storageSession } from "@pureadmin/utils";
 | 
					import { storageSession } from "@pureadmin/utils";
 | 
				
			||||||
import { ref, reactive, watch, computed, getCurrentInstance } from "vue";
 | 
					 | 
				
			||||||
import { operates, thirdParty } from "./utils/enums";
 | 
					import { operates, thirdParty } from "./utils/enums";
 | 
				
			||||||
 | 
					import { useLayout } from "/@/layout/hooks/useLayout";
 | 
				
			||||||
import { useUserStoreHook } from "/@/store/modules/user";
 | 
					import { useUserStoreHook } from "/@/store/modules/user";
 | 
				
			||||||
import { bg, avatar, currentWeek } from "./utils/static";
 | 
					import { bg, avatar, currentWeek } from "./utils/static";
 | 
				
			||||||
import { ReImageVerify } from "/@/components/ReImageVerify";
 | 
					import { ReImageVerify } from "/@/components/ReImageVerify";
 | 
				
			||||||
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
 | 
					import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
 | 
				
			||||||
 | 
					import { useTranslationLang } from "/@/layout/hooks/useTranslationLang";
 | 
				
			||||||
 | 
					import { useDataThemeChange } from "/@/layout/hooks/useDataThemeChange";
 | 
				
			||||||
 | 
					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({
 | 
					defineOptions({
 | 
				
			||||||
  name: "Login"
 | 
					  name: "Login"
 | 
				
			||||||
@ -31,6 +39,13 @@ const currentPage = computed(() => {
 | 
				
			|||||||
  return useUserStoreHook().currentPage;
 | 
					  return useUserStoreHook().currentPage;
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { initStorage } = useLayout();
 | 
				
			||||||
 | 
					initStorage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { dataTheme, dataThemeChange } = useDataThemeChange();
 | 
				
			||||||
 | 
					const { getDropdownItemStyle, getDropdownItemClass } = useNav();
 | 
				
			||||||
 | 
					const { locale, translationCh, translationEn } = useTranslationLang();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ruleForm = reactive({
 | 
					const ruleForm = reactive({
 | 
				
			||||||
  username: "admin",
 | 
					  username: "admin",
 | 
				
			||||||
  password: "admin123",
 | 
					  password: "admin123",
 | 
				
			||||||
@ -67,138 +82,184 @@ function onHandle(value) {
 | 
				
			|||||||
watch(imgCode, value => {
 | 
					watch(imgCode, value => {
 | 
				
			||||||
  useUserStoreHook().SET_VERIFYCODE(value);
 | 
					  useUserStoreHook().SET_VERIFYCODE(value);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dataThemeChange();
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <img :src="bg" class="wave" />
 | 
					  <div class="wh-full select-none">
 | 
				
			||||||
  <div class="login-container">
 | 
					    <img :src="bg" class="wave" />
 | 
				
			||||||
    <div class="img">
 | 
					    <div class="flex-c absolute right-5 top-3">
 | 
				
			||||||
      <component :is="currentWeek" />
 | 
					      <!-- 主题 -->
 | 
				
			||||||
 | 
					      <el-switch
 | 
				
			||||||
 | 
					        v-model="dataTheme"
 | 
				
			||||||
 | 
					        inline-prompt
 | 
				
			||||||
 | 
					        :active-icon="dayIcon"
 | 
				
			||||||
 | 
					        :inactive-icon="darkIcon"
 | 
				
			||||||
 | 
					        @change="dataThemeChange"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <!-- 国际化 -->
 | 
				
			||||||
 | 
					      <el-dropdown trigger="click">
 | 
				
			||||||
 | 
					        <globalization
 | 
				
			||||||
 | 
					          class="hover:color-primary !hover:bg-transparent w-20px h-20px ml-1.5 cursor-pointer outline-none duration-300"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <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>
 | 
					    </div>
 | 
				
			||||||
    <div class="login-box">
 | 
					    <div class="login-container">
 | 
				
			||||||
      <div class="login-form">
 | 
					      <div class="img">
 | 
				
			||||||
        <avatar class="avatar" />
 | 
					        <component :is="currentWeek" />
 | 
				
			||||||
        <Motion>
 | 
					      </div>
 | 
				
			||||||
          <h2>{{ title }}</h2>
 | 
					      <div class="login-box">
 | 
				
			||||||
        </Motion>
 | 
					        <div class="login-form">
 | 
				
			||||||
 | 
					          <avatar class="avatar" />
 | 
				
			||||||
        <el-form
 | 
					          <Motion>
 | 
				
			||||||
          v-if="currentPage === 0"
 | 
					            <h2 class="outline-none">{{ title }}</h2>
 | 
				
			||||||
          ref="ruleFormRef"
 | 
					 | 
				
			||||||
          :model="ruleForm"
 | 
					 | 
				
			||||||
          :rules="loginRules"
 | 
					 | 
				
			||||||
          size="large"
 | 
					 | 
				
			||||||
          @keyup.enter="onLogin(ruleFormRef)"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <Motion :delay="100">
 | 
					 | 
				
			||||||
            <el-form-item prop="username">
 | 
					 | 
				
			||||||
              <el-input
 | 
					 | 
				
			||||||
                clearable
 | 
					 | 
				
			||||||
                v-model="ruleForm.username"
 | 
					 | 
				
			||||||
                placeholder="账号"
 | 
					 | 
				
			||||||
                :prefix-icon="useRenderIcon('user')"
 | 
					 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
            </el-form-item>
 | 
					 | 
				
			||||||
          </Motion>
 | 
					          </Motion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <Motion :delay="150">
 | 
					          <el-form
 | 
				
			||||||
            <el-form-item prop="password">
 | 
					            v-if="currentPage === 0"
 | 
				
			||||||
              <el-input
 | 
					            ref="ruleFormRef"
 | 
				
			||||||
                clearable
 | 
					            :model="ruleForm"
 | 
				
			||||||
                show-password
 | 
					            :rules="loginRules"
 | 
				
			||||||
                v-model="ruleForm.password"
 | 
					            size="large"
 | 
				
			||||||
                placeholder="密码"
 | 
					            @keyup.enter="onLogin(ruleFormRef)"
 | 
				
			||||||
                :prefix-icon="useRenderIcon('lock')"
 | 
					          >
 | 
				
			||||||
              />
 | 
					            <Motion :delay="100">
 | 
				
			||||||
            </el-form-item>
 | 
					              <el-form-item prop="username">
 | 
				
			||||||
          </Motion>
 | 
					                <el-input
 | 
				
			||||||
 | 
					                  clearable
 | 
				
			||||||
 | 
					                  v-model="ruleForm.username"
 | 
				
			||||||
 | 
					                  placeholder="账号"
 | 
				
			||||||
 | 
					                  :prefix-icon="useRenderIcon('user')"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </el-form-item>
 | 
				
			||||||
 | 
					            </Motion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <Motion :delay="200">
 | 
					            <Motion :delay="150">
 | 
				
			||||||
            <el-form-item prop="verifyCode">
 | 
					              <el-form-item prop="password">
 | 
				
			||||||
              <el-input
 | 
					                <el-input
 | 
				
			||||||
                clearable
 | 
					                  clearable
 | 
				
			||||||
                v-model="ruleForm.verifyCode"
 | 
					                  show-password
 | 
				
			||||||
                placeholder="验证码"
 | 
					                  v-model="ruleForm.password"
 | 
				
			||||||
                :prefix-icon="
 | 
					                  placeholder="密码"
 | 
				
			||||||
                  useRenderIcon('ri:shield-keyhole-line', { online: true })
 | 
					                  :prefix-icon="useRenderIcon('lock')"
 | 
				
			||||||
                "
 | 
					                />
 | 
				
			||||||
              >
 | 
					              </el-form-item>
 | 
				
			||||||
                <template v-slot:append>
 | 
					            </Motion>
 | 
				
			||||||
                  <ReImageVerify v-model:code="imgCode" />
 | 
					 | 
				
			||||||
                </template>
 | 
					 | 
				
			||||||
              </el-input>
 | 
					 | 
				
			||||||
            </el-form-item>
 | 
					 | 
				
			||||||
          </Motion>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <Motion :delay="250">
 | 
					            <Motion :delay="200">
 | 
				
			||||||
            <el-form-item>
 | 
					              <el-form-item prop="verifyCode">
 | 
				
			||||||
              <div class="w-full h-20px flex justify-between items-center">
 | 
					                <el-input
 | 
				
			||||||
                <el-checkbox v-model="checked">记住密码</el-checkbox>
 | 
					                  clearable
 | 
				
			||||||
                <el-button
 | 
					                  v-model="ruleForm.verifyCode"
 | 
				
			||||||
                  link
 | 
					                  placeholder="验证码"
 | 
				
			||||||
                  type="primary"
 | 
					                  :prefix-icon="
 | 
				
			||||||
                  @click="useUserStoreHook().SET_CURRENTPAGE(4)"
 | 
					                    useRenderIcon('ri:shield-keyhole-line', { online: true })
 | 
				
			||||||
 | 
					                  "
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                  忘记密码?
 | 
					                  <template v-slot:append>
 | 
				
			||||||
                </el-button>
 | 
					                    <ReImageVerify v-model:code="imgCode" />
 | 
				
			||||||
              </div>
 | 
					                  </template>
 | 
				
			||||||
              <el-button
 | 
					                </el-input>
 | 
				
			||||||
                class="w-full mt-4"
 | 
					              </el-form-item>
 | 
				
			||||||
                size="default"
 | 
					            </Motion>
 | 
				
			||||||
                type="primary"
 | 
					 | 
				
			||||||
                :loading="loading"
 | 
					 | 
				
			||||||
                @click="onLogin(ruleFormRef)"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                登录
 | 
					 | 
				
			||||||
              </el-button>
 | 
					 | 
				
			||||||
            </el-form-item>
 | 
					 | 
				
			||||||
          </Motion>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <Motion :delay="300">
 | 
					            <Motion :delay="250">
 | 
				
			||||||
            <el-form-item>
 | 
					              <el-form-item>
 | 
				
			||||||
              <div class="w-full h-20px flex justify-between items-center">
 | 
					                <div class="w-full h-20px flex justify-between items-center">
 | 
				
			||||||
 | 
					                  <el-checkbox v-model="checked">记住密码</el-checkbox>
 | 
				
			||||||
 | 
					                  <el-button
 | 
				
			||||||
 | 
					                    link
 | 
				
			||||||
 | 
					                    type="primary"
 | 
				
			||||||
 | 
					                    @click="useUserStoreHook().SET_CURRENTPAGE(4)"
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    忘记密码?
 | 
				
			||||||
 | 
					                  </el-button>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
                <el-button
 | 
					                <el-button
 | 
				
			||||||
                  v-for="(item, index) in operates"
 | 
					 | 
				
			||||||
                  :key="index"
 | 
					 | 
				
			||||||
                  class="w-full mt-4"
 | 
					                  class="w-full mt-4"
 | 
				
			||||||
                  size="default"
 | 
					                  size="default"
 | 
				
			||||||
                  @click="onHandle(index + 1)"
 | 
					                  type="primary"
 | 
				
			||||||
 | 
					                  :loading="loading"
 | 
				
			||||||
 | 
					                  @click="onLogin(ruleFormRef)"
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                  {{ item.title }}
 | 
					                  登录
 | 
				
			||||||
                </el-button>
 | 
					                </el-button>
 | 
				
			||||||
 | 
					              </el-form-item>
 | 
				
			||||||
 | 
					            </Motion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <Motion :delay="300">
 | 
				
			||||||
 | 
					              <el-form-item>
 | 
				
			||||||
 | 
					                <div class="w-full h-20px flex justify-between items-center">
 | 
				
			||||||
 | 
					                  <el-button
 | 
				
			||||||
 | 
					                    v-for="(item, index) in operates"
 | 
				
			||||||
 | 
					                    :key="index"
 | 
				
			||||||
 | 
					                    class="w-full mt-4"
 | 
				
			||||||
 | 
					                    size="default"
 | 
				
			||||||
 | 
					                    @click="onHandle(index + 1)"
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    {{ item.title }}
 | 
				
			||||||
 | 
					                  </el-button>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </el-form-item>
 | 
				
			||||||
 | 
					            </Motion>
 | 
				
			||||||
 | 
					          </el-form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <Motion v-if="currentPage === 0" :delay="350">
 | 
				
			||||||
 | 
					            <el-form-item>
 | 
				
			||||||
 | 
					              <el-divider>
 | 
				
			||||||
 | 
					                <p class="text-gray-500 text-xs">第三方登录</p>
 | 
				
			||||||
 | 
					              </el-divider>
 | 
				
			||||||
 | 
					              <div class="w-full flex justify-evenly">
 | 
				
			||||||
 | 
					                <span
 | 
				
			||||||
 | 
					                  v-for="(item, index) in thirdParty"
 | 
				
			||||||
 | 
					                  :key="index"
 | 
				
			||||||
 | 
					                  :title="`${item.title}登录`"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <IconifyIconOnline
 | 
				
			||||||
 | 
					                    :icon="`ri:${item.icon}-fill`"
 | 
				
			||||||
 | 
					                    width="20"
 | 
				
			||||||
 | 
					                    class="cursor-pointer text-gray-500 hover:text-blue-400"
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
            </el-form-item>
 | 
					            </el-form-item>
 | 
				
			||||||
          </Motion>
 | 
					          </Motion>
 | 
				
			||||||
        </el-form>
 | 
					          <!-- 手机号登录 -->
 | 
				
			||||||
 | 
					          <phone v-if="currentPage === 1" />
 | 
				
			||||||
        <Motion v-if="currentPage === 0" :delay="350">
 | 
					          <!-- 二维码登录 -->
 | 
				
			||||||
          <el-form-item>
 | 
					          <qrCode v-if="currentPage === 2" />
 | 
				
			||||||
            <el-divider>
 | 
					          <!-- 注册 -->
 | 
				
			||||||
              <p class="text-gray-500 text-xs">第三方登录</p>
 | 
					          <regist v-if="currentPage === 3" />
 | 
				
			||||||
            </el-divider>
 | 
					          <!-- 忘记密码 -->
 | 
				
			||||||
            <div class="w-full flex justify-evenly">
 | 
					          <update v-if="currentPage === 4" />
 | 
				
			||||||
              <span
 | 
					        </div>
 | 
				
			||||||
                v-for="(item, index) in thirdParty"
 | 
					 | 
				
			||||||
                :key="index"
 | 
					 | 
				
			||||||
                :title="`${item.title}登录`"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <IconifyIconOnline
 | 
					 | 
				
			||||||
                  :icon="`ri:${item.icon}-fill`"
 | 
					 | 
				
			||||||
                  width="20"
 | 
					 | 
				
			||||||
                  class="cursor-pointer text-gray-500 hover:text-blue-400"
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
              </span>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </el-form-item>
 | 
					 | 
				
			||||||
        </Motion>
 | 
					 | 
				
			||||||
        <!-- 手机号登录 -->
 | 
					 | 
				
			||||||
        <phone v-if="currentPage === 1" />
 | 
					 | 
				
			||||||
        <!-- 二维码登录 -->
 | 
					 | 
				
			||||||
        <qrCode v-if="currentPage === 2" />
 | 
					 | 
				
			||||||
        <!-- 注册 -->
 | 
					 | 
				
			||||||
        <regist v-if="currentPage === 3" />
 | 
					 | 
				
			||||||
        <!-- 忘记密码 -->
 | 
					 | 
				
			||||||
        <update v-if="currentPage === 4" />
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
@ -212,4 +273,20 @@ watch(imgCode, value => {
 | 
				
			|||||||
:deep(.el-input-group__append, .el-input-group__prepend) {
 | 
					:deep(.el-input-group__append, .el-input-group__prepend) {
 | 
				
			||||||
  padding: 0;
 | 
					  padding: 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.translation {
 | 
				
			||||||
 | 
					  ::v-deep(.el-dropdown-menu__item) {
 | 
				
			||||||
 | 
					    padding: 5px 40px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .check-zh {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    left: 20px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .check-en {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    left: 20px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user