完善后台布局

This commit is contained in:
2026-01-16 23:17:20 +08:00
parent 8cf5b446cf
commit b4c300bb32
9 changed files with 228 additions and 135 deletions

View File

@@ -4,11 +4,16 @@
<div class="setting-item">
<div class="setting-title">布局模式</div>
<div class="layout-mode-list">
<div v-for="mode in layoutModes" :key="mode.value" class="layout-mode-item"
<div
v-for="mode in layoutModes"
:key="mode.value"
class="layout-mode-item"
:class="{ active: layoutStore.layoutMode === mode.value }"
@click="handleLayoutChange(mode.value)">
@click="handleLayoutChange(mode.value)"
>
<div class="layout-preview" :class="`preview-${mode.value}`">
<div class="preview-sidebar"></div>
<div v-if="mode.value === 'default'" class="preview-sidebar-2"></div>
<div class="preview-content">
<div class="preview-header"></div>
<div class="preview-body"></div>
@@ -23,9 +28,14 @@
<div class="setting-item">
<div class="setting-title">主题颜色</div>
<div class="color-list">
<div v-for="color in themeColors" :key="color" class="color-item"
:class="{ active: themeColor === color }" :style="{ backgroundColor: color }"
@click="changeThemeColor(color)">
<div
v-for="color in themeColors"
:key="color"
class="color-item"
:class="{ active: themeColor === color }"
:style="{ backgroundColor: color }"
@click="changeThemeColor(color)"
>
<CheckOutlined v-if="themeColor === color" />
</div>
</div>
@@ -38,6 +48,20 @@
<span>显示标签栏</span>
<a-switch v-model:checked="showTags" @change="handleShowTagsChange" />
</div>
<div class="toggle-item">
<span>显示面包屑</span>
<a-switch v-model:checked="showBreadcrumb" @change="handleShowBreadcrumbChange" />
</div>
</div>
</div>
<div class="setting-item">
<div class="setting-title">其他设置</div>
<div class="action-buttons">
<a-button type="primary" block @click="handleResetSettings">
<ReloadOutlined />
重置设置
</a-button>
</div>
</div>
</div>
@@ -45,16 +69,22 @@
</template>
<script setup>
import { ref, defineExpose } from 'vue'
import { ref, defineExpose, defineOptions, watch, onMounted } from 'vue'
import { message } from 'ant-design-vue'
import { useLayoutStore } from '@/stores/modules/layout'
import { CheckOutlined } from '@ant-design/icons-vue'
import { CheckOutlined, ReloadOutlined } from '@ant-design/icons-vue'
// 定义组件名称(多词命名)
defineOptions({
name: 'LayoutSetting'
})
const layoutStore = useLayoutStore()
const open = ref(false)
const themeColor = ref('#1890ff')
const showTags = ref(true)
const showBreadcrumb = ref(true)
const layoutModes = [
{ value: 'default', label: '默认布局' },
@@ -96,15 +126,60 @@ const handleLayoutChange = (mode) => {
// 切换主题颜色
const changeThemeColor = (color) => {
themeColor.value = color
// 这里可以实现主题切换逻辑
// 更新 CSS 变量
document.documentElement.style.setProperty('--primary-color', color)
message.success('主题颜色已更新')
}
// 切换标签栏显示
const handleShowTagsChange = (checked) => {
// 这里可以实现标签栏显示/隐藏逻辑
console.log('showTags:', checked)
showTags.value = checked
// 触发自定义事件或更新状态
document.documentElement.style.setProperty('--show-tags', checked ? 'block' : 'none')
message.success(checked ? '标签栏已显示' : '标签栏已隐藏')
}
// 切换面包屑显示
const handleShowBreadcrumbChange = (checked) => {
showBreadcrumb.value = checked
message.success(checked ? '面包屑已显示' : '面包屑已隐藏')
}
// 重置设置
const handleResetSettings = () => {
themeColor.value = '#1890ff'
showTags.value = true
showBreadcrumb.value = true
layoutStore.setLayoutMode('default')
document.documentElement.style.setProperty('--primary-color', '#1890ff')
document.documentElement.style.setProperty('--show-tags', 'block')
message.success('设置已重置')
}
// 初始化
onMounted(() => {
// 从本地存储或其他地方恢复设置
const savedThemeColor = localStorage.getItem('themeColor')
if (savedThemeColor) {
themeColor.value = savedThemeColor
document.documentElement.style.setProperty('--primary-color', savedThemeColor)
}
const savedShowTags = localStorage.getItem('showTags')
if (savedShowTags !== null) {
showTags.value = savedShowTags === 'true'
document.documentElement.style.setProperty('--show-tags', savedShowTags === 'true' ? 'block' : 'none')
}
})
// 监听设置变化并保存到本地存储
watch(themeColor, (newVal) => {
localStorage.setItem('themeColor', newVal)
})
watch(showTags, (newVal) => {
localStorage.setItem('showTags', String(newVal))
})
</script>
<style scoped lang="scss">
@@ -133,11 +208,14 @@ const handleShowTagsChange = (checked) => {
transition: all 0.3s;
&:hover {
border-color: #1890ff;
border-color: var(--primary-color, #1890ff);
transform: translateY(-2px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
&.active {
border-color: #1890ff;
border-color: var(--primary-color, #1890ff);
background-color: rgba(24, 144, 255, 0.05);
}
.layout-preview {
@@ -149,32 +227,38 @@ const handleShowTagsChange = (checked) => {
display: flex;
background-color: #f0f2f5;
.preview-sidebar {
background-color: #001529;
}
.preview-sidebar-2 {
background-color: #fff;
border-left: 1px solid #e8e8e8;
}
.preview-content {
flex: 1;
padding: 4px;
.preview-header {
height: 8px;
background-color: #fff;
margin-bottom: 4px;
}
.preview-body {
height: calc(100% - 12px);
background-color: #e8e8e8;
}
}
&.preview-default {
.preview-sidebar {
width: 20px;
background-color: #001529;
}
.preview-sidebar-2 {
width: 24px;
background-color: #fff;
border-left: 1px solid #e8e8e8;
}
.preview-content {
flex: 1;
padding: 4px;
.preview-header {
height: 8px;
background-color: #fff;
margin-bottom: 4px;
}
.preview-body {
height: calc(100% - 12px);
background-color: #e8e8e8;
}
}
}
@@ -184,22 +268,6 @@ const handleShowTagsChange = (checked) => {
background-color: #fff;
border-right: 1px solid #e8e8e8;
}
.preview-content {
flex: 1;
padding: 4px;
.preview-header {
height: 8px;
background-color: #fff;
margin-bottom: 4px;
}
.preview-body {
height: calc(100% - 12px);
background-color: #e8e8e8;
}
}
}
&.preview-top {
@@ -212,16 +280,12 @@ const handleShowTagsChange = (checked) => {
}
.preview-content {
flex: 1;
padding: 4px;
.preview-header {
display: none;
}
.preview-body {
height: 100%;
background-color: #e8e8e8;
}
}
}
@@ -237,7 +301,7 @@ const handleShowTagsChange = (checked) => {
position: absolute;
top: 4px;
right: 4px;
color: #1890ff;
color: var(--primary-color, #1890ff);
font-size: 12px;
}
}
@@ -256,13 +320,17 @@ const handleShowTagsChange = (checked) => {
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.2s;
transition: all 0.2s;
border: 2px solid transparent;
&:hover {
transform: scale(1.1);
}
&.active {
border-color: #fff;
box-shadow: 0 0 0 2px var(--primary-color, #1890ff);
.anticon {
color: #fff;
}
@@ -288,6 +356,13 @@ const handleShowTagsChange = (checked) => {
}
}
}
.action-buttons {
:deep(.ant-btn) {
height: 40px;
font-size: 14px;
}
}
}
}
</style>