400 lines
8.2 KiB
Vue
400 lines
8.2 KiB
Vue
<template>
|
|
<a-drawer
|
|
v-model:open="open"
|
|
title="布局配置"
|
|
placement="right"
|
|
:width="420"
|
|
>
|
|
<div class="setting-content">
|
|
<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"
|
|
:class="{
|
|
active: layoutStore.layoutMode === 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>
|
|
</div>
|
|
</div>
|
|
<div class="layout-name">{{ mode.label }}</div>
|
|
<CheckOutlined
|
|
v-if="layoutStore.layoutMode === mode.value"
|
|
class="check-icon"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<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)"
|
|
>
|
|
<CheckOutlined v-if="themeColor === color" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="setting-item">
|
|
<div class="setting-title">显示设置</div>
|
|
<div class="toggle-list">
|
|
<div class="toggle-item">
|
|
<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>
|
|
</a-drawer>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, watch, onMounted } from "vue";
|
|
import { message } from "ant-design-vue";
|
|
import { useLayoutStore } from "@/stores/modules/layout";
|
|
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: "默认布局" },
|
|
{ value: "menu", label: "菜单布局" },
|
|
{ value: "top", label: "顶部布局" },
|
|
];
|
|
|
|
const themeColors = [
|
|
"#1890ff",
|
|
"#f5222d",
|
|
"#fa541c",
|
|
"#faad14",
|
|
"#13c2c2",
|
|
"#52c41a",
|
|
"#2f54eb",
|
|
"#722ed1",
|
|
];
|
|
|
|
const openDrawer = () => {
|
|
open.value = true;
|
|
};
|
|
|
|
const closeDrawer = () => {
|
|
open.value = false;
|
|
};
|
|
|
|
defineExpose({
|
|
openDrawer,
|
|
closeDrawer,
|
|
});
|
|
|
|
// 切换布局
|
|
const handleLayoutChange = (mode) => {
|
|
layoutStore.setLayoutMode(mode);
|
|
const modeLabel = layoutModes.find((m) => m.value === mode)?.label || mode;
|
|
message.success(`已切换到${modeLabel}`);
|
|
};
|
|
|
|
// 切换主题颜色
|
|
const changeThemeColor = (color) => {
|
|
themeColor.value = color;
|
|
// 更新 CSS 变量
|
|
document.documentElement.style.setProperty("--primary-color", color);
|
|
message.success("主题颜色已更新");
|
|
};
|
|
|
|
// 切换标签栏显示
|
|
const handleShowTagsChange = (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">
|
|
.setting-content {
|
|
.setting-item {
|
|
margin-bottom: 32px;
|
|
|
|
.setting-title {
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
margin-bottom: 16px;
|
|
color: #333;
|
|
}
|
|
|
|
.layout-mode-list {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: 12px;
|
|
|
|
.layout-mode-item {
|
|
position: relative;
|
|
border: 2px solid #e8e8e8;
|
|
border-radius: 8px;
|
|
padding: 12px;
|
|
cursor: pointer;
|
|
transition: all 0.3s;
|
|
|
|
&:hover {
|
|
border-color: var(--primary-color, #1890ff);
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
&.active {
|
|
border-color: var(--primary-color, #1890ff);
|
|
background-color: rgba(24, 144, 255, 0.05);
|
|
}
|
|
|
|
.layout-preview {
|
|
width: 100%;
|
|
height: 60px;
|
|
border-radius: 4px;
|
|
margin-bottom: 8px;
|
|
overflow: hidden;
|
|
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;
|
|
}
|
|
|
|
.preview-sidebar-2 {
|
|
width: 24px;
|
|
}
|
|
}
|
|
|
|
&.preview-menu {
|
|
.preview-sidebar {
|
|
width: 30px;
|
|
background-color: #fff;
|
|
border-right: 1px solid #e8e8e8;
|
|
}
|
|
}
|
|
|
|
&.preview-top {
|
|
flex-direction: column;
|
|
|
|
.preview-sidebar {
|
|
width: 100%;
|
|
height: 12px;
|
|
background-color: #fff;
|
|
}
|
|
|
|
.preview-content {
|
|
.preview-header {
|
|
display: none;
|
|
}
|
|
|
|
.preview-body {
|
|
height: 100%;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.layout-name {
|
|
font-size: 12px;
|
|
color: #666;
|
|
text-align: center;
|
|
}
|
|
|
|
.check-icon {
|
|
position: absolute;
|
|
top: 4px;
|
|
right: 4px;
|
|
color: var(--primary-color, #1890ff);
|
|
font-size: 12px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.color-list {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 12px;
|
|
|
|
.color-item {
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.toggle-list {
|
|
.toggle-item {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 12px 0;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
span {
|
|
font-size: 14px;
|
|
color: #333;
|
|
}
|
|
}
|
|
}
|
|
|
|
.action-buttons {
|
|
:deep(.ant-btn) {
|
|
height: 40px;
|
|
font-size: 14px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|