From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/layout/components/Setting/src/Setting.vue |  303 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 303 insertions(+), 0 deletions(-)

diff --git a/src/layout/components/Setting/src/Setting.vue b/src/layout/components/Setting/src/Setting.vue
new file mode 100644
index 0000000..92ecf41
--- /dev/null
+++ b/src/layout/components/Setting/src/Setting.vue
@@ -0,0 +1,303 @@
+<script lang="ts" setup>
+import { ElMessage } from 'element-plus'
+import { useClipboard, useCssVar } from '@vueuse/core'
+
+import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
+import { useDesign } from '@/hooks/web/useDesign'
+
+import { setCssVar, trim } from '@/utils'
+import { colorIsDark, hexToRGB, lighten } from '@/utils/color'
+import { useAppStore } from '@/store/modules/app'
+import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
+import ColorRadioPicker from './components/ColorRadioPicker.vue'
+import InterfaceDisplay from './components/InterfaceDisplay.vue'
+import LayoutRadioPicker from './components/LayoutRadioPicker.vue'
+
+defineOptions({ name: 'Setting' })
+
+const { t } = useI18n()
+const appStore = useAppStore()
+
+const { getPrefixCls } = useDesign()
+const prefixCls = getPrefixCls('setting')
+const layout = computed(() => appStore.getLayout)
+const drawer = ref(false)
+
+// 涓婚鑹茬浉鍏�
+const systemTheme = ref(appStore.getTheme.elColorPrimary)
+
+const setSystemTheme = (color: string) => {
+  setCssVar('--el-color-primary', color)
+  appStore.setTheme({ elColorPrimary: color })
+  const leftMenuBgColor = useCssVar('--left-menu-bg-color', document.documentElement)
+  setMenuTheme(trim(unref(leftMenuBgColor)))
+}
+
+// 澶撮儴涓婚鐩稿叧
+const headerTheme = ref(appStore.getTheme.topHeaderBgColor || '')
+
+const setHeaderTheme = (color: string) => {
+  const isDarkColor = colorIsDark(color)
+  const textColor = isDarkColor ? '#fff' : 'inherit'
+  const textHoverColor = isDarkColor ? lighten(color!, 6) : '#f6f6f6'
+  const topToolBorderColor = isDarkColor ? color : '#eee'
+  setCssVar('--top-header-bg-color', color)
+  setCssVar('--top-header-text-color', textColor)
+  setCssVar('--top-header-hover-color', textHoverColor)
+  appStore.setTheme({
+    topHeaderBgColor: color,
+    topHeaderTextColor: textColor,
+    topHeaderHoverColor: textHoverColor,
+    topToolBorderColor
+  })
+  if (unref(layout) === 'top') {
+    setMenuTheme(color)
+  }
+}
+
+// 鑿滃崟涓婚鐩稿叧
+const menuTheme = ref(appStore.getTheme.leftMenuBgColor || '')
+
+const setMenuTheme = (color: string) => {
+  const primaryColor = useCssVar('--el-color-primary', document.documentElement)
+  const isDarkColor = colorIsDark(color)
+  const theme: Recordable = {
+    // 宸︿晶鑿滃崟杈规棰滆壊
+    leftMenuBorderColor: isDarkColor ? 'inherit' : '#eee',
+    // 宸︿晶鑿滃崟鑳屾櫙棰滆壊
+    leftMenuBgColor: color,
+    // 宸︿晶鑿滃崟娴呰壊鑳屾櫙棰滆壊
+    leftMenuBgLightColor: isDarkColor ? lighten(color!, 6) : color,
+    // 宸︿晶鑿滃崟閫変腑鑳屾櫙棰滆壊
+    leftMenuBgActiveColor: isDarkColor
+      ? 'var(--el-color-primary)'
+      : hexToRGB(unref(primaryColor), 0.1),
+    // 宸︿晶鑿滃崟鏀惰捣閫変腑鑳屾櫙棰滆壊
+    leftMenuCollapseBgActiveColor: isDarkColor
+      ? 'var(--el-color-primary)'
+      : hexToRGB(unref(primaryColor), 0.1),
+    // 宸︿晶鑿滃崟瀛椾綋棰滆壊
+    leftMenuTextColor: isDarkColor ? '#bfcbd9' : '#333',
+    // 宸︿晶鑿滃崟閫変腑瀛椾綋棰滆壊
+    leftMenuTextActiveColor: isDarkColor ? '#fff' : 'var(--el-color-primary)',
+    // logo瀛椾綋棰滆壊
+    logoTitleTextColor: isDarkColor ? '#fff' : 'inherit',
+    // logo杈规棰滆壊
+    logoBorderColor: isDarkColor ? color : '#eee'
+  }
+  appStore.setTheme(theme)
+  appStore.setCssVarTheme()
+}
+if (layout.value === 'top' && !appStore.getIsDark) {
+  headerTheme.value = '#fff'
+  setHeaderTheme('#fff')
+}
+
+// 鐩戝惉layout鍙樺寲锛岄噸缃竴浜涗富棰樿壊
+watch(
+  () => layout.value,
+  (n) => {
+    if (n === 'top' && !appStore.getIsDark) {
+      headerTheme.value = '#fff'
+      setHeaderTheme('#fff')
+    } else {
+      setMenuTheme(unref(menuTheme))
+    }
+  }
+)
+
+// 鎷疯礉
+const copyConfig = async () => {
+  const { copy, copied, isSupported } = useClipboard({
+    legacy: true,
+    source: `
+      // 闈㈠寘灞�
+      breadcrumb: ${appStore.getBreadcrumb},
+      // 闈㈠寘灞戝浘鏍�
+      breadcrumbIcon: ${appStore.getBreadcrumbIcon},
+      // 鎶樺彔鍥炬爣
+      hamburger: ${appStore.getHamburger},
+      // 鍏ㄥ睆鍥炬爣
+      screenfull: ${appStore.getScreenfull},
+      // 灏哄鍥炬爣
+      size: ${appStore.getSize},
+      // 澶氳瑷�鍥炬爣
+      locale: ${appStore.getLocale},
+      // 娑堟伅鍥炬爣
+      message: ${appStore.getMessage},
+      // 鏍囩椤�
+      tagsView: ${appStore.getTagsView},
+      // 鏍囩椤�
+      tagsViewImmerse: ${appStore.getTagsViewImmerse},
+      // 鏍囩椤靛浘鏍�
+      tagsViewIcon: ${appStore.getTagsViewIcon},
+      // logo
+      logo: ${appStore.getLogo},
+      // 鑿滃崟鎵嬮鐞�
+      uniqueOpened: ${appStore.getUniqueOpened},
+      // 鍥哄畾header
+      fixedHeader: ${appStore.getFixedHeader},
+      // 椤佃剼
+      footer: ${appStore.getFooter},
+      // 鐏拌壊妯″紡
+      greyMode: ${appStore.getGreyMode},
+      // layout甯冨眬
+      layout: '${appStore.getLayout}',
+      // 鏆楅粦妯″紡
+      isDark: ${appStore.getIsDark},
+      // 缁勪欢灏哄
+      currentSize: '${appStore.getCurrentSize}',
+      // 涓婚鐩稿叧
+      theme: {
+        // 涓婚鑹�
+        elColorPrimary: '${appStore.getTheme.elColorPrimary}',
+        // 宸︿晶鑿滃崟杈规棰滆壊
+        leftMenuBorderColor: '${appStore.getTheme.leftMenuBorderColor}',
+        // 宸︿晶鑿滃崟鑳屾櫙棰滆壊
+        leftMenuBgColor: '${appStore.getTheme.leftMenuBgColor}',
+        // 宸︿晶鑿滃崟娴呰壊鑳屾櫙棰滆壊
+        leftMenuBgLightColor: '${appStore.getTheme.leftMenuBgLightColor}',
+        // 宸︿晶鑿滃崟閫変腑鑳屾櫙棰滆壊
+        leftMenuBgActiveColor: '${appStore.getTheme.leftMenuBgActiveColor}',
+        // 宸︿晶鑿滃崟鏀惰捣閫変腑鑳屾櫙棰滆壊
+        leftMenuCollapseBgActiveColor: '${appStore.getTheme.leftMenuCollapseBgActiveColor}',
+        // 宸︿晶鑿滃崟瀛椾綋棰滆壊
+        leftMenuTextColor: '${appStore.getTheme.leftMenuTextColor}',
+        // 宸︿晶鑿滃崟閫変腑瀛椾綋棰滆壊
+        leftMenuTextActiveColor: '${appStore.getTheme.leftMenuTextActiveColor}',
+        // logo瀛椾綋棰滆壊
+        logoTitleTextColor: '${appStore.getTheme.logoTitleTextColor}',
+        // logo杈规棰滆壊
+        logoBorderColor: '${appStore.getTheme.logoBorderColor}',
+        // 澶撮儴鑳屾櫙棰滆壊
+        topHeaderBgColor: '${appStore.getTheme.topHeaderBgColor}',
+        // 澶撮儴瀛椾綋棰滆壊
+        topHeaderTextColor: '${appStore.getTheme.topHeaderTextColor}',
+        // 澶撮儴鎮仠棰滆壊
+        topHeaderHoverColor: '${appStore.getTheme.topHeaderHoverColor}',
+        // 澶撮儴杈规棰滆壊
+        topToolBorderColor: '${appStore.getTheme.topToolBorderColor}'
+      }
+    `
+  })
+  if (!isSupported) {
+    ElMessage.error(t('setting.copyFailed'))
+  } else {
+    await copy()
+    if (unref(copied)) {
+      ElMessage.success(t('setting.copySuccess'))
+    }
+  }
+}
+
+// 娓呯┖缂撳瓨
+const clear = () => {
+  const { wsCache } = useCache()
+  wsCache.delete(CACHE_KEY.LAYOUT)
+  wsCache.delete(CACHE_KEY.THEME)
+  wsCache.delete(CACHE_KEY.IS_DARK)
+  window.location.reload()
+}
+</script>
+
+<template>
+  <div
+    :class="prefixCls"
+    class="fixed right-0 top-[45%] h-40px w-40px cursor-pointer bg-[var(--el-color-primary)] text-center leading-40px"
+    @click="drawer = true"
+  >
+    <Icon color="#fff" icon="ep:setting" />
+  </div>
+
+  <ElDrawer v-model="drawer" :z-index="4000" direction="rtl" size="350px">
+    <template #header>
+      <span class="text-16px font-700">{{ t('setting.projectSetting') }}</span>
+    </template>
+
+    <div class="text-center">
+      <!-- 涓婚 -->
+      <ElDivider>{{ t('setting.theme') }}</ElDivider>
+      <ThemeSwitch />
+
+      <!-- 甯冨眬 -->
+      <ElDivider>{{ t('setting.layout') }}</ElDivider>
+      <LayoutRadioPicker />
+
+      <!-- 绯荤粺涓婚 -->
+      <ElDivider>{{ t('setting.systemTheme') }}</ElDivider>
+      <ColorRadioPicker
+        v-model="systemTheme"
+        :schema="[
+          '#409eff',
+          '#009688',
+          '#536dfe',
+          '#ff5c93',
+          '#ee4f12',
+          '#0096c7',
+          '#9c27b0',
+          '#ff9800'
+        ]"
+        @change="setSystemTheme"
+      />
+
+      <!-- 澶撮儴涓婚 -->
+      <ElDivider>{{ t('setting.headerTheme') }}</ElDivider>
+      <ColorRadioPicker
+        v-model="headerTheme"
+        :schema="[
+          '#fff',
+          '#151515',
+          '#5172dc',
+          '#e74c3c',
+          '#24292e',
+          '#394664',
+          '#009688',
+          '#383f45'
+        ]"
+        @change="setHeaderTheme"
+      />
+
+      <!-- 鑿滃崟涓婚 -->
+      <template v-if="layout !== 'top'">
+        <ElDivider>{{ t('setting.menuTheme') }}</ElDivider>
+        <ColorRadioPicker
+          v-model="menuTheme"
+          :schema="[
+            '#fff',
+            '#001529',
+            '#212121',
+            '#273352',
+            '#191b24',
+            '#383f45',
+            '#001628',
+            '#344058'
+          ]"
+          @change="setMenuTheme"
+        />
+      </template>
+    </div>
+
+    <!-- 鐣岄潰鏄剧ず -->
+    <ElDivider>{{ t('setting.interfaceDisplay') }}</ElDivider>
+    <InterfaceDisplay />
+
+    <ElDivider />
+    <div>
+      <ElButton class="w-full" type="primary" @click="copyConfig">{{ t('setting.copy') }}</ElButton>
+    </div>
+    <div class="mt-5px">
+      <ElButton class="w-full" type="danger" @click="clear">
+        {{ t('setting.clearAndReset') }}
+      </ElButton>
+    </div>
+  </ElDrawer>
+</template>
+
+<style lang="scss" scoped>
+$prefix-cls: #{$namespace}-setting;
+
+.#{$prefix-cls} {
+  z-index: 1200; /* 淇娌℃湁z-index浼氳琛ㄦ牸灞傝鐩�,鍊间笉瑕佽秴杩�4000 */
+  border-radius: 6px 0 0 6px;
+}
+</style>

--
Gitblit v1.8.0