This commit is contained in:
2026-01-26 10:01:26 +08:00
parent 01e87acfd1
commit 3f58d013ca
9 changed files with 1805 additions and 33 deletions

View File

@@ -0,0 +1,495 @@
<template>
<div class="setting-container">
<!-- 设置按钮 -->
<div class="setting-btn" @click="showDrawer = true">
<el-icon>
<Setting />
</el-icon>
</div>
<!-- 设置抽屉 -->
<el-drawer v-model="showDrawer" title="系统设置" :size="300" :close-on-click-modal="false">
<div class="setting-content">
<!-- 布局模式 -->
<div class="setting-item">
<div class="setting-title">布局模式</div>
<div class="setting-value">
<el-radio-group v-model="layoutMode" @change="handleLayoutModeChange">
<el-radio label="default">
<div class="layout-option">
<div class="layout-preview layout-default">
<div class="layout-aside-left"></div>
<div class="layout-aside-right"></div>
<div class="layout-main"></div>
</div>
<span>双栏布局</span>
</div>
</el-radio>
<el-radio label="menu">
<div class="layout-option">
<div class="layout-preview layout-menu">
<div class="layout-aside"></div>
<div class="layout-main"></div>
</div>
<span>菜单布局</span>
</div>
</el-radio>
<el-radio label="top">
<div class="layout-option">
<div class="layout-preview layout-top">
<div class="layout-header"></div>
<div class="layout-main"></div>
</div>
<span>顶部布局</span>
</div>
</el-radio>
</el-radio-group>
</div>
</div>
<!-- 主题色 -->
<div class="setting-item">
<div class="setting-title">主题色</div>
<div class="setting-value">
<div class="color-picker-wrapper">
<el-color-picker v-model="themeColor" show-alpha :predefine="predefineColors"
@change="handleThemeColorChange" />
</div>
<div class="color-presets">
<div v-for="color in predefineColors" :key="color" class="color-preset"
:class="{ active: themeColor === color }" :style="{ backgroundColor: color }"
@click="handleColorPresetClick(color)"></div>
</div>
</div>
</div>
<!-- 主题模式 -->
<div class="setting-item">
<div class="setting-title">主题模式</div>
<div class="setting-value">
<el-radio-group v-model="isDark" @change="handleThemeModeChange">
<el-radio :label="false">
<el-icon>
<Sunny />
</el-icon>
浅色
</el-radio>
<el-radio :label="true">
<el-icon>
<Moon />
</el-icon>
深色
</el-radio>
</el-radio-group>
</div>
</div>
<!-- 标签栏 -->
<div class="setting-item">
<div class="setting-title">
<span>显示标签栏</span>
<el-tooltip content="开启后页面顶部显示标签页" placement="top">
<el-icon>
<QuestionFilled />
</el-icon>
</el-tooltip>
</div>
<div class="setting-value">
<el-switch v-model="showTags" @change="handleShowTagsChange" />
</div>
</div>
<!-- 面包屑 -->
<div class="setting-item">
<div class="setting-title">
<span>显示面包屑</span>
<el-tooltip content="开启后页面顶部显示面包屑导航" placement="top">
<el-icon>
<QuestionFilled />
</el-icon>
</el-tooltip>
</div>
<div class="setting-value">
<el-switch v-model="showBreadcrumb" @change="handleShowBreadcrumbChange" />
</div>
</div>
<!-- 操作按钮 -->
<div class="setting-actions">
<el-button type="primary" @click="handleSave">
<el-icon>
<Check />
</el-icon>
保存配置
</el-button>
<el-button @click="handleReset">
<el-icon>
<RefreshLeft />
</el-icon>
重置默认
</el-button>
</div>
</div>
</el-drawer>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import {
Setting,
Sunny,
Moon,
QuestionFilled,
Check,
RefreshLeft,
} from '@element-plus/icons-vue'
import { useLayoutStore } from '@/stores/modules/layout'
defineOptions({
name: 'LayoutSetting',
})
const layoutStore = useLayoutStore()
// 抽屉显示状态
const showDrawer = ref(false)
// 预定义颜色
const predefineColors = [
'#1890ff',
'#409eff',
'#67c23a',
'#e6a23c',
'#f56c6c',
'#909399',
'#722ed1',
'#eb2f96',
'#52c41a',
'#1890ff',
'#2f54eb',
'#722ed1',
'#f5222d',
'#fa541c',
'#fa8c16',
'#faad14',
'#fadb14',
'#a0d911',
'#52c41a',
'#13c2c2',
'#1890ff',
'#2f54eb',
'#722ed1',
]
// 布局模式
const layoutMode = computed({
get: () => layoutStore.layoutMode,
set: (val) => layoutStore.setLayoutMode(val),
})
// 主题色
const themeColor = ref(layoutStore.themeColor)
// 主题模式(深色/浅色)
const isDark = ref(document.documentElement.classList.contains('dark'))
// 显示标签栏
const showTags = computed({
get: () => layoutStore.showTags,
set: (val) => layoutStore.setShowTags(val),
})
// 显示面包屑
const showBreadcrumb = computed({
get: () => layoutStore.showBreadcrumb,
set: (val) => layoutStore.setShowBreadcrumb(val),
})
// 布局模式变化
const handleLayoutModeChange = (value) => {
console.log('Layout mode changed:', value)
}
// 主题色变化
const handleThemeColorChange = (value) => {
if (value) {
layoutStore.setThemeColor(value)
}
}
// 预定义颜色点击
const handleColorPresetClick = (color) => {
themeColor.value = color
layoutStore.setThemeColor(color)
}
// 主题模式变化
const handleThemeModeChange = (value) => {
if (value) {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
}
// 标签栏显示变化
const handleShowTagsChange = (value) => {
layoutStore.setShowTags(value)
}
// 面包屑显示变化
const handleShowBreadcrumbChange = (value) => {
layoutStore.setShowBreadcrumb(value)
}
// 保存配置
const handleSave = () => {
ElMessage.success('配置已保存')
showDrawer.value = false
}
// 重置配置
const handleReset = () => {
layoutStore.resetTheme()
themeColor.value = layoutStore.themeColor
isDark.value = false
document.documentElement.classList.remove('dark')
ElMessage.success('已重置为默认配置')
}
// 初始化
onMounted(() => {
themeColor.value = layoutStore.themeColor
})
</script>
<style lang="scss" scoped>
.setting-container {
// 设置按钮
.setting-btn {
position: fixed;
top: 50%;
right: 0;
transform: translateY(-50%);
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
background: var(--el-color-primary);
color: #fff;
cursor: pointer;
border-radius: 6px 0 0 6px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 9999;
transition: all 0.3s;
.el-icon {
font-size: 20px;
}
&:hover {
width: 56px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
}
// 设置内容
.setting-content {
padding: 20px;
.setting-item {
margin-bottom: 24px;
.setting-title {
font-size: 14px;
font-weight: 500;
color: var(--el-text-color-primary);
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 4px;
.el-icon {
font-size: 14px;
color: var(--el-text-color-secondary);
cursor: help;
}
}
.setting-value {
// 布局选项
:deep(.el-radio-group) {
width: 100%;
display: flex;
flex-direction: column;
gap: 12px;
.el-radio {
margin-right: 0;
width: 100%;
}
.el-radio__label {
width: 100%;
padding-left: 0;
}
}
.layout-option {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
border: 2px solid var(--el-border-color);
border-radius: 8px;
transition: all 0.3s;
cursor: pointer;
&:hover {
border-color: var(--el-color-primary);
background-color: var(--el-fill-color-light);
}
span {
font-size: 14px;
color: var(--el-text-color-primary);
}
}
// 布局预览
.layout-preview {
width: 80px;
height: 60px;
background: var(--el-fill-color-blank);
border: 2px solid var(--el-border-color);
border-radius: 4px;
position: relative;
overflow: hidden;
&.layout-default {
.layout-aside-left {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 20px;
background: var(--el-color-primary-light-7);
}
.layout-aside-right {
position: absolute;
left: 20px;
top: 0;
bottom: 0;
width: 25px;
background: var(--el-color-primary-light-5);
}
.layout-main {
position: absolute;
right: 0;
top: 0;
bottom: 0;
left: 45px;
background: var(--el-fill-color-lighter);
}
}
&.layout-menu {
.layout-aside {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 25px;
background: var(--el-color-primary-light-5);
}
.layout-main {
position: absolute;
right: 0;
top: 0;
bottom: 0;
left: 25px;
background: var(--el-fill-color-lighter);
}
}
&.layout-top {
.layout-header {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 12px;
background: var(--el-color-primary-light-5);
}
.layout-main {
position: absolute;
right: 0;
top: 12px;
bottom: 0;
left: 0;
background: var(--el-fill-color-lighter);
}
}
}
// 颜色选择器
.color-picker-wrapper {
margin-bottom: 12px;
:deep(.el-color-picker__trigger) {
width: 100%;
height: 40px;
}
}
.color-presets {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 8px;
.color-preset {
width: 100%;
padding-bottom: 100%;
position: relative;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
border: 2px solid transparent;
&:hover {
transform: scale(1.1);
}
&.active {
border-color: var(--el-color-primary);
transform: scale(1.1);
}
}
}
}
}
// 操作按钮
.setting-actions {
margin-top: 32px;
padding-top: 20px;
border-top: 1px solid var(--el-border-color-light);
display: flex;
gap: 12px;
.el-button {
flex: 1;
}
}
}
}
</style>