feat(Layout): Add topLeft layout
This commit is contained in:
parent
839b6015b8
commit
71b1c5e10c
|
@ -83,12 +83,27 @@ export default defineComponent({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
:deep(.el-breadcrumb__item) {
|
:deep(.el-breadcrumb__item):not(:last-child) {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
.el-breadcrumb__inner {
|
.el-breadcrumb__inner {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
color: var(--top-header-text-color);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-breadcrumb__item):last-child {
|
||||||
|
.el-breadcrumb__inner {
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, unref } from 'vue'
|
import { computed, unref } from 'vue'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
color: propTypes.string.def('')
|
||||||
|
})
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
@ -17,6 +22,7 @@ const toggleCollapse = () => {
|
||||||
<Icon
|
<Icon
|
||||||
:size="18"
|
:size="18"
|
||||||
:icon="collapse ? 'ant-design:menu-unfold-outlined' : 'ant-design:menu-fold-outlined'"
|
:icon="collapse ? 'ant-design:menu-unfold-outlined' : 'ant-design:menu-fold-outlined'"
|
||||||
|
:color="color"
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
@click="toggleCollapse"
|
@click="toggleCollapse"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
import ColorRadioPicker from './src/ColorRadioPicker.vue'
|
|
||||||
|
|
||||||
export { ColorRadioPicker }
|
|
|
@ -3,6 +3,11 @@ import { computed, unref } from 'vue'
|
||||||
import { ElDropdown, ElDropdownMenu, ElDropdownItem } from 'element-plus'
|
import { ElDropdown, ElDropdownMenu, ElDropdownItem } from 'element-plus'
|
||||||
import { useLocaleStore } from '@/store/modules/locale'
|
import { useLocaleStore } from '@/store/modules/locale'
|
||||||
import { useLocale } from '@/hooks/web/useLocale'
|
import { useLocale } from '@/hooks/web/useLocale'
|
||||||
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
color: propTypes.string.def('')
|
||||||
|
})
|
||||||
|
|
||||||
const localeStore = useLocaleStore()
|
const localeStore = useLocaleStore()
|
||||||
|
|
||||||
|
@ -24,7 +29,13 @@ const setLang = (lang: LocaleType) => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ElDropdown trigger="click" @command="setLang">
|
<ElDropdown trigger="click" @command="setLang">
|
||||||
<Icon :size="18" icon="ion:language-sharp" class="cursor-pointer" :class="$attrs.class" />
|
<Icon
|
||||||
|
:size="18"
|
||||||
|
icon="ion:language-sharp"
|
||||||
|
class="cursor-pointer"
|
||||||
|
:class="$attrs.class"
|
||||||
|
:color="color"
|
||||||
|
/>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<ElDropdownMenu>
|
<ElDropdownMenu>
|
||||||
<ElDropdownItem v-for="item in langMap" :key="item.lang" :command="item.lang">
|
<ElDropdownItem v-for="item in langMap" :key="item.lang" :command="item.lang">
|
||||||
|
|
|
@ -41,7 +41,7 @@ watch(
|
||||||
{
|
{
|
||||||
'v-logo__Top': layout !== 'classic'
|
'v-logo__Top': layout !== 'classic'
|
||||||
},
|
},
|
||||||
'flex h-[var(--logo-height)] items-center cursor-pointer pl-8px relative'
|
'flex !h-[var(--logo-height)] items-center cursor-pointer pl-8px relative'
|
||||||
]"
|
]"
|
||||||
to="/"
|
to="/"
|
||||||
>
|
>
|
||||||
|
@ -49,9 +49,18 @@ watch(
|
||||||
src="@/assets/imgs/logo.png"
|
src="@/assets/imgs/logo.png"
|
||||||
class="w-[calc(var(--logo-height)-10px)] h-[calc(var(--logo-height)-10px)]"
|
class="w-[calc(var(--logo-height)-10px)] h-[calc(var(--logo-height)-10px)]"
|
||||||
/>
|
/>
|
||||||
<div v-if="show" class="text-[var(--logo-title-text-color)] ml-10px text-16px font-700">{{
|
<div
|
||||||
title
|
v-if="show"
|
||||||
}}</div>
|
:class="[
|
||||||
|
'ml-10px text-16px font-700',
|
||||||
|
{
|
||||||
|
'text-[var(--logo-title-text-color)]': layout === 'classic',
|
||||||
|
'text-[var(--top-header-text-color)]': layout === 'topLeft'
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
{{ title }}
|
||||||
|
</div>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -7,23 +7,19 @@ import type { LayoutType } from '@/config/app'
|
||||||
import { useRenderMenuItem } from './components/useRenderMenuItem'
|
import { useRenderMenuItem } from './components/useRenderMenuItem'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { isUrl } from '@/utils/is'
|
import { isUrl } from '@/utils/is'
|
||||||
import { Logo } from '@/components/Logo'
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Menu',
|
name: 'Menu',
|
||||||
setup() {
|
setup() {
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
// logo
|
|
||||||
const logo = computed(() => appStore.logo)
|
|
||||||
|
|
||||||
const { push, currentRoute } = useRouter()
|
const { push, currentRoute } = useRouter()
|
||||||
|
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
const menuMode = computed((): 'vertical' | 'horizontal' => {
|
const menuMode = computed((): 'vertical' | 'horizontal' => {
|
||||||
// 竖
|
// 竖
|
||||||
const vertical: LayoutType[] = ['classic']
|
const vertical: LayoutType[] = ['classic', 'topLeft']
|
||||||
|
|
||||||
if (vertical.includes(appStore.getLayout)) {
|
if (vertical.includes(appStore.getLayout)) {
|
||||||
return 'vertical'
|
return 'vertical'
|
||||||
|
@ -64,8 +60,7 @@ export default defineComponent({
|
||||||
'bg-[var(--left-menu-bg-color)]'
|
'bg-[var(--left-menu-bg-color)]'
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{logo.value ? <Logo></Logo> : undefined}
|
<ElScrollbar>
|
||||||
<ElScrollbar class={[{ '!h-[calc(100%-var(--logo-height))]': logo.value }]}>
|
|
||||||
<ElMenu
|
<ElMenu
|
||||||
defaultActive={unref(activeMenu)}
|
defaultActive={unref(activeMenu)}
|
||||||
mode={unref(menuMode)}
|
mode={unref(menuMode)}
|
||||||
|
@ -103,6 +98,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{prefix-cls} {
|
.@{prefix-cls} {
|
||||||
|
position: relative;
|
||||||
transition: width var(--transition-time-02);
|
transition: width var(--transition-time-02);
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Icon } from '@/components/Icon'
|
import { Icon } from '@/components/Icon'
|
||||||
import { useFullscreen } from '@vueuse/core'
|
import { useFullscreen } from '@vueuse/core'
|
||||||
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
color: propTypes.string.def('')
|
||||||
|
})
|
||||||
|
|
||||||
const { toggle, isFullscreen } = useFullscreen()
|
const { toggle, isFullscreen } = useFullscreen()
|
||||||
|
|
||||||
|
@ -11,6 +16,10 @@ const toggleFullscreen = () => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div @click="toggleFullscreen">
|
<div @click="toggleFullscreen">
|
||||||
<Icon :size="18" :icon="isFullscreen ? 'zmdi:fullscreen-exit' : 'zmdi:fullscreen'" />
|
<Icon
|
||||||
|
:size="18"
|
||||||
|
:icon="isFullscreen ? 'zmdi:fullscreen-exit' : 'zmdi:fullscreen'"
|
||||||
|
:color="color"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -3,12 +3,13 @@ import { ElDrawer, ElDivider } from 'element-plus'
|
||||||
import { ref, unref } from 'vue'
|
import { ref, unref } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
||||||
import { ColorRadioPicker } from '@/components/ColorRadioPicker'
|
|
||||||
import { colorIsDark, lighten, hexToRGB } from '@/utils/color'
|
import { colorIsDark, lighten, hexToRGB } from '@/utils/color'
|
||||||
import { useCssVar } from '@vueuse/core'
|
import { useCssVar } from '@vueuse/core'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import { trim, setCssVar } from '@/utils'
|
import { trim, setCssVar } from '@/utils'
|
||||||
|
import ColorRadioPicker from './components/ColorRadioPicker.vue'
|
||||||
import InterfaceDisplay from './components/InterfaceDisplay.vue'
|
import InterfaceDisplay from './components/InterfaceDisplay.vue'
|
||||||
|
import LayoutRadioPicker from './components/LayoutRadioPicker.vue'
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
@ -26,6 +27,23 @@ const setSystemTheme = (color: string) => {
|
||||||
setMenuTheme(trim(unref(leftMenuBgColor)))
|
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'
|
||||||
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 菜单主题相关
|
// 菜单主题相关
|
||||||
const menuTheme = ref(appStore.getTheme.leftMenuBgColor)
|
const menuTheme = ref(appStore.getTheme.leftMenuBgColor)
|
||||||
|
|
||||||
|
@ -81,6 +99,7 @@ const setMenuTheme = (color: string) => {
|
||||||
|
|
||||||
<!-- 布局 -->
|
<!-- 布局 -->
|
||||||
<ElDivider>{{ t('setting.layout') }}</ElDivider>
|
<ElDivider>{{ t('setting.layout') }}</ElDivider>
|
||||||
|
<LayoutRadioPicker />
|
||||||
|
|
||||||
<!-- 系统主题 -->
|
<!-- 系统主题 -->
|
||||||
<ElDivider>{{ t('setting.systemTheme') }}</ElDivider>
|
<ElDivider>{{ t('setting.systemTheme') }}</ElDivider>
|
||||||
|
@ -99,6 +118,23 @@ const setMenuTheme = (color: string) => {
|
||||||
@change="setSystemTheme"
|
@change="setSystemTheme"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- 头部主题 -->
|
||||||
|
<ElDivider>{{ t('setting.headerTheme') }}</ElDivider>
|
||||||
|
<ColorRadioPicker
|
||||||
|
v-model="headerTheme"
|
||||||
|
:schema="[
|
||||||
|
'#fff',
|
||||||
|
'#151515',
|
||||||
|
'#5172dc',
|
||||||
|
'#e74c3c',
|
||||||
|
'#24292e',
|
||||||
|
'#394664',
|
||||||
|
'#009688',
|
||||||
|
'#383f45'
|
||||||
|
]"
|
||||||
|
@change="setHeaderTheme"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 菜单主题 -->
|
<!-- 菜单主题 -->
|
||||||
<ElDivider>{{ t('setting.menuTheme') }}</ElDivider>
|
<ElDivider>{{ t('setting.menuTheme') }}</ElDivider>
|
||||||
<ColorRadioPicker
|
<ColorRadioPicker
|
||||||
|
|
|
@ -71,6 +71,13 @@ const logoChange = (show: boolean) => {
|
||||||
appStore.setLogo(show)
|
appStore.setLogo(show)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 固定头部
|
||||||
|
const fixedHeader = ref(appStore.getFixedHeader)
|
||||||
|
|
||||||
|
const fixedHeaderChange = (show: boolean) => {
|
||||||
|
appStore.setFixedHeader(show)
|
||||||
|
}
|
||||||
|
|
||||||
// 灰色模式
|
// 灰色模式
|
||||||
const greyMode = ref(appStore.getGreyMode)
|
const greyMode = ref(appStore.getGreyMode)
|
||||||
|
|
||||||
|
@ -126,6 +133,11 @@ const greyModeChange = (show: boolean) => {
|
||||||
<ElSwitch v-model="logo" @change="logoChange" />
|
<ElSwitch v-model="logo" @change="logoChange" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-14px">{{ t('setting.fixedHeader') }}</span>
|
||||||
|
<ElSwitch v-model="fixedHeader" @change="fixedHeaderChange" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<span class="text-14px">{{ t('setting.greyMode') }}</span>
|
<span class="text-14px">{{ t('setting.greyMode') }}</span>
|
||||||
<ElSwitch v-model="greyMode" @change="greyModeChange" />
|
<ElSwitch v-model="greyMode" @change="greyModeChange" />
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useAppStore } from '@/store/modules/app'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
const layout = computed(() => appStore.getLayout)
|
||||||
|
console.log(layout.value)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="v-layout-radio-picker flex flex-wrap space-x-14px">
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
'v-layout-radio-picker__classic relative w-56px h-48px cursor-pointer bg-gray-100',
|
||||||
|
{
|
||||||
|
'is-acitve': layout === 'classic'
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
@click="appStore.setLayout('classic')"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
'v-layout-radio-picker__top-left relative w-56px h-48px cursor-pointer bg-gray-100',
|
||||||
|
{
|
||||||
|
'is-acitve': layout === 'topLeft'
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
@click="appStore.setLayout('topLeft')"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@prefix-cls: ~'@{namespace}-layout-radio-picker';
|
||||||
|
|
||||||
|
.@{prefix-cls} {
|
||||||
|
&__classic {
|
||||||
|
border: 2px solid #e5e7eb;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1;
|
||||||
|
width: 33%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #273352;
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 25%;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px 4px 0 4px;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__top-left {
|
||||||
|
border: 2px solid #e5e7eb;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
height: 33%;
|
||||||
|
background-color: #273352;
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 33%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-acitve {
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -3,6 +3,12 @@ import { computed } from 'vue'
|
||||||
import { ElDropdown, ElDropdownMenu, ElDropdownItem } from 'element-plus'
|
import { ElDropdown, ElDropdownMenu, ElDropdownItem } from 'element-plus'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
color: propTypes.string.def('')
|
||||||
|
})
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
@ -16,12 +22,7 @@ const setCurrentSize = (size: ElememtPlusSzie) => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ElDropdown trigger="click" @command="setCurrentSize">
|
<ElDropdown trigger="click" @command="setCurrentSize">
|
||||||
<Icon
|
<Icon :size="18" icon="mdi:format-size" :color="color" class="cursor-pointer" />
|
||||||
:size="18"
|
|
||||||
icon="mdi:format-size"
|
|
||||||
color="var(--el-text-color-primary)"
|
|
||||||
class="cursor-pointer"
|
|
||||||
/>
|
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<ElDropdownMenu>
|
<ElDropdownMenu>
|
||||||
<ElDropdownItem v-for="item in sizeMap" :key="item" :command="item">
|
<ElDropdownItem v-for="item in sizeMap" :key="item" :command="item">
|
||||||
|
|
|
@ -125,8 +125,10 @@ watch(
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="v-tags-view h-[var(--tags-view-height)] flex w-full">
|
<div class="v-tags-view h-[var(--tags-view-height)] flex w-full relative">
|
||||||
<span class="v-tags-view__tool w-[40px] h-[40px] text-center leading-[40px] cursor-pointer">
|
<span
|
||||||
|
class="v-tags-view__tool w-[var(--tags-view-height)] h-[var(--tags-view-height)] text-center leading-[var(--tags-view-height)] cursor-pointer"
|
||||||
|
>
|
||||||
<Icon icon="ep:d-arrow-left" color="#333" />
|
<Icon icon="ep:d-arrow-left" color="#333" />
|
||||||
</span>
|
</span>
|
||||||
<div class="overflow-hidden flex-1">
|
<div class="overflow-hidden flex-1">
|
||||||
|
@ -215,11 +217,13 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
</ElScrollbar>
|
</ElScrollbar>
|
||||||
</div>
|
</div>
|
||||||
<span class="v-tags-view__tool w-[40px] h-[40px] text-center leading-[40px] cursor-pointer">
|
<span
|
||||||
|
class="v-tags-view__tool w-[var(--tags-view-height)] h-[var(--tags-view-height)] text-center leading-[var(--tags-view-height)] cursor-pointer"
|
||||||
|
>
|
||||||
<Icon icon="ep:d-arrow-right" color="#333" />
|
<Icon icon="ep:d-arrow-right" color="#333" />
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
class="v-tags-view__tool w-[40px] h-[40px] text-center leading-[40px] cursor-pointer"
|
class="v-tags-view__tool w-[var(--tags-view-height)] h-[var(--tags-view-height)] text-center leading-[var(--tags-view-height)] cursor-pointer"
|
||||||
@click="refreshSelectedTag(selectedTag)"
|
@click="refreshSelectedTag(selectedTag)"
|
||||||
>
|
>
|
||||||
<Icon icon="ant-design:reload-outlined" color="#333" />
|
<Icon icon="ant-design:reload-outlined" color="#333" />
|
||||||
|
@ -275,7 +279,7 @@ watch(
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="v-tags-view__tool w-[40px] h-[40px] text-center leading-[40px] cursor-pointer block"
|
class="v-tags-view__tool w-[var(--tags-view-height)] h-[var(--tags-view-height)] text-center leading-[var(--tags-view-height)] cursor-pointer block"
|
||||||
>
|
>
|
||||||
<Icon icon="ant-design:setting-outlined" color="#333" />
|
<Icon icon="ant-design:setting-outlined" color="#333" />
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -34,7 +34,7 @@ const loginOut = () => {
|
||||||
<ElDropdown trigger="click">
|
<ElDropdown trigger="click">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<img src="@/assets/imgs/avatar.png" alt="" class="w-[calc(var(--tags-view-height)-10px)]" />
|
<img src="@/assets/imgs/avatar.png" alt="" class="w-[calc(var(--tags-view-height)-10px)]" />
|
||||||
<span class="<lg:hidden text-14px pl-[5px] text-dark-50">Archer</span>
|
<span class="<lg:hidden text-14px pl-[5px] text-[var(--top-header-text-color)]">Archer</span>
|
||||||
</div>
|
</div>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<ElDropdownMenu>
|
<ElDropdownMenu>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { useCache } from '@/hooks/web/useCache'
|
||||||
|
|
||||||
const { wsCache } = useCache()
|
const { wsCache } = useCache()
|
||||||
|
|
||||||
export type LayoutType = 'classic' | 'leftTop' | 'top' | 'test'
|
export type LayoutType = 'classic' | 'topLeft' | 'leftTop' | 'top' | 'test'
|
||||||
|
|
||||||
export interface AppState {
|
export interface AppState {
|
||||||
breadcrumb: boolean
|
breadcrumb: boolean
|
||||||
|
@ -14,6 +14,7 @@ export interface AppState {
|
||||||
locale: boolean
|
locale: boolean
|
||||||
tagsView: boolean
|
tagsView: boolean
|
||||||
logo: boolean
|
logo: boolean
|
||||||
|
fixedHeader: boolean
|
||||||
greyMode: boolean
|
greyMode: boolean
|
||||||
|
|
||||||
layout: LayoutType
|
layout: LayoutType
|
||||||
|
@ -37,9 +38,10 @@ export const appModules: AppState = {
|
||||||
locale: true, // 多语言图标
|
locale: true, // 多语言图标
|
||||||
tagsView: true, // 标签页
|
tagsView: true, // 标签页
|
||||||
logo: true, // logo
|
logo: true, // logo
|
||||||
|
fixedHeader: true, // 固定toolheader
|
||||||
greyMode: false, // 是否开始灰色模式,用于特殊悼念日
|
greyMode: false, // 是否开始灰色模式,用于特殊悼念日
|
||||||
|
|
||||||
layout: 'classic', // layout布局
|
layout: wsCache.get('layout') || 'classic', // layout布局
|
||||||
title: 'butterfly-admin', // 标题
|
title: 'butterfly-admin', // 标题
|
||||||
logoTitle: 'ButterflyAdmin', // logo标题
|
logoTitle: 'ButterflyAdmin', // logo标题
|
||||||
userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
|
userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
|
||||||
|
@ -67,6 +69,12 @@ export const appModules: AppState = {
|
||||||
// logo字体颜色
|
// logo字体颜色
|
||||||
logoTitleTextColor: '#fff',
|
logoTitleTextColor: '#fff',
|
||||||
// logo边框颜色
|
// logo边框颜色
|
||||||
logoBorderColor: 'inherit'
|
logoBorderColor: 'inherit',
|
||||||
|
// 头部背景颜色
|
||||||
|
topHeaderBgColor: '#fff',
|
||||||
|
// 头部字体颜色
|
||||||
|
topHeaderTextColor: 'inherit',
|
||||||
|
// 头部悬停颜色
|
||||||
|
topHeaderHoverColor: '#f6f6f6'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,100 +1,50 @@
|
||||||
<script lang="tsx">
|
<script lang="tsx">
|
||||||
import { computed, defineComponent } from 'vue'
|
import { computed, defineComponent, unref } from 'vue'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import { Menu } from '@/components/Menu'
|
|
||||||
import { Collapse } from '@/components/Collapse'
|
|
||||||
import { LocaleDropdown } from '@/components/LocaleDropdown'
|
|
||||||
import { SizeDropdown } from '@/components/SizeDropdown'
|
|
||||||
import { UserInfo } from '@/components/UserInfo'
|
|
||||||
import { Screenfull } from '@/components/Screenfull'
|
|
||||||
import { Breadcrumb } from '@/components/Breadcrumb'
|
|
||||||
import { TagsView } from '@/components/TagsView'
|
|
||||||
import { Backtop } from '@/components/Backtop'
|
import { Backtop } from '@/components/Backtop'
|
||||||
import { Setting } from '@/components/Setting'
|
import { Setting } from '@/components/Setting'
|
||||||
import AppView from './components/AppView.vue'
|
import { useRenderLayout } from './components/useRenderLayout'
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
// 是否是移动端
|
// 是否是移动端
|
||||||
const mobile = computed(() => appStore.getMobile)
|
const mobile = computed(() => appStore.getMobile)
|
||||||
|
|
||||||
// 面包屑
|
|
||||||
const breadcrumb = computed(() => appStore.getBreadcrumb)
|
|
||||||
|
|
||||||
// 菜单折叠
|
// 菜单折叠
|
||||||
const collapse = computed(() => appStore.getCollapse)
|
const collapse = computed(() => appStore.getCollapse)
|
||||||
|
|
||||||
// 折叠图标
|
const layout = computed(() => appStore.getLayout)
|
||||||
const hamburger = computed(() => appStore.getHamburger)
|
|
||||||
|
|
||||||
// 全屏图标
|
|
||||||
const screenfull = computed(() => appStore.getScreenfull)
|
|
||||||
|
|
||||||
// 尺寸图标
|
|
||||||
const size = computed(() => appStore.getSize)
|
|
||||||
|
|
||||||
// 多语言图标
|
|
||||||
const locale = computed(() => appStore.getLocale)
|
|
||||||
|
|
||||||
// 标签页
|
|
||||||
const tagsView = computed(() => appStore.getTagsView)
|
|
||||||
|
|
||||||
const classSuffix = computed(() => appStore.getLayout)
|
|
||||||
|
|
||||||
const handleClickOutside = () => {
|
const handleClickOutside = () => {
|
||||||
appStore.setCollapse(true)
|
appStore.setCollapse(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const renderLayout = () => {
|
||||||
|
switch (unref(layout)) {
|
||||||
|
case 'classic':
|
||||||
|
const { renderClassic } = useRenderLayout()
|
||||||
|
return renderClassic()
|
||||||
|
case 'topLeft':
|
||||||
|
const { renderTopLeft } = useRenderLayout()
|
||||||
|
return renderTopLeft()
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Layout',
|
name: 'Layout',
|
||||||
setup() {
|
setup() {
|
||||||
return () => (
|
return () => (
|
||||||
<section class={['v-app', `v-app__${classSuffix.value}`, 'w-[100%] h-[100%] relative']}>
|
<section class={['v-app', `v-app__${layout.value}`, 'w-[100%] h-[100%] relative']}>
|
||||||
{mobile.value && !collapse.value ? (
|
{mobile.value && !collapse.value ? (
|
||||||
<div
|
<div
|
||||||
class="absolute top-0 left-0 w-full h-full opacity-30 z-99 bg-[var(--el-color-black)]"
|
class="absolute top-0 left-0 w-full h-full opacity-30 z-99 bg-[var(--el-color-black)]"
|
||||||
onClick={handleClickOutside}
|
onClick={handleClickOutside}
|
||||||
></div>
|
></div>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<Menu class="absolute top-0 left-0"></Menu>
|
|
||||||
<div
|
|
||||||
class={[
|
|
||||||
'v-app-right',
|
|
||||||
'absolute top-0 h-[100%]',
|
|
||||||
collapse.value
|
|
||||||
? 'w-[calc(100%-var(--left-menu-min-width))]'
|
|
||||||
: 'w-[calc(100%-var(--left-menu-max-width))]',
|
|
||||||
collapse.value
|
|
||||||
? 'left-[var(--left-menu-min-width)]'
|
|
||||||
: 'left-[var(--left-menu-max-width)]',
|
|
||||||
'<md:(!left-0 !w-[100%])'
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class={[
|
|
||||||
'v-app-right__tool',
|
|
||||||
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center justify-between'
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<div class="h-full flex items-center">
|
|
||||||
{hamburger.value ? <Collapse class="header__tigger"></Collapse> : undefined}
|
|
||||||
{breadcrumb.value ? <Breadcrumb class="<md:hidden"></Breadcrumb> : undefined}
|
|
||||||
</div>
|
|
||||||
<div class="h-full flex items-center">
|
|
||||||
{screenfull.value ? <Screenfull class="header__tigger"></Screenfull> : undefined}
|
|
||||||
{size.value ? <SizeDropdown class="header__tigger"></SizeDropdown> : undefined}
|
|
||||||
{locale.value ? <LocaleDropdown class="header__tigger"></LocaleDropdown> : undefined}
|
|
||||||
<UserInfo class="header__tigger"></UserInfo>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{tagsView.value ? (
|
|
||||||
<div class="v-app-right__tags-view relative">
|
|
||||||
<TagsView></TagsView>
|
|
||||||
</div>
|
|
||||||
) : undefined}
|
|
||||||
|
|
||||||
<AppView></AppView>
|
{renderLayout()}
|
||||||
</div>
|
|
||||||
|
|
||||||
<Backtop></Backtop>
|
<Backtop></Backtop>
|
||||||
|
|
||||||
|
@ -107,36 +57,4 @@ export default defineComponent({
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@prefix-cls: ~'@{namespace}-app';
|
@prefix-cls: ~'@{namespace}-app';
|
||||||
|
|
||||||
.header__tigger {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
padding: 1px 10px 0;
|
|
||||||
cursor: pointer;
|
|
||||||
align-items: center;
|
|
||||||
transition: background var(--transition-time-02);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.@{prefix-cls} {
|
|
||||||
&-right {
|
|
||||||
transition: left var(--transition-time-02);
|
|
||||||
|
|
||||||
&__tool,
|
|
||||||
&__tags-view {
|
|
||||||
&::after {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 1px;
|
|
||||||
border-top: 1px solid var(--top-tool-border-color);
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -10,15 +10,7 @@ const getCaches = computed((): string[] => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-scrollbar
|
<section class="p-[var(--app-content-padding)] w-[100%]">
|
||||||
:class="[
|
|
||||||
'v-content',
|
|
||||||
{
|
|
||||||
'!h-[calc(100%-var(--top-tool-height)-var(--tags-view-height))]': true
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<section class="p-[var(--app-content-padding)]">
|
|
||||||
<router-view>
|
<router-view>
|
||||||
<template #default="{ Component, route }">
|
<template #default="{ Component, route }">
|
||||||
<keep-alive :include="getCaches">
|
<keep-alive :include="getCaches">
|
||||||
|
@ -27,5 +19,4 @@ const getCaches = computed((): string[] => {
|
||||||
</template>
|
</template>
|
||||||
</router-view>
|
</router-view>
|
||||||
</section>
|
</section>
|
||||||
</el-scrollbar>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
<script lang="tsx">
|
||||||
|
import { defineComponent, computed } from 'vue'
|
||||||
|
import { Collapse } from '@/components/Collapse'
|
||||||
|
import { LocaleDropdown } from '@/components/LocaleDropdown'
|
||||||
|
import { SizeDropdown } from '@/components/SizeDropdown'
|
||||||
|
import { UserInfo } from '@/components/UserInfo'
|
||||||
|
import { Screenfull } from '@/components/Screenfull'
|
||||||
|
import { Breadcrumb } from '@/components/Breadcrumb'
|
||||||
|
import { useAppStore } from '@/store/modules/app'
|
||||||
|
|
||||||
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
// 面包屑
|
||||||
|
const breadcrumb = computed(() => appStore.getBreadcrumb)
|
||||||
|
|
||||||
|
// 折叠图标
|
||||||
|
const hamburger = computed(() => appStore.getHamburger)
|
||||||
|
|
||||||
|
// 全屏图标
|
||||||
|
const screenfull = computed(() => appStore.getScreenfull)
|
||||||
|
|
||||||
|
// 尺寸图标
|
||||||
|
const size = computed(() => appStore.getSize)
|
||||||
|
|
||||||
|
// 多语言图标
|
||||||
|
const locale = computed(() => appStore.getLocale)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'ToolHeader',
|
||||||
|
setup() {
|
||||||
|
return () => (
|
||||||
|
<div
|
||||||
|
class={[
|
||||||
|
'v-tool-header',
|
||||||
|
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center justify-between'
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<div class="h-full flex items-center">
|
||||||
|
{hamburger.value ? (
|
||||||
|
<Collapse class="hover-tigger" color="var(--top-header-text-color)"></Collapse>
|
||||||
|
) : undefined}
|
||||||
|
{breadcrumb.value ? <Breadcrumb class="<md:hidden"></Breadcrumb> : undefined}
|
||||||
|
</div>
|
||||||
|
<div class="h-full flex items-center">
|
||||||
|
{screenfull.value ? (
|
||||||
|
<Screenfull class="hover-tigger" color="var(--top-header-text-color)"></Screenfull>
|
||||||
|
) : undefined}
|
||||||
|
{size.value ? (
|
||||||
|
<SizeDropdown class="hover-tigger" color="var(--top-header-text-color)"></SizeDropdown>
|
||||||
|
) : undefined}
|
||||||
|
{locale.value ? (
|
||||||
|
<LocaleDropdown
|
||||||
|
class="hover-tigger"
|
||||||
|
color="var(--top-header-text-color)"
|
||||||
|
></LocaleDropdown>
|
||||||
|
) : undefined}
|
||||||
|
<UserInfo class="hover-tigger"></UserInfo>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@prefix-cls: ~'@{namespace}-tool-header';
|
||||||
|
|
||||||
|
.@{prefix-cls} {
|
||||||
|
transition: left var(--transition-time-02);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,155 @@
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useAppStore } from '@/store/modules/app'
|
||||||
|
import { Menu } from '@/components/Menu'
|
||||||
|
import { TagsView } from '@/components/TagsView'
|
||||||
|
import { Logo } from '@/components/Logo'
|
||||||
|
import AppView from './AppView.vue'
|
||||||
|
import ToolHeader from './ToolHeader.vue'
|
||||||
|
import { ElScrollbar } from 'element-plus'
|
||||||
|
|
||||||
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
// 标签页
|
||||||
|
const tagsView = computed(() => appStore.getTagsView)
|
||||||
|
|
||||||
|
// 菜单折叠
|
||||||
|
const collapse = computed(() => appStore.getCollapse)
|
||||||
|
|
||||||
|
// logo
|
||||||
|
const logo = computed(() => appStore.logo)
|
||||||
|
|
||||||
|
// 固定头部
|
||||||
|
const fixedHeader = computed(() => appStore.getFixedHeader)
|
||||||
|
|
||||||
|
// 是否是移动端
|
||||||
|
const mobile = computed(() => appStore.getMobile)
|
||||||
|
|
||||||
|
export const useRenderLayout = () => {
|
||||||
|
const renderClassic = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class={['absolute top-0 left-0 h-full', { '!fixed z-99': mobile.value }]}>
|
||||||
|
{logo.value ? (
|
||||||
|
<Logo
|
||||||
|
class={[
|
||||||
|
'bg-[var(--left-menu-bg-color)]',
|
||||||
|
{
|
||||||
|
'!pl-0': mobile.value && collapse.value,
|
||||||
|
'w-[var(--left-menu-min-width)]': appStore.getCollapse,
|
||||||
|
'w-[var(--left-menu-max-width)]': !appStore.getCollapse
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
style="transition: all var(--transition-time-02);"
|
||||||
|
></Logo>
|
||||||
|
) : undefined}
|
||||||
|
<Menu class={[{ '!h-[calc(100%-var(--logo-height))]': logo.value }]}></Menu>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class={[
|
||||||
|
'v-app-right',
|
||||||
|
'absolute top-0 h-[100%]',
|
||||||
|
{
|
||||||
|
'w-[calc(100%-var(--left-menu-min-width))] left-[var(--left-menu-min-width)]':
|
||||||
|
collapse.value && !mobile.value && !mobile.value,
|
||||||
|
'w-[calc(100%-var(--left-menu-max-width))] left-[var(--left-menu-max-width)]':
|
||||||
|
!collapse.value && !mobile.value && !mobile.value,
|
||||||
|
'fixed !w-full !left-0': mobile.value
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
style="transition: all var(--transition-time-02);"
|
||||||
|
>
|
||||||
|
<ElScrollbar
|
||||||
|
class={[
|
||||||
|
'v-content',
|
||||||
|
{
|
||||||
|
'!h-[calc(100%-var(--top-tool-height)-var(--tags-view-height))] mt-[calc(var(--top-tool-height)+var(--tags-view-height))]':
|
||||||
|
fixedHeader.value
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class={[
|
||||||
|
{
|
||||||
|
'fixed top-0 left-0 z-10': fixedHeader.value,
|
||||||
|
'w-[calc(100%-var(--left-menu-min-width))] left-[var(--left-menu-min-width)]':
|
||||||
|
collapse.value && fixedHeader.value && !mobile.value,
|
||||||
|
'w-[calc(100%-var(--left-menu-max-width))] left-[var(--left-menu-max-width)]':
|
||||||
|
!collapse.value && fixedHeader.value && !mobile.value,
|
||||||
|
'!w-full !left-0': mobile.value
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
style="transition: all var(--transition-time-02);"
|
||||||
|
>
|
||||||
|
<ToolHeader class="border-bottom bg-[var(--top-header-bg-color)]"></ToolHeader>
|
||||||
|
|
||||||
|
{tagsView.value ? <TagsView class="border-bottom"></TagsView> : undefined}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<AppView></AppView>
|
||||||
|
</ElScrollbar>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderTopLeft = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class="flex items-center bg-[var(--top-header-bg-color)]">
|
||||||
|
<Logo class="hover-tigger !pr-15px"></Logo>
|
||||||
|
|
||||||
|
<ToolHeader class="flex-1"></ToolHeader>
|
||||||
|
</div>
|
||||||
|
<div class="absolute top-[var(--logo-height)] left-0 w-full h-[calc(100%-var(--logo-height))] flex">
|
||||||
|
<Menu class="!h-full"></Menu>
|
||||||
|
<div
|
||||||
|
class={[
|
||||||
|
'v-app-right',
|
||||||
|
'h-[100%]',
|
||||||
|
{
|
||||||
|
'w-[calc(100%-var(--left-menu-min-width))] left-[var(--left-menu-min-width)]':
|
||||||
|
collapse.value,
|
||||||
|
'w-[calc(100%-var(--left-menu-max-width))] left-[var(--left-menu-max-width)]':
|
||||||
|
!collapse.value
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
style="transition: all var(--transition-time-02);"
|
||||||
|
>
|
||||||
|
<ElScrollbar
|
||||||
|
class={[
|
||||||
|
'v-content',
|
||||||
|
{
|
||||||
|
'!h-[calc(100%-var(--tags-view-height))] mt-[calc(var(--tags-view-height))]':
|
||||||
|
fixedHeader.value && tagsView.value
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{tagsView.value ? (
|
||||||
|
<TagsView
|
||||||
|
class={[
|
||||||
|
'border-bottom border-top',
|
||||||
|
{
|
||||||
|
'!fixed top-0 left-0 z-10': fixedHeader.value,
|
||||||
|
'w-[calc(100%-var(--left-menu-min-width))] left-[var(--left-menu-min-width)] mt-[var(--logo-height)]':
|
||||||
|
collapse.value && fixedHeader.value,
|
||||||
|
'w-[calc(100%-var(--left-menu-max-width))] left-[var(--left-menu-max-width)] mt-[var(--logo-height)]':
|
||||||
|
!collapse.value && fixedHeader.value
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
style="transition: all var(--transition-time-02);"
|
||||||
|
></TagsView>
|
||||||
|
) : undefined}
|
||||||
|
|
||||||
|
<AppView></AppView>
|
||||||
|
</ElScrollbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
renderClassic,
|
||||||
|
renderTopLeft
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,9 @@ export default {
|
||||||
localeIcon: 'Locale icon',
|
localeIcon: 'Locale icon',
|
||||||
tagsView: 'Tags view',
|
tagsView: 'Tags view',
|
||||||
logo: 'Logo',
|
logo: 'Logo',
|
||||||
greyMode: 'Grey mode'
|
greyMode: 'Grey mode',
|
||||||
|
fixedHeader: 'Fixed header',
|
||||||
|
headerTheme: 'Header theme'
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: 'Default',
|
default: 'Default',
|
||||||
|
|
|
@ -35,7 +35,9 @@ export default {
|
||||||
localeIcon: '多语言图标',
|
localeIcon: '多语言图标',
|
||||||
tagsView: '标签页',
|
tagsView: '标签页',
|
||||||
logo: '标志',
|
logo: '标志',
|
||||||
greyMode: '灰色模式'
|
greyMode: '灰色模式',
|
||||||
|
fixedHeader: '固定头部',
|
||||||
|
headerTheme: '头部主题'
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: '默认',
|
default: '默认',
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { useCache } from '@/hooks/web/useCache'
|
||||||
import { appModules } from '@/config/app'
|
import { appModules } from '@/config/app'
|
||||||
import type { AppState, LayoutType } from '@/config/app'
|
import type { AppState, LayoutType } from '@/config/app'
|
||||||
import { setCssVar, humpToUnderline } from '@/utils'
|
import { setCssVar, humpToUnderline } from '@/utils'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
const { wsCache } = useCache()
|
const { wsCache } = useCache()
|
||||||
|
|
||||||
|
@ -38,6 +39,9 @@ export const useAppStore = defineStore({
|
||||||
getLogo(): boolean {
|
getLogo(): boolean {
|
||||||
return this.logo
|
return this.logo
|
||||||
},
|
},
|
||||||
|
getFixedHeader(): boolean {
|
||||||
|
return this.fixedHeader
|
||||||
|
},
|
||||||
getGreyMode(): boolean {
|
getGreyMode(): boolean {
|
||||||
return this.greyMode
|
return this.greyMode
|
||||||
},
|
},
|
||||||
|
@ -98,12 +102,20 @@ export const useAppStore = defineStore({
|
||||||
setLogo(logo: boolean) {
|
setLogo(logo: boolean) {
|
||||||
this.logo = logo
|
this.logo = logo
|
||||||
},
|
},
|
||||||
|
setFixedHeader(fixedHeader: boolean) {
|
||||||
|
this.fixedHeader = fixedHeader
|
||||||
|
},
|
||||||
setGreyMode(greyMode: boolean) {
|
setGreyMode(greyMode: boolean) {
|
||||||
this.greyMode = greyMode
|
this.greyMode = greyMode
|
||||||
},
|
},
|
||||||
|
|
||||||
setLayout(layout: LayoutType) {
|
setLayout(layout: LayoutType) {
|
||||||
|
if (this.mobile && layout !== 'classic') {
|
||||||
|
ElMessage.warning('移动端模式下不支持切换其他布局')
|
||||||
|
return
|
||||||
|
}
|
||||||
this.layout = layout
|
this.layout = layout
|
||||||
|
wsCache.set('layout', this.layout)
|
||||||
},
|
},
|
||||||
setTitle(title: string) {
|
setTitle(title: string) {
|
||||||
this.title = title
|
this.title = title
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
.hover-tigger {
|
||||||
|
@apply flex h-full pt-1px px-10px cursor-pointer items-center;
|
||||||
|
transition: background var(--transition-time-02);
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--top-header-hover-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-bottom {
|
||||||
|
@apply relative;
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
border-top: 1px solid var(--top-tool-border-color);
|
||||||
|
@apply absolute bottom-0 left-0 w-full h-1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-top {
|
||||||
|
@apply relative;
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
border-top: 1px solid var(--top-tool-border-color);
|
||||||
|
@apply absolute top-0 left-0 w-full h-1px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1,2 @@
|
||||||
@import './var.css';
|
@import './var.css';
|
||||||
|
@import './common.less';
|
||||||
|
|
|
@ -30,13 +30,19 @@
|
||||||
/* logo end */
|
/* logo end */
|
||||||
|
|
||||||
/* header start */
|
/* header start */
|
||||||
|
--top-header-bg-color: '#fff';
|
||||||
|
|
||||||
|
--top-header-text-color: 'inherit';
|
||||||
|
|
||||||
|
--top-header-hover-color: #f6f6f6;
|
||||||
|
|
||||||
--top-tool-height: var(--logo-height);
|
--top-tool-height: var(--logo-height);
|
||||||
|
|
||||||
--top-tool-p-x: 0;
|
--top-tool-p-x: 0;
|
||||||
|
|
||||||
--top-tool-border-color: #eee;
|
--top-tool-border-color: #eee;
|
||||||
|
|
||||||
--tags-view-height: 40px;
|
--tags-view-height: 35px;
|
||||||
/* header start */
|
/* header start */
|
||||||
|
|
||||||
--app-content-padding: 20px;
|
--app-content-padding: 20px;
|
||||||
|
|
|
@ -132,7 +132,8 @@ const signIn = async () => {
|
||||||
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
||||||
})
|
})
|
||||||
permissionStore.setIsAddRouters(true)
|
permissionStore.setIsAddRouters(true)
|
||||||
push({ path: redirect.value || permissionStore.addRouters[0].path })
|
// push({ path: redirect.value || permissionStore.addRouters[0].path })
|
||||||
|
push({ path: permissionStore.addRouters[0].path })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
},
|
},
|
||||||
hmr: {
|
hmr: {
|
||||||
overlay: false
|
overlay: false
|
||||||
}
|
},
|
||||||
|
host: '0.0.0.0'
|
||||||
},
|
},
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
include: [
|
include: [
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { defineConfig } from 'windicss/helpers'
|
import { defineConfig } from 'windicss/helpers'
|
||||||
|
// import plugin from 'windicss/plugin'
|
||||||
|
|
||||||
// function range(size, startAt = 1) {
|
// function range(size, startAt = 1) {
|
||||||
// return Array.from(Array(size).keys()).map((i) => i + startAt)
|
// return Array.from(Array(size).keys()).map((i) => i + startAt)
|
||||||
|
@ -34,16 +35,33 @@ export default defineConfig({
|
||||||
// // ...range(50).map((i) => `ml-${i}px`)
|
// // ...range(50).map((i) => `ml-${i}px`)
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
// Plugin: [
|
// plugins: [
|
||||||
// require('@windicss/plugin-animations')({
|
// plugin(({ addComponents }) => {
|
||||||
// settings: {
|
// addComponents({
|
||||||
// animatedSpeed: 1000,
|
// '.hover-tigger': {
|
||||||
// heartBeatSpeed: 1000,
|
// display: 'flex',
|
||||||
// hingeSpeed: 2000,
|
// height: '100%',
|
||||||
// bounceInSpeed: 750,
|
// padding: '1px 10px 0',
|
||||||
// bounceOutSpeed: 750,
|
// cursor: 'pointer',
|
||||||
// animationDelaySpeed: 1000
|
// alignItems: 'center',
|
||||||
|
// transition: 'background var(--transition-time-02)',
|
||||||
|
// '&:hover': {
|
||||||
|
// backgroundColor: '#f6f6f6'
|
||||||
// }
|
// }
|
||||||
|
// },
|
||||||
|
// '.border-bottom': {
|
||||||
|
// position: 'relative',
|
||||||
|
// '&:after': {
|
||||||
|
// position: 'absolute',
|
||||||
|
// bottom: '0',
|
||||||
|
// left: '0',
|
||||||
|
// width: '100%',
|
||||||
|
// height: '1px',
|
||||||
|
// borderTop: '1px solid var(--top-tool-border-color)',
|
||||||
|
// content: ''
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
// })
|
// })
|
||||||
// ]
|
// ]
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue