feat: 主题设置页面
This commit is contained in:
parent
e3773fd8b5
commit
bf7eaf4ae6
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a-drawer :width="340" :visible="props.systemOpen" @ok="handleOk" @cancel="handleCancel" unmount-on-close>
|
||||
<a-drawer :width="340" :visible="props.systemOpen" @ok="handleCancel" @cancel="handleCancel" unmount-on-close>
|
||||
<template #title> 系统设置 </template>
|
||||
<div>
|
||||
<div>
|
||||
@ -8,6 +8,10 @@
|
||||
<div>菜单折叠</div>
|
||||
<a-switch v-model="collapsed" />
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<div>菜单手风琴</div>
|
||||
<a-switch v-model="isAccordion" />
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<div>面包屑</div>
|
||||
<a-switch v-model="isBreadcrumb" />
|
||||
@ -25,23 +29,23 @@
|
||||
<div class="title">水印设置</div>
|
||||
<div class="flex-row">
|
||||
<div>水印颜色</div>
|
||||
<a-switch />
|
||||
<a-color-picker v-model="watermarkStyle.color" format="rgb" :history-colors="['#00000026']" />
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<div>水印文案</div>
|
||||
<a-input :style="{ width: '100px' }" default-value="content" placeholder="请输入" allow-clear />
|
||||
<a-input :style="{ width: '100px' }" v-model="watermark" placeholder="请输入" allow-clear />
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<div>水印大小</div>
|
||||
<a-slider :default-value="50" :style="{ width: '100px' }" />
|
||||
<a-slider v-model="watermarkStyle.fontSize" :min="10" :max="50" :style="{ width: '100px' }" />
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<div>水印角度</div>
|
||||
<a-slider :default-value="50" :style="{ width: '100px' }" />
|
||||
<a-slider v-model="watermarkRotate" :min="0" :max="360" :style="{ width: '100px' }" />
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<div>水印间隙</div>
|
||||
<a-slider :default-value="50" :style="{ width: '100px' }" />
|
||||
<a-slider :default-value="gapInfo[0]" :min="0" :max="300" :style="{ width: '100px' }" @change="onWatermarkGap" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -55,7 +59,8 @@ import { useThemeConfig } from "@/store/modules/theme-config";
|
||||
import { currentlyRoute } from "@/router/route-output";
|
||||
const themeStore = useThemeConfig();
|
||||
const routerStore = useRoutesListStore();
|
||||
const { collapsed, isBreadcrumb, isTabs, isFooter } = storeToRefs(themeStore);
|
||||
const { collapsed, isAccordion, isBreadcrumb, isTabs, isFooter, watermark, watermarkStyle, watermarkRotate, watermarkGap } =
|
||||
storeToRefs(themeStore);
|
||||
const { tabsList, cacheRoutes } = storeToRefs(routerStore);
|
||||
const route = useRoute();
|
||||
const props = defineProps({
|
||||
@ -64,9 +69,17 @@ const props = defineProps({
|
||||
default: false
|
||||
}
|
||||
});
|
||||
// 是否关闭tabs栏
|
||||
// 如果关闭,那么所有tabs全部取消、所有页面缓存全部取消
|
||||
// 如果开启,那么添加当前路由到tabs
|
||||
|
||||
const gapInfo = ref(watermarkGap.value);
|
||||
const onWatermarkGap = (e: number) => {
|
||||
watermarkGap.value = watermarkGap.value.map(() => e);
|
||||
};
|
||||
|
||||
/*
|
||||
是否关闭tabs栏
|
||||
如果关闭,那么所有tabs全部取消、所有页面缓存全部取消
|
||||
如果开启,那么添加当前路由到tabs
|
||||
*/
|
||||
const tabsChange = (e: Boolean) => {
|
||||
if (!e) {
|
||||
tabsList.value = [];
|
||||
@ -76,9 +89,6 @@ const tabsChange = (e: Boolean) => {
|
||||
}
|
||||
};
|
||||
const emits = defineEmits(["systemCancel"]);
|
||||
const handleOk = () => {
|
||||
emits("systemCancel");
|
||||
};
|
||||
const handleCancel = () => {
|
||||
emits("systemCancel");
|
||||
};
|
||||
|
||||
176
src/layout/components/Header/components/theme-settings/index.vue
Normal file
176
src/layout/components/Header/components/theme-settings/index.vue
Normal file
@ -0,0 +1,176 @@
|
||||
<template>
|
||||
<a-drawer :width="340" :visible="props.themeOpen" @ok="handleCancel" @cancel="handleCancel" unmount-on-close>
|
||||
<template #title> 主题设置 </template>
|
||||
<div>
|
||||
<div>
|
||||
<a-divider orientation="center">导航模式</a-divider>
|
||||
<div class="flex-common">
|
||||
<a-tooltip v-for="item in layoutList" :key="item.value" :content="item.label" position="top" mini>
|
||||
<div
|
||||
:class="layoutType === item.value ? `current-layout ${item.class}` : item.class"
|
||||
@click="layouetChange(item.value)"
|
||||
>
|
||||
<icon-check-circle-fill class="layout-icon" />
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a-divider orientation="center">主题设置</a-divider>
|
||||
<div class="flex-row">
|
||||
<div>主题色</div>
|
||||
<a-switch />
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<div>色弱模式</div>
|
||||
<a-switch />
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<div>灰色模式</div>
|
||||
<a-switch />
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<div>侧边栏深色</div>
|
||||
<a-switch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useThemeConfig } from "@/store/modules/theme-config";
|
||||
|
||||
const themeStore = useThemeConfig();
|
||||
const { layoutType } = storeToRefs(themeStore);
|
||||
|
||||
const layoutList = reactive({
|
||||
layoutDefaults: {
|
||||
value: "layoutDefaults",
|
||||
label: "默认布局",
|
||||
class: "layout-defaults"
|
||||
},
|
||||
layoutHead: {
|
||||
value: "layoutHead",
|
||||
label: "横向布局",
|
||||
class: "layout-head"
|
||||
},
|
||||
layoutMixing: {
|
||||
value: "layoutMixing",
|
||||
label: "混合布局",
|
||||
class: "layout-mixing"
|
||||
}
|
||||
});
|
||||
|
||||
const layouetChange = (type: string) => {
|
||||
layoutType.value = type;
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
themeOpen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["themeCancel"]);
|
||||
const handleCancel = () => {
|
||||
emits("themeCancel");
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box-gap {
|
||||
margin-top: $margin;
|
||||
}
|
||||
.flex-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: $margin;
|
||||
}
|
||||
.flex-common {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: $margin;
|
||||
}
|
||||
|
||||
.layout-defaults,
|
||||
.layout-head,
|
||||
.layout-mixing {
|
||||
width: 70px;
|
||||
height: 50px;
|
||||
margin-right: $margin;
|
||||
background: $color-fill-1;
|
||||
border-radius: $radius-box;
|
||||
overflow: hidden;
|
||||
box-shadow: $shadow-special;
|
||||
.layout-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.current-layout {
|
||||
position: relative;
|
||||
.layout-icon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
font-size: $font-size-body-3;
|
||||
color: $color-primary;
|
||||
}
|
||||
}
|
||||
.layout-defaults {
|
||||
position: relative;
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 20px;
|
||||
height: 100%;
|
||||
background: #232324;
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 50px;
|
||||
height: 15px;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
.layout-head {
|
||||
position: relative;
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 15px;
|
||||
background: #232324;
|
||||
}
|
||||
}
|
||||
.layout-mixing {
|
||||
position: relative;
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 15px;
|
||||
background: #232324;
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 15px;
|
||||
width: 20px;
|
||||
height: calc(100% - 15px);
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -63,7 +63,7 @@
|
||||
</a-tooltip>
|
||||
<!-- 主题设置 -->
|
||||
<a-tooltip :content="$t(`language.theme-settings`)">
|
||||
<a-button size="mini" type="text" class="icon_btn">
|
||||
<a-button size="mini" type="text" class="icon_btn" @click="onThemeSetting">
|
||||
<template #icon>
|
||||
<icon-skin :size="18" />
|
||||
</template>
|
||||
@ -112,12 +112,14 @@
|
||||
</a-dropdown>
|
||||
</div>
|
||||
<SystemSettings :system-open="systemOpen" @system-cancel="systemOpen = false" />
|
||||
<ThemeSettings :theme-open="themeOpen" @theme-cancel="themeOpen = false" />
|
||||
</a-layout-header>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import Notice from "@/layout/components/Header/components/notice/index.vue";
|
||||
import Breadcrumb from "@/layout/components/Header/components/breadcrumb/index.vue";
|
||||
import SystemSettings from "@/layout/components/Header/components/system-settings/index.vue";
|
||||
import ThemeSettings from "@/layout/components/Header/components/theme-settings/index.vue";
|
||||
import myImage from "@/assets/img/my-image.jpg";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { Modal } from "@arco-design/web-vue";
|
||||
@ -140,6 +142,12 @@ const systemOpen = ref(false);
|
||||
const onSystemSetting = () => {
|
||||
systemOpen.value = true;
|
||||
};
|
||||
|
||||
// 主题设置
|
||||
const themeOpen = ref(false);
|
||||
const onThemeSetting = () => {
|
||||
themeOpen.value = true;
|
||||
};
|
||||
// 全屏
|
||||
const fullScreen = ref(true);
|
||||
const onFullScreen = () => {
|
||||
|
||||
@ -1,18 +1,20 @@
|
||||
<template>
|
||||
<a-layout-content :class="isFooter ? 'content' : 'content-no-footer'">
|
||||
<Tabs v-if="isTabs" />
|
||||
<a-scrollbar style="height: 100%; overflow: auto" :outer-class="isTabs ? 'scrollbar' : 'scrollbar-no-tabs'">
|
||||
<div class="main">
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<MainTransition>
|
||||
<keep-alive :include="cacheRoutes">
|
||||
<component :is="Component" :key="route.name" v-if="refreshPage" />
|
||||
</keep-alive>
|
||||
</MainTransition>
|
||||
</router-view>
|
||||
</div>
|
||||
</a-scrollbar>
|
||||
</a-layout-content>
|
||||
<a-watermark :content="watermark" v-bind="watermarkConfig">
|
||||
<a-layout-content :class="isFooter ? 'content' : 'content-no-footer'">
|
||||
<Tabs v-if="isTabs" />
|
||||
<a-scrollbar style="height: 100%; overflow: auto" :outer-class="isTabs ? 'scrollbar' : 'scrollbar-no-tabs'">
|
||||
<div class="main">
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<MainTransition>
|
||||
<keep-alive :include="cacheRoutes">
|
||||
<component :is="Component" :key="route.name" v-if="refreshPage" />
|
||||
</keep-alive>
|
||||
</MainTransition>
|
||||
</router-view>
|
||||
</div>
|
||||
</a-scrollbar>
|
||||
</a-layout-content>
|
||||
</a-watermark>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@ -21,9 +23,22 @@ import { storeToRefs } from "pinia";
|
||||
import { useThemeConfig } from "@/store/modules/theme-config";
|
||||
import { useRoutesListStore } from "@/store/modules/route-list";
|
||||
const themeStore = useThemeConfig();
|
||||
let { refreshPage, isTabs, isFooter } = storeToRefs(themeStore);
|
||||
let { refreshPage, isTabs, isFooter, watermark, watermarkStyle, watermarkRotate, watermarkGap } = storeToRefs(themeStore);
|
||||
const routerStore = useRoutesListStore();
|
||||
const { cacheRoutes } = storeToRefs(routerStore);
|
||||
|
||||
// 水印配置
|
||||
const watermarkConfig = computed(() => {
|
||||
return {
|
||||
font: watermarkStyle.value,
|
||||
rotate: watermarkRotate.value,
|
||||
gap: watermarkGap.value
|
||||
};
|
||||
});
|
||||
|
||||
watch(watermarkConfig, newv => {
|
||||
console.log(newv);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -2,8 +2,9 @@
|
||||
<a-menu
|
||||
breakpoint="xl"
|
||||
:collapsed="collapsed"
|
||||
:auto-scroll-into-view="true"
|
||||
:auto-open-selected="true"
|
||||
:accordion="true"
|
||||
:accordion="isAccordion"
|
||||
:selected-keys="[currentRoute.name]"
|
||||
@menu-item-click="onMenuItem"
|
||||
>
|
||||
@ -22,7 +23,7 @@ const router = useRouter();
|
||||
const routerStore = useRoutesListStore();
|
||||
const { routeTree, currentRoute } = storeToRefs(routerStore);
|
||||
const themeStore = useThemeConfig();
|
||||
const { collapsed } = storeToRefs(themeStore);
|
||||
const { collapsed, isAccordion } = storeToRefs(themeStore);
|
||||
|
||||
/**
|
||||
* @description 菜单点击事件
|
||||
|
||||
@ -1,17 +1,24 @@
|
||||
<template>
|
||||
<div>
|
||||
<LangProvider>
|
||||
<component :is="layouts['defaults']" />
|
||||
<component :is="layouts[layoutType]" />
|
||||
</LangProvider>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useThemeConfig } from "@/store/modules/theme-config";
|
||||
import { loadingPage } from "@/utils/loading-page";
|
||||
|
||||
const themeStore = useThemeConfig();
|
||||
const { layoutType } = storeToRefs(themeStore);
|
||||
|
||||
// 引入组件-异步组件
|
||||
const layouts = {
|
||||
defaults: defineAsyncComponent(() => import("@/layout/layout-defaults/index.vue")),
|
||||
mixing: defineAsyncComponent(() => import("@/layout/layout-mixing/index.vue"))
|
||||
const layouts: any = {
|
||||
layoutDefaults: defineAsyncComponent(() => import("@/layout/layout-defaults/index.vue")),
|
||||
layoutHead: defineAsyncComponent(() => import("@/layout/layout-head/index.vue")),
|
||||
layoutMixing: defineAsyncComponent(() => import("@/layout/layout-mixing/index.vue"))
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
7
src/layout/layout-head/index.vue
Normal file
7
src/layout/layout-head/index.vue
Normal file
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div>头部布局</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -215,7 +215,7 @@ export const dynamicRoutes: RouteRecordRaw[] = [
|
||||
title: "about-project",
|
||||
hide: false,
|
||||
keepAlive: true,
|
||||
affix: true,
|
||||
affix: false,
|
||||
link: "",
|
||||
iframe: false,
|
||||
roles: ["admin", "common"],
|
||||
|
||||
@ -1,5 +1,22 @@
|
||||
import { defineStore } from "pinia";
|
||||
import persistedstateConfig from "@/store/config/index";
|
||||
|
||||
interface ThemeConfig {
|
||||
collapsed: Boolean;
|
||||
refreshPage: Boolean;
|
||||
language: string;
|
||||
darkMode: Boolean;
|
||||
isAccordion: Boolean;
|
||||
isBreadcrumb: Boolean;
|
||||
isTabs: Boolean;
|
||||
isFooter: Boolean;
|
||||
watermark: string;
|
||||
watermarkStyle: any;
|
||||
watermarkRotate: number;
|
||||
watermarkGap: Array<number>;
|
||||
layoutType: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局配置
|
||||
* @methods setCollapsed 设置菜单折叠
|
||||
@ -7,14 +24,23 @@ import persistedstateConfig from "@/store/config/index";
|
||||
* @methods setLanguage 设置语言
|
||||
*/
|
||||
export const useThemeConfig = defineStore("theme-config", {
|
||||
state: (): any => ({
|
||||
state: (): ThemeConfig => ({
|
||||
collapsed: false, // 是否折叠菜单
|
||||
refreshPage: true, // 刷新页面
|
||||
language: "zh-CN", // 系统语言
|
||||
darkMode: false, // 黑暗模式
|
||||
isAccordion: true, // 菜单手风琴
|
||||
isBreadcrumb: true, // 面包屑渲染
|
||||
isTabs: true, // 标签栏渲染
|
||||
isFooter: true // 页脚渲染
|
||||
isFooter: true, // 页脚渲染
|
||||
watermark: "dc admin", // 水印
|
||||
watermarkStyle: {
|
||||
fontSize: 12,
|
||||
color: "rgba(0, 0, 0, 0.15)"
|
||||
}, // 水印风格
|
||||
watermarkRotate: 330, // 水印角度
|
||||
watermarkGap: [100, 100], // 水印间隙
|
||||
layoutType: "layoutDefaults" // 布局模式:layoutDefaults、layoutHead、layoutMixing
|
||||
}),
|
||||
actions: {
|
||||
// 折叠菜单
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user