7 changed files with 673 additions and 653 deletions
@ -0,0 +1,302 @@ |
|||||||
|
<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({ |
||||||
|
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} { |
||||||
|
border-radius: 6px 0 0 6px; |
||||||
|
z-index: 1200;/*修正没有z-index会被表格层覆盖,值不要超过4000*/ |
||||||
|
} |
||||||
|
</style> |
Loading…
Reference in new issue