refactor: tailwindcss样式优化
Former-commit-id: 3ab444012a3b3f81929830d5c73df8c68437cb87
This commit is contained in:
@@ -1,12 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-breadcrumb class="app-breadcrumb" separator-class="el-icon-arrow-right">
|
<el-breadcrumb
|
||||||
|
separator-class="el-icon-arrow-right"
|
||||||
|
class="h-[50px] flex items-center"
|
||||||
|
>
|
||||||
<transition-group name="breadcrumb">
|
<transition-group name="breadcrumb">
|
||||||
<el-breadcrumb-item v-for="(item, index) in breadcrumbs" :key="item.path">
|
<el-breadcrumb-item v-for="(item, index) in breadcrumbs" :key="item.path">
|
||||||
<span
|
<span
|
||||||
v-if="
|
v-if="
|
||||||
item.redirect === 'noredirect' || index === breadcrumbs.length - 1
|
item.redirect === 'noredirect' || index === breadcrumbs.length - 1
|
||||||
"
|
"
|
||||||
class="no-redirect"
|
class="text-[#97a8be]"
|
||||||
>{{ generateTitle(item.meta.title) }}</span
|
>{{ generateTitle(item.meta.title) }}</span
|
||||||
>
|
>
|
||||||
<a v-else @click.prevent="handleLink(item)">
|
<a v-else @click.prevent="handleLink(item)">
|
||||||
@@ -88,11 +91,6 @@ onBeforeMount(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.el-breadcrumb__inner,
|
|
||||||
.el-breadcrumb__inner a {
|
|
||||||
font-weight: 400 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-breadcrumb.el-breadcrumb {
|
.app-breadcrumb.el-breadcrumb {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="padding: 0 15px" @click="toggleClick">
|
<div
|
||||||
|
@click="toggleClick"
|
||||||
|
class="px-[15px] hover:bg-gray-50 cursor-pointer h-[50px] leading-[50px]"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
:class="{ 'is-active': isActive }"
|
:class="{ 'is-active': isActive }"
|
||||||
class="hamburger"
|
class="hamburger"
|
||||||
viewBox="0 0 1024 1024"
|
viewBox="0 0 1024 1024"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="64"
|
|
||||||
height="64"
|
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
|
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
|
||||||
@@ -33,8 +34,6 @@ function toggleClick() {
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.hamburger {
|
.hamburger {
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function handleLanguageChange(lang: string) {
|
|||||||
trigger="click"
|
trigger="click"
|
||||||
@command="handleLanguageChange"
|
@command="handleLanguageChange"
|
||||||
>
|
>
|
||||||
<div class="lang-select__icon">
|
<div class="cursor-pointer w-[40px] h-[50px] leading-[50px] text-center">
|
||||||
<svg-icon class-name="international-icon" icon-class="language" />
|
<svg-icon class-name="international-icon" icon-class="language" />
|
||||||
</div>
|
</div>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
@@ -42,9 +42,3 @@ function handleLanguageChange(lang: string) {
|
|||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.lang-select__icon {
|
|
||||||
line-height: 50px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="cursor-pointer w-[40px] h-[50px] leading-[50px] text-center">
|
||||||
<svg-icon
|
<svg-icon
|
||||||
:icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'"
|
:icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'"
|
||||||
@click="toggle"
|
@click="toggle"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ function handleSizeChange(size: string) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-dropdown trigger="click" @command="handleSizeChange">
|
<el-dropdown trigger="click" @command="handleSizeChange">
|
||||||
<div style="line-height: 50px">
|
<div class="cursor-pointerw-[40px] h-[50px] leading-[50px] text-center">
|
||||||
<svg-icon icon-class="size" />
|
<svg-icon icon-class="size" />
|
||||||
</div>
|
</div>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ const symbolId = computed(() => `#${props.prefix}-${props.iconClass}`);
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
vertical-align: -0.15em;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,12 +40,3 @@ const tagsViewStore = useTagsViewStore();
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
// fix css style bug in open el-dialog
|
|
||||||
.el-popup-parent--hidden {
|
|
||||||
.fixed-header {
|
|
||||||
padding-right: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -3,20 +3,23 @@ import { computed } from 'vue';
|
|||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { ElMessageBox } from 'element-plus';
|
import { ElMessageBox } from 'element-plus';
|
||||||
|
|
||||||
import Breadcrumb from '@/components/Breadcrumb/index.vue';
|
|
||||||
import Hamburger from '@/components/Hamburger/index.vue';
|
import Hamburger from '@/components/Hamburger/index.vue';
|
||||||
|
import Breadcrumb from '@/components/Breadcrumb/index.vue';
|
||||||
import Screenfull from '@/components/Screenfull/index.vue';
|
import Screenfull from '@/components/Screenfull/index.vue';
|
||||||
import SizeSelect from '@/components/SizeSelect/index.vue';
|
import SizeSelect from '@/components/SizeSelect/index.vue';
|
||||||
import LangSelect from '@/components/LangSelect/index.vue';
|
import LangSelect from '@/components/LangSelect/index.vue';
|
||||||
|
import MixNav from './Sidebar/MixNav.vue';
|
||||||
import { CaretBottom } from '@element-plus/icons-vue';
|
import { CaretBottom } from '@element-plus/icons-vue';
|
||||||
|
|
||||||
import { useAppStore, DeviceType } from '@/store/modules/app';
|
import { useAppStore } from '@/store/modules/app';
|
||||||
import { useTagsViewStore } from '@/store/modules/tagsView';
|
import { useTagsViewStore } from '@/store/modules/tagsView';
|
||||||
import { useUserStore } from '@/store/modules/user';
|
import { useUserStore } from '@/store/modules/user';
|
||||||
|
import { useSettingsStore } from '@/store/modules/settings';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const tagsViewStore = useTagsViewStore();
|
const tagsViewStore = useTagsViewStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
const settingsStore = useSettingsStore();
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -47,31 +50,44 @@ function logout() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="navbar">
|
<div class="navbar">
|
||||||
<hamburger
|
<div
|
||||||
id="hamburger-container"
|
class="flex justify-start"
|
||||||
:is-active="appStore.sidebar.opened"
|
v-if="device === 'mobile' || settingsStore.layout === 'left'"
|
||||||
class="hamburger-container"
|
>
|
||||||
@toggleClick="toggleSideBar"
|
<hamburger
|
||||||
/>
|
:is-active="appStore.sidebar.opened"
|
||||||
|
@toggleClick="toggleSideBar"
|
||||||
|
/>
|
||||||
|
<!-- 面包屑导航栏 -->
|
||||||
|
<breadcrumb />
|
||||||
|
</div>
|
||||||
|
|
||||||
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" />
|
<mix-nav v-if="device !== 'mobile' && settingsStore.layout === 'mix'" />
|
||||||
|
|
||||||
<div class="right-menu">
|
<div
|
||||||
<template v-if="device !== DeviceType.mobile">
|
v-if="device === 'mobile' || settingsStore.layout === 'left'"
|
||||||
<screenfull id="screenfull" class="right-menu-item hover-effect" />
|
class="flex justify-start"
|
||||||
|
>
|
||||||
|
<div v-if="device !== 'mobile'" class="flex justify-center items-center">
|
||||||
|
<!--全屏 -->
|
||||||
|
<screenfull id="screenfull" />
|
||||||
|
|
||||||
|
<!-- 布局大小 -->
|
||||||
<el-tooltip content="布局大小" effect="dark" placement="bottom">
|
<el-tooltip content="布局大小" effect="dark" placement="bottom">
|
||||||
<size-select id="size-select" class="right-menu-item hover-effect" />
|
<size-select />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<lang-select class="right-menu-item hover-effect" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<el-dropdown
|
<!--语言选择-->
|
||||||
class="avatar-container right-menu-item hover-effect"
|
<lang-select />
|
||||||
trigger="click"
|
</div>
|
||||||
>
|
|
||||||
<div class="avatar-wrapper">
|
<el-dropdown trigger="click">
|
||||||
<img :src="userStore.avatar + '?imageView2/1/w/80/h/80'" />
|
<div class="flex justify-center items-center pr-[20px]">
|
||||||
<CaretBottom style="width: 0.6em; height: 0.6em; margin-left: 5px" />
|
<img
|
||||||
|
:src="userStore.avatar + '?imageView2/1/w/80/h/80'"
|
||||||
|
class="w-[40px] h-[40px] rounded-lg"
|
||||||
|
/>
|
||||||
|
<CaretBottom class="w-3 h-3" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
@@ -99,85 +115,15 @@ function logout() {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
ul {
|
.el-dropdown {
|
||||||
list-style: none;
|
font-size: 18px;
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
overflow: hidden;
|
display: flex;
|
||||||
position: relative;
|
align-items: center;
|
||||||
background: #fff;
|
justify-content: space-between;
|
||||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
box-shadow: 0 0px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
|
||||||
.hamburger-container {
|
|
||||||
line-height: 46px;
|
|
||||||
height: 100%;
|
|
||||||
float: left;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.3s;
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: rgba(0, 0, 0, 0.025);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.breadcrumb-container {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right-menu {
|
|
||||||
float: right;
|
|
||||||
height: 100%;
|
|
||||||
line-height: 50px;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right-menu-item {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 0 8px;
|
|
||||||
height: 100%;
|
|
||||||
font-size: 18px;
|
|
||||||
color: #5a5e66;
|
|
||||||
vertical-align: text-bottom;
|
|
||||||
|
|
||||||
&.hover-effect {
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.3s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: rgba(0, 0, 0, 0.025);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar-container {
|
|
||||||
margin-right: 30px;
|
|
||||||
|
|
||||||
.avatar-wrapper {
|
|
||||||
margin-top: 5px;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
img {
|
|
||||||
cursor: pointer;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-icon-caret-bottom {
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
right: -20px;
|
|
||||||
top: 25px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,25 +1,34 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { Sunny, Moon } from '@element-plus/icons-vue';
|
||||||
|
|
||||||
import { useSettingsStore } from '@/store/modules/settings';
|
import { useSettingsStore } from '@/store/modules/settings';
|
||||||
|
|
||||||
import ThemePicker from '@/components/ThemePicker/index.vue';
|
import { useDark, useToggle } from '@vueuse/core';
|
||||||
|
import { ElDivider, ElSwitch, ElTooltip } from 'element-plus';
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
|
const isDark = useDark();
|
||||||
|
|
||||||
function themeChange(val: string) {
|
function toggleTheme() {
|
||||||
settingsStore.changeSetting({ key: 'theme', value: val });
|
const isDark = useDark();
|
||||||
|
useToggle(isDark);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.document.body.setAttribute('layout', settingsStore.layout);
|
||||||
|
});
|
||||||
|
|
||||||
|
function changeLayout(layout: string) {
|
||||||
|
settingsStore.changeSetting({ key: 'layout', value: layout });
|
||||||
|
window.document.body.setAttribute('layout', settingsStore.layout);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="drawer-container">
|
<div class="settings-container">
|
||||||
<h3 class="drawer-title">系统布局配置</h3>
|
<h3 class="text-base font-bold">项目配置</h3>
|
||||||
<div class="drawer-item">
|
<el-divider />
|
||||||
<span>主题颜色</span>
|
|
||||||
<div style="float: right; height: 26px; margin: -3px 8px 0 0">
|
|
||||||
<theme-picker @change="themeChange" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="drawer-item">
|
<div class="drawer-item">
|
||||||
<span>开启 Tags-View</span>
|
<span>开启 Tags-View</span>
|
||||||
<el-switch v-model="settingsStore.tagsView" class="drawer-switch" />
|
<el-switch v-model="settingsStore.tagsView" class="drawer-switch" />
|
||||||
@@ -35,23 +44,53 @@ function themeChange(val: string) {
|
|||||||
<el-switch v-model="settingsStore.sidebarLogo" class="drawer-switch" />
|
<el-switch v-model="settingsStore.sidebarLogo" class="drawer-switch" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-divider>导航栏模式</el-divider>
|
<el-divider>主题</el-divider>
|
||||||
|
|
||||||
<ul class="navbar">
|
<div class="flex justify-center" @click.stop>
|
||||||
|
<el-switch
|
||||||
|
v-model="isDark"
|
||||||
|
inline-prompt
|
||||||
|
@change="toggleTheme"
|
||||||
|
:active-icon="Sunny"
|
||||||
|
:inactive-icon="Moon"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-divider>导航栏布局</el-divider>
|
||||||
|
|
||||||
|
<ul class="layout">
|
||||||
<el-tooltip content="左侧模式" placement="bottom">
|
<el-tooltip content="左侧模式" placement="bottom">
|
||||||
<li class="navbar__item navbar__item--left">
|
<li
|
||||||
|
:class="
|
||||||
|
'layout-item layout-left ' +
|
||||||
|
(settingsStore.layout == 'left' ? 'is-active' : '')
|
||||||
|
"
|
||||||
|
@click="changeLayout('left')"
|
||||||
|
>
|
||||||
<div />
|
<div />
|
||||||
<div />
|
<div />
|
||||||
</li>
|
</li>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="顶部模式" placement="bottom">
|
<el-tooltip content="顶部模式" placement="bottom">
|
||||||
<li class="navbar__item navbar__item--top">
|
<li
|
||||||
|
:class="
|
||||||
|
'layout-item layout-top ' +
|
||||||
|
(settingsStore.layout == 'top' ? 'is-active' : '')
|
||||||
|
"
|
||||||
|
@click="changeLayout('top')"
|
||||||
|
>
|
||||||
<div />
|
<div />
|
||||||
<div />
|
<div />
|
||||||
</li>
|
</li>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="混合模式" placement="bottom">
|
<el-tooltip content="混合模式" placement="bottom">
|
||||||
<li class="navbar__item navbar__item--mix">
|
<li
|
||||||
|
:class="
|
||||||
|
'layout-item layout-mix ' +
|
||||||
|
(settingsStore.layout == 'mix' ? 'is-active' : '')
|
||||||
|
"
|
||||||
|
@click="changeLayout('mix')"
|
||||||
|
>
|
||||||
<div />
|
<div />
|
||||||
<div />
|
<div />
|
||||||
</li>
|
</li>
|
||||||
@@ -61,11 +100,9 @@ function themeChange(val: string) {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.drawer-container {
|
.settings-container {
|
||||||
padding: 24px;
|
padding: 16px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1.5;
|
|
||||||
word-wrap: break-word;
|
|
||||||
|
|
||||||
.drawer-title {
|
.drawer-title {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
@@ -84,34 +121,27 @@ function themeChange(val: string) {
|
|||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.job-link {
|
.layout {
|
||||||
display: block;
|
display: flex;
|
||||||
position: absolute;
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-around;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
left: 0;
|
height: 50px;
|
||||||
bottom: 0;
|
padding: 0;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar {
|
&-item {
|
||||||
display: flex;
|
width: 18%;
|
||||||
flex-wrap: wrap;
|
height: 45px;
|
||||||
justify-content: space-around;
|
background: #f0f2f5;
|
||||||
width: 100%;
|
position: relative;
|
||||||
height: 50px;
|
overflow: hidden;
|
||||||
padding: 0;
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
&__item {
|
}
|
||||||
width: 18%;
|
&-item.is-active {
|
||||||
height: 45px;
|
border: 2px solid var(--el-color-primary);
|
||||||
background: #f0f2f5;
|
}
|
||||||
position: relative;
|
&-left {
|
||||||
overflow: hidden;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 1px 2.5px 0 rgb(0 0 0 / 18%);
|
|
||||||
|
|
||||||
&--left {
|
|
||||||
div {
|
div {
|
||||||
&:nth-child(1) {
|
&:nth-child(1) {
|
||||||
width: 30%;
|
width: 30%;
|
||||||
@@ -131,7 +161,7 @@ function themeChange(val: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&--top {
|
&-top {
|
||||||
div {
|
div {
|
||||||
&:nth-child(1) {
|
&:nth-child(1) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -142,7 +172,7 @@ function themeChange(val: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&--mix {
|
&-mix {
|
||||||
div {
|
div {
|
||||||
&:nth-child(1) {
|
&:nth-child(1) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -156,7 +186,7 @@ function themeChange(val: string) {
|
|||||||
height: 70%;
|
height: 70%;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background: #fff;
|
background: #1b2a47;
|
||||||
box-shadow: 0 0 1px #888;
|
box-shadow: 0 0 1px #888;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import { useSettingsStore } from '@/store/modules/settings';
|
||||||
|
|
||||||
|
const settingsStore = useSettingsStore();
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
collapse: {
|
collapse: {
|
||||||
@@ -14,71 +17,25 @@ const logo = ref<string>(
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="sidebar-logo-container" :class="{ collapse: collapse }">
|
<transition class="bg-gray-800">
|
||||||
<transition name="sidebarLogoFade">
|
<router-link
|
||||||
<router-link
|
v-if="collapse"
|
||||||
v-if="collapse"
|
key="collapse"
|
||||||
key="collapse"
|
class="h-[50px] flex items-center justify-center"
|
||||||
class="sidebar-logo-link"
|
to="/"
|
||||||
to="/"
|
>
|
||||||
>
|
<img v-if="settingsStore.sidebarLogo" :src="logo" class="w-5 h-5" />
|
||||||
<img v-if="logo" :src="logo" class="sidebar-logo" />
|
<h1 v-else>vue3-element-admin</h1>
|
||||||
<h1 v-else class="sidebar-title">vue3-element-admin</h1>
|
</router-link>
|
||||||
</router-link>
|
|
||||||
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
|
<router-link
|
||||||
<img v-if="logo" :src="logo" class="sidebar-logo" />
|
v-else
|
||||||
<h1 class="sidebar-title">vue3-element-admin</h1>
|
key="expand"
|
||||||
</router-link>
|
class="h-[50px] flex items-center justify-center"
|
||||||
</transition>
|
to="/"
|
||||||
</div>
|
>
|
||||||
|
<img v-if="settingsStore.sidebarLogo" :src="logo" class="w-5 h-5" />
|
||||||
|
<span class="ml-3 text-white text-sm font-bold">vue3-element-admin</span>
|
||||||
|
</router-link>
|
||||||
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.sidebarLogoFade-enter-active {
|
|
||||||
transition: opacity 1.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebarLogoFade-enter,
|
|
||||||
.sidebarLogoFade-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-logo-container {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: 50px;
|
|
||||||
line-height: 50px;
|
|
||||||
background: #2b2f3a;
|
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
& .sidebar-logo-link {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
& .sidebar-logo {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .sidebar-title {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0;
|
|
||||||
color: #fff;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 50px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.collapse {
|
|
||||||
.sidebar-logo {
|
|
||||||
margin-right: 0px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
153
src/layout/components/Sidebar/MixNav.vue
Normal file
153
src/layout/components/Sidebar/MixNav.vue
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted } from 'vue';
|
||||||
|
import { RouterLink, useRoute, useRouter, RouteRecordRaw } from 'vue-router';
|
||||||
|
import {
|
||||||
|
ElDropdown,
|
||||||
|
ElDropdownItem,
|
||||||
|
ElDropdownMenu,
|
||||||
|
ElMenu,
|
||||||
|
ElMessageBox,
|
||||||
|
ElTooltip
|
||||||
|
} from 'element-plus';
|
||||||
|
|
||||||
|
import Screenfull from '@/components/Screenfull/index.vue';
|
||||||
|
import SizeSelect from '@/components/SizeSelect/index.vue';
|
||||||
|
import LangSelect from '@/components/LangSelect/index.vue';
|
||||||
|
import { CaretBottom } from '@element-plus/icons-vue';
|
||||||
|
|
||||||
|
import SidebarItem from './SidebarItem.vue';
|
||||||
|
import variables from '@/styles/variables.module.scss';
|
||||||
|
|
||||||
|
import { useTagsViewStore } from '@/store/modules/tagsView';
|
||||||
|
import { useUserStore } from '@/store/modules/user';
|
||||||
|
import { usePermissionStore } from '@/store/modules/permission';
|
||||||
|
|
||||||
|
const tagsViewStore = useTagsViewStore();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const permissionStore = usePermissionStore();
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const routes = [] as any[];
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('origin routes', permissionStore.routes);
|
||||||
|
permissionStore.routes.forEach(item => {
|
||||||
|
const { children, ...newItem } = item;
|
||||||
|
routes.push(newItem);
|
||||||
|
});
|
||||||
|
console.log('routes', routes);
|
||||||
|
});
|
||||||
|
|
||||||
|
const activeMenu = computed<string>(() => {
|
||||||
|
const { meta, path } = route;
|
||||||
|
if (meta?.activeMenu) {
|
||||||
|
return meta.activeMenu as string;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
});
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
userStore
|
||||||
|
.logout()
|
||||||
|
.then(() => {
|
||||||
|
tagsViewStore.delAllViews();
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
router.push(`/login?redirect=${route.fullPath}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="horizontal-header">
|
||||||
|
<el-menu
|
||||||
|
class="horizontal-header-menu"
|
||||||
|
:default-active="activeMenu"
|
||||||
|
:background-color="variables.menuBg"
|
||||||
|
:text-color="variables.menuText"
|
||||||
|
:active-text-color="variables.menuActiveText"
|
||||||
|
mode="horizontal"
|
||||||
|
>
|
||||||
|
<sidebar-item
|
||||||
|
v-for="route in routes"
|
||||||
|
:item="route"
|
||||||
|
:key="route.path"
|
||||||
|
:base-path="route.path"
|
||||||
|
/>
|
||||||
|
</el-menu>
|
||||||
|
|
||||||
|
<div class="horizontal-header-right">
|
||||||
|
<!--全屏 -->
|
||||||
|
<screenfull id="screenfull" />
|
||||||
|
|
||||||
|
<!-- 布局大小 -->
|
||||||
|
<el-tooltip content="布局大小" effect="dark" placement="bottom">
|
||||||
|
<size-select />
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<!--语言选择-->
|
||||||
|
<lang-select />
|
||||||
|
|
||||||
|
<el-dropdown trigger="click">
|
||||||
|
<div class="flex justify-center items-center pr-[20px]">
|
||||||
|
<img
|
||||||
|
:src="userStore.avatar + '?imageView2/1/w/80/h/80'"
|
||||||
|
class="w-[40px] h-[40px] rounded-lg"
|
||||||
|
/>
|
||||||
|
<CaretBottom class="w-3 h-3" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<router-link to="/">
|
||||||
|
<el-dropdown-item>{{ $t('navbar.dashboard') }}</el-dropdown-item>
|
||||||
|
</router-link>
|
||||||
|
<a target="_blank" href="https://github.com/hxrui">
|
||||||
|
<el-dropdown-item>Github</el-dropdown-item>
|
||||||
|
</a>
|
||||||
|
<a target="_blank" href="https://gitee.com/haoxr">
|
||||||
|
<el-dropdown-item>{{ $t('navbar.gitee') }}</el-dropdown-item>
|
||||||
|
</a>
|
||||||
|
<a target="_blank" href="https://www.cnblogs.com/haoxianrui/">
|
||||||
|
<el-dropdown-item>{{ $t('navbar.document') }}</el-dropdown-item>
|
||||||
|
</a>
|
||||||
|
<el-dropdown-item divided @click="logout">
|
||||||
|
{{ $t('navbar.logout') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.horizontal-header {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
background: #001529;
|
||||||
|
|
||||||
|
&-menu {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-right {
|
||||||
|
display: flex;
|
||||||
|
min-width: 340px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -86,13 +86,14 @@ function resolvePath(routePath: string) {
|
|||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</app-link>
|
</app-link>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-sub-menu v-else :index="resolvePath(item.path)" popper-append-to-body>
|
<el-sub-menu v-else :index="resolvePath(item.path)" popper-append-to-body>
|
||||||
<!-- popper-append-to-body -->
|
<!-- popper-append-to-body -->
|
||||||
<template #title>
|
<template #title>
|
||||||
<svg-icon
|
<svg-icon
|
||||||
v-if="item.meta && item.meta.icon"
|
v-if="item.meta && item.meta.icon"
|
||||||
:icon-class="item.meta.icon"
|
:icon-class="item.meta.icon"
|
||||||
></svg-icon>
|
/>
|
||||||
<span v-if="item.meta && item.meta.title">{{
|
<span v-if="item.meta && item.meta.title">{{
|
||||||
generateTitle(item.meta.title)
|
generateTitle(item.meta.title)
|
||||||
}}</span>
|
}}</span>
|
||||||
@@ -104,10 +105,7 @@ function resolvePath(routePath: string) {
|
|||||||
:item="child"
|
:item="child"
|
||||||
:is-nest="true"
|
:is-nest="true"
|
||||||
:base-path="resolvePath(child.path)"
|
:base-path="resolvePath(child.path)"
|
||||||
class="nest-menu"
|
|
||||||
/>
|
/>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ function moveToTarget(currentTag: TagView) {
|
|||||||
} else if (lastTag === currentTag) {
|
} else if (lastTag === currentTag) {
|
||||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth;
|
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth;
|
||||||
} else {
|
} else {
|
||||||
const tagListDom = document.getElementsByClassName('tags-view__item');
|
const tagListDom = document.getElementsByClassName('tags-item');
|
||||||
const currentIndex = tagsViewStore.visitedViews.findIndex(
|
const currentIndex = tagsViewStore.visitedViews.findIndex(
|
||||||
item => item === currentTag
|
item => item === currentTag
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -237,10 +237,12 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="tags-view__container">
|
<div
|
||||||
|
class="h-[34px] w-full border-b-[1px] border-gray-200 shadow-lg shadow-[rgba(0, 21, 41, 0.08)]"
|
||||||
|
>
|
||||||
<scroll-pane
|
<scroll-pane
|
||||||
ref="scrollPaneRef"
|
ref="scrollPaneRef"
|
||||||
class="tags-view__wrapper"
|
class="tags-container"
|
||||||
@scroll="handleScroll"
|
@scroll="handleScroll"
|
||||||
>
|
>
|
||||||
<router-link
|
<router-link
|
||||||
@@ -249,24 +251,26 @@ onMounted(() => {
|
|||||||
:data-path="tag.path"
|
:data-path="tag.path"
|
||||||
:class="isActive(tag) ? 'active' : ''"
|
:class="isActive(tag) ? 'active' : ''"
|
||||||
:to="{ path: tag.path, query: tag.query }"
|
:to="{ path: tag.path, query: tag.query }"
|
||||||
class="tags-view__item"
|
class="tags-item"
|
||||||
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
|
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
|
||||||
@contextmenu.prevent="openMenu(tag, $event)"
|
@contextmenu.prevent="openMenu(tag, $event)"
|
||||||
>
|
>
|
||||||
{{ generateTitle(tag.meta?.title) }}
|
{{ generateTitle(tag.meta?.title) }}
|
||||||
|
|
||||||
<span
|
<span
|
||||||
v-if="!isAffix(tag)"
|
v-if="!isAffix(tag)"
|
||||||
class="icon-close"
|
class="tags-item-remove"
|
||||||
@click.prevent.stop="closeSelectedTag(tag)"
|
@click.prevent.stop="closeSelectedTag(tag)"
|
||||||
>
|
>
|
||||||
<svg-icon icon-class="close" />
|
<svg-icon icon-class="close" />
|
||||||
</span>
|
</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</scroll-pane>
|
</scroll-pane>
|
||||||
|
|
||||||
<ul
|
<ul
|
||||||
v-show="visible"
|
v-show="visible"
|
||||||
:style="{ left: left + 'px', top: top + 'px' }"
|
:style="{ left: left + 'px', top: top + 'px' }"
|
||||||
class="tags-view__menu"
|
class="tags-item-menu"
|
||||||
>
|
>
|
||||||
<li @click="refreshSelectedTag(selectedTag)">
|
<li @click="refreshSelectedTag(selectedTag)">
|
||||||
<svg-icon icon-class="refresh" />
|
<svg-icon icon-class="refresh" />
|
||||||
@@ -297,90 +301,67 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.tags-view__container {
|
.tags-container {
|
||||||
height: 34px;
|
.tags-item {
|
||||||
width: 100%;
|
display: inline-block;
|
||||||
background: #fff;
|
cursor: pointer;
|
||||||
border-bottom: 1px solid #d8dce5;
|
border: 1px solid #d8dce5;
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
|
padding: 3px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 4px 0 0 5px;
|
||||||
|
|
||||||
.tags-view__wrapper {
|
&:first-of-type {
|
||||||
.tags-view__item {
|
margin-left: 15px;
|
||||||
display: inline-block;
|
}
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 26px;
|
|
||||||
line-height: 26px;
|
|
||||||
border: 1px solid #d8dce5;
|
|
||||||
color: #495060;
|
|
||||||
background: #fff;
|
|
||||||
padding: 0 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-top: 4px;
|
|
||||||
|
|
||||||
&:first-of-type {
|
&:last-of-type {
|
||||||
margin-left: 15px;
|
margin-right: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-of-type {
|
&:hover {
|
||||||
margin-right: 15px;
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&.active {
|
||||||
color: var(--el-color-primary);
|
background-color: var(--el-color-primary);
|
||||||
}
|
color: var(--el-color-primary-light-9);
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
&.active {
|
&::before {
|
||||||
background-color: var(--el-color-primary);
|
content: '';
|
||||||
color: var(--el-color-primary-light-9);
|
background: #fff;
|
||||||
border-color: var(--el-color-primary);
|
display: inline-block;
|
||||||
&::before {
|
width: 8px;
|
||||||
content: '';
|
height: 8px;
|
||||||
background: #fff;
|
|
||||||
display: inline-block;
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 50%;
|
|
||||||
position: relative;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-close {
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
text-align: center;
|
position: relative;
|
||||||
|
margin-right: 5px;
|
||||||
&:hover {
|
|
||||||
background-color: #ccc;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.tags-view__menu {
|
|
||||||
margin: 0;
|
|
||||||
background: #fff;
|
|
||||||
z-index: 3000;
|
|
||||||
position: absolute;
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 5px 0;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 400;
|
|
||||||
color: #333;
|
|
||||||
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin: 0;
|
|
||||||
padding: 7px 16px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
|
&-remove {
|
||||||
|
border-radius: 50%;
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #eee;
|
color: #fff;
|
||||||
|
background-color: #ccc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tags-item-menu {
|
||||||
|
background: #fff;
|
||||||
|
z-index: 99;
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding: 8px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -30,15 +30,15 @@ const classObj = computed(() => ({
|
|||||||
hideSidebar: !appStore.sidebar.opened,
|
hideSidebar: !appStore.sidebar.opened,
|
||||||
openSidebar: appStore.sidebar.opened,
|
openSidebar: appStore.sidebar.opened,
|
||||||
withoutAnimation: appStore.sidebar.withoutAnimation,
|
withoutAnimation: appStore.sidebar.withoutAnimation,
|
||||||
mobile: appStore.device === DeviceType.mobile
|
mobile: appStore.device === 'mobile'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (width.value < WIDTH) {
|
if (width.value < WIDTH) {
|
||||||
appStore.toggleDevice(DeviceType.mobile);
|
appStore.toggleDevice('mobile');
|
||||||
appStore.closeSideBar(true);
|
appStore.closeSideBar(true);
|
||||||
} else {
|
} else {
|
||||||
appStore.toggleDevice(DeviceType.desktop);
|
appStore.toggleDevice('desktop');
|
||||||
|
|
||||||
if (width.value >= 1200) {
|
if (width.value >= 1200) {
|
||||||
//大屏
|
//大屏
|
||||||
@@ -59,10 +59,11 @@ function handleOutsideClick() {
|
|||||||
<!-- 手机设备 && 侧边栏 → 显示遮罩层 -->
|
<!-- 手机设备 && 侧边栏 → 显示遮罩层 -->
|
||||||
<div
|
<div
|
||||||
v-if="classObj.mobile && classObj.openSidebar"
|
v-if="classObj.mobile && classObj.openSidebar"
|
||||||
class="drawer-bg"
|
|
||||||
@click="handleOutsideClick"
|
@click="handleOutsideClick"
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<Sidebar class="sidebar-container" />
|
<Sidebar class="sidebar-container" />
|
||||||
|
|
||||||
<div :class="{ hasTagsView: showTagsView }" class="main-container">
|
<div :class="{ hasTagsView: showTagsView }" class="main-container">
|
||||||
<div :class="{ 'fixed-header': fixedHeader }">
|
<div :class="{ 'fixed-header': fixedHeader }">
|
||||||
<navbar />
|
<navbar />
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ interface DefaultSettings {
|
|||||||
fixedHeader: boolean;
|
fixedHeader: boolean;
|
||||||
sidebarLogo: boolean;
|
sidebarLogo: boolean;
|
||||||
errorLog: string;
|
errorLog: string;
|
||||||
|
layout: string;
|
||||||
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultSettings: DefaultSettings = {
|
const defaultSettings: DefaultSettings = {
|
||||||
@@ -13,7 +15,9 @@ const defaultSettings: DefaultSettings = {
|
|||||||
tagsView: true,
|
tagsView: true,
|
||||||
fixedHeader: false,
|
fixedHeader: false,
|
||||||
sidebarLogo: true,
|
sidebarLogo: true,
|
||||||
errorLog: 'production'
|
errorLog: 'production',
|
||||||
|
layout: 'left',
|
||||||
|
theme: 'light'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default defaultSettings;
|
export default defaultSettings;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { getLanguage } from '@/lang/index';
|
import { getLanguage } from '@/lang/index';
|
||||||
import { computed, reactive, ref } from 'vue';
|
import { computed, reactive, ref } from 'vue';
|
||||||
|
import { useStorage } from '@vueuse/core';
|
||||||
|
|
||||||
// Element Plus 语言包
|
// Element Plus 语言包
|
||||||
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
||||||
@@ -27,7 +28,7 @@ export enum SizeType {
|
|||||||
// setup
|
// setup
|
||||||
export const useAppStore = defineStore('app', () => {
|
export const useAppStore = defineStore('app', () => {
|
||||||
// state
|
// state
|
||||||
const device = ref<DeviceType>(DeviceType.desktop);
|
const device = useStorage<string>('device', 'desktop');
|
||||||
const size = ref(getSize() || 'default');
|
const size = ref(getSize() || 'default');
|
||||||
const language = ref(getLanguage());
|
const language = ref(getLanguage());
|
||||||
const sidebar = reactive({
|
const sidebar = reactive({
|
||||||
@@ -66,7 +67,7 @@ export const useAppStore = defineStore('app', () => {
|
|||||||
setSidebarStatus('opened');
|
setSidebarStatus('opened');
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleDevice(val: DeviceType) {
|
function toggleDevice(val: string) {
|
||||||
device.value = val;
|
device.value = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,38 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import defaultSettings from '../../settings';
|
import defaultSettings from '../../settings';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useCssVar, useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
|
|
||||||
const el = document.documentElement;
|
/**
|
||||||
|
* 主题类型
|
||||||
|
*/
|
||||||
|
export enum ThemeType {
|
||||||
|
light,
|
||||||
|
dark
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 布局类型
|
||||||
|
*/
|
||||||
|
export enum LayoutType {
|
||||||
|
left,
|
||||||
|
top,
|
||||||
|
mix
|
||||||
|
}
|
||||||
|
|
||||||
export const useSettingsStore = defineStore('setting', () => {
|
export const useSettingsStore = defineStore('setting', () => {
|
||||||
// state
|
// state
|
||||||
const theme = useStorage('theme', useCssVar('--el-color-primary', el))
|
|
||||||
|
|
||||||
const showSettings = ref<boolean>(defaultSettings.showSettings);
|
const showSettings = ref<boolean>(defaultSettings.showSettings);
|
||||||
const tagsView = useStorage<boolean>('tagsView', defaultSettings.tagsView)
|
const tagsView = useStorage<boolean>('tagsView', defaultSettings.tagsView);
|
||||||
const fixedHeader = ref<boolean>(defaultSettings.fixedHeader);
|
const fixedHeader = ref<boolean>(defaultSettings.fixedHeader);
|
||||||
const sidebarLogo = ref<boolean>(defaultSettings.sidebarLogo);
|
const sidebarLogo = ref<boolean>(defaultSettings.sidebarLogo);
|
||||||
|
|
||||||
|
const layout = useStorage<string>('layout', defaultSettings.layout);
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
function changeSetting(param: { key: string; value: any }) {
|
function changeSetting(param: { key: string; value: any }) {
|
||||||
const { key, value } = param;
|
const { key, value } = param;
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'theme':
|
|
||||||
theme.value = value;
|
|
||||||
break;
|
|
||||||
case 'showSettings':
|
case 'showSettings':
|
||||||
showSettings.value = value;
|
showSettings.value = value;
|
||||||
break;
|
break;
|
||||||
@@ -33,17 +45,20 @@ export const useSettingsStore = defineStore('setting', () => {
|
|||||||
case 'sidevarLogo':
|
case 'sidevarLogo':
|
||||||
sidebarLogo.value = value;
|
sidebarLogo.value = value;
|
||||||
break;
|
break;
|
||||||
|
case 'layout':
|
||||||
|
layout.value = value;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
theme,
|
|
||||||
showSettings,
|
showSettings,
|
||||||
tagsView,
|
tagsView,
|
||||||
fixedHeader,
|
fixedHeader,
|
||||||
sidebarLogo,
|
sidebarLogo,
|
||||||
|
layout,
|
||||||
changeSetting
|
changeSetting
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 数据表格 -->
|
<!-- 数据表格 -->
|
||||||
<el-card>
|
<el-card shadow="never">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-button type="success" :icon="Plus" @click="handleAdd"
|
<el-button type="success" :icon="Plus" @click="handleAdd"
|
||||||
>新增</el-button
|
>新增</el-button
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ onMounted(() => {
|
|||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-card>
|
<el-card shadow="never">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-button type="success" :icon="Plus" @click="handleAdd"
|
<el-button type="success" :icon="Plus" @click="handleAdd"
|
||||||
>新增</el-button
|
>新增</el-button
|
||||||
@@ -269,19 +269,19 @@ onMounted(() => {
|
|||||||
border
|
border
|
||||||
>
|
>
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="角色名称" prop="name" min-width="150" />
|
<el-table-column label="角色名称" prop="name" min-width="120" />
|
||||||
<el-table-column label="角色编码" prop="code" width="150" />
|
<el-table-column label="角色编码" prop="code" width="100" />
|
||||||
|
|
||||||
<el-table-column label="状态" align="center" width="150">
|
<el-table-column label="状态" align="center" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="scope.row.status === 1" type="success">正常</el-tag>
|
<el-tag v-if="scope.row.status === 1" type="success">正常</el-tag>
|
||||||
<el-tag v-else type="info">禁用</el-tag>
|
<el-tag v-else type="info">禁用</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="排序" align="center" width="100" prop="sort" />
|
<el-table-column label="排序" align="center" width="80" prop="sort" />
|
||||||
<el-table-column prop="createTime" label="创建时间" width="160" />
|
<el-table-column prop="createTime" label="创建时间" width="180" />
|
||||||
<el-table-column prop="updateTime" label="修改时间" width="160" />
|
<el-table-column prop="updateTime" label="修改时间" width="180" />
|
||||||
|
|
||||||
<el-table-column label="操作" align="left">
|
<el-table-column label="操作" align="left">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ onMounted(() => {
|
|||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<!-- 部门树 -->
|
<!-- 部门树 -->
|
||||||
<el-col :span="4" :xs="24">
|
<el-col :span="4" :xs="24">
|
||||||
<el-card class="box-card">
|
<el-card shadow="never">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="deptName"
|
v-model="deptName"
|
||||||
placeholder="部门名称"
|
placeholder="部门名称"
|
||||||
@@ -517,7 +517,7 @@ onMounted(() => {
|
|||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-card>
|
<el-card shadow="never">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-form-item style="float: left">
|
<el-form-item style="float: left">
|
||||||
<el-button
|
<el-button
|
||||||
|
|||||||
Reference in New Issue
Block a user