mirror of
https://gitee.com/fantastic-admin/basic.git
synced 2024-12-05 21:47:55 +08:00
settings.js 参数结构调整,ThemeSetting 组件重构并更名为 AppSetting
This commit is contained in:
parent
8e24cb6000
commit
b0e3bd2fb5
22
src/App.vue
22
src/App.vue
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-config-provider :size="settingsStore.elementSize">
|
||||
<el-config-provider :size="settingsStore.app.elementSize">
|
||||
<RouterView
|
||||
:style="{
|
||||
'--g-main-sidebar-actual-width': mainSidebarActualWidth,
|
||||
@ -17,7 +17,7 @@ const settingsStore = useSettingsStore()
|
||||
const mainSidebarActualWidth = computed(() => {
|
||||
let actualWidth = getComputedStyle(document.documentElement).getPropertyValue('--g-main-sidebar-width')
|
||||
actualWidth = parseInt(actualWidth)
|
||||
if (['head', 'single'].includes(settingsStore.menuMode)) {
|
||||
if (['head', 'single'].includes(settingsStore.menu.menuMode)) {
|
||||
actualWidth = 0
|
||||
}
|
||||
return `${actualWidth}px`
|
||||
@ -27,7 +27,7 @@ const mainSidebarActualWidth = computed(() => {
|
||||
const subSidebarActualWidth = computed(() => {
|
||||
let actualWidth = getComputedStyle(document.documentElement).getPropertyValue('--g-sub-sidebar-width')
|
||||
actualWidth = parseInt(actualWidth)
|
||||
if (settingsStore.sidebarCollapse) {
|
||||
if (settingsStore.menu.subMenuCollapse) {
|
||||
actualWidth = 64
|
||||
}
|
||||
return `${actualWidth}px`
|
||||
@ -35,12 +35,12 @@ const subSidebarActualWidth = computed(() => {
|
||||
|
||||
watch(() => settingsStore.mode, () => {
|
||||
if (settingsStore.mode === 'pc') {
|
||||
settingsStore.updateThemeSetting({
|
||||
'sidebarCollapse': settingsStore.sidebarCollapseLastStatus
|
||||
settingsStore.$patch(state => {
|
||||
state.menu.subMenuCollapse = settingsStore.subMenuCollapseLastStatus
|
||||
})
|
||||
} else if (settingsStore.mode === 'mobile') {
|
||||
settingsStore.updateThemeSetting({
|
||||
'sidebarCollapse': true
|
||||
settingsStore.$patch(state => {
|
||||
state.menu.subMenuCollapse = true
|
||||
})
|
||||
}
|
||||
document.body.setAttribute('data-mode', settingsStore.mode)
|
||||
@ -48,17 +48,17 @@ watch(() => settingsStore.mode, () => {
|
||||
immediate: true
|
||||
})
|
||||
|
||||
watch(() => settingsStore.menuMode, () => {
|
||||
document.body.setAttribute('data-menu-mode', settingsStore.menuMode)
|
||||
watch(() => settingsStore.menu.menuMode, () => {
|
||||
document.body.setAttribute('data-menu-mode', settingsStore.menu.menuMode)
|
||||
}, {
|
||||
immediate: true
|
||||
})
|
||||
|
||||
watch([
|
||||
() => settingsStore.enableDynamicTitle,
|
||||
() => settingsStore.app.enableDynamicTitle,
|
||||
() => settingsStore.title
|
||||
], () => {
|
||||
if (settingsStore.enableDynamicTitle && settingsStore.title) {
|
||||
if (settingsStore.app.enableDynamicTitle && settingsStore.title) {
|
||||
let title = settingsStore.title
|
||||
document.title = `${title} - ${import.meta.env.VITE_APP_TITLE}`
|
||||
} else {
|
||||
|
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<footer class="copyright">
|
||||
Copyright © {{ settingsStore.copyrightDates }}
|
||||
<a v-if="settingsStore.copyrightWebsite" :href="settingsStore.copyrightWebsite" target="_blank" rel="noopener">{{ settingsStore.copyrightCompany }},</a>
|
||||
<span v-else>{{ settingsStore.copyrightCompany }},</span>
|
||||
Copyright © {{ settingsStore.copyright.dates }}
|
||||
<a v-if="settingsStore.copyright.website" :href="settingsStore.copyright.website" target="_blank" rel="noopener">{{ settingsStore.copyright.company }},</a>
|
||||
<span v-else>{{ settingsStore.copyright.company }},</span>
|
||||
All Rights Reserved
|
||||
</footer>
|
||||
</template>
|
||||
|
357
src/layout/components/AppSetting/index.vue
Normal file
357
src/layout/components/AppSetting/index.vue
Normal file
@ -0,0 +1,357 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="isShow" title="应用配置" direction="rtl" :size="350" custom-class="flex-container">
|
||||
<div class="container">
|
||||
<el-alert title="应用配置可实时预览效果,但仅是临时生效,要想真正作用于项目,可以点击下方的“复制配置”按钮,将配置粘贴到 src/settings.custom.json 中即可,或者也可在 src/settings.js 中直接修改默认配置。同时建议在生产环境隐藏应用配置功能。" type="error" :closable="false" />
|
||||
<el-divider v-if="settingsStore.mode === 'pc'">导航栏模式</el-divider>
|
||||
<div v-if="settingsStore.mode === 'pc'" class="menu-mode">
|
||||
<el-tooltip content="侧边栏模式(含主导航)" placement="top" :show-after="500" :append-to-body="false">
|
||||
<div class="mode mode-side" :class="{'active': settings.menu.menuMode === 'side'}" @click="settings.menu.menuMode = 'side'">
|
||||
<svg-icon name="el-icon-check" />
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="顶部模式" placement="top" :show-after="500" :append-to-body="false">
|
||||
<div class="mode mode-head" :class="{'active': settings.menu.menuMode === 'head'}" @click="settings.menu.menuMode = 'head'">
|
||||
<svg-icon name="el-icon-check" />
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="侧边栏模式(不含主导航)" placement="top" :show-after="500" :append-to-body="false">
|
||||
<div class="mode mode-single" :class="{'active': settings.menu.menuMode === 'single'}" @click="settings.menu.menuMode = 'single'">
|
||||
<svg-icon name="el-icon-check" />
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-divider>导航栏</el-divider>
|
||||
<div class="setting-item">
|
||||
<div class="label">是否折叠</div>
|
||||
<el-switch v-model="settings.menu.subMenuCollapse" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
切换跳转
|
||||
<el-tooltip content="开启该功能后,切换侧边栏时,页面自动跳转至该侧边栏导航下第一个路由地址" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="settings.menu.switchMainMenuAndPageJump" :disabled="['single'].includes(settings.menu.menuMode)" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
保持展开一个
|
||||
<el-tooltip content="开启该功能后,侧边栏只保持一个子菜单的展开" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="settings.menu.subMenuUniqueOpened" />
|
||||
</div>
|
||||
<el-divider>顶栏</el-divider>
|
||||
<div class="setting-item">
|
||||
<div class="label">是否固定</div>
|
||||
<el-switch v-model="settings.topbar.fixed" />
|
||||
</div>
|
||||
<div v-if="settingsStore.mode === 'pc'" class="setting-item">
|
||||
<div class="label">折叠按钮</div>
|
||||
<el-switch v-model="settings.topbar.enableSidebarCollapse" />
|
||||
</div>
|
||||
<div v-if="settingsStore.mode === 'pc'" class="setting-item">
|
||||
<div class="label">面包屑导航</div>
|
||||
<el-switch v-model="settings.topbar.enableBreadcrumb" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
导航栏搜索
|
||||
<el-tooltip content="对导航栏进行快捷搜索" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="settings.topbar.enableNavSearch" />
|
||||
</div>
|
||||
<div v-if="settingsStore.mode === 'pc'" class="setting-item">
|
||||
<div class="label">
|
||||
全屏
|
||||
<el-tooltip content="该功能使用场景极少,用户习惯于通过窗口“最大化”功能来扩大显示区域,以显示更多内容,并且使用 F11 键也可以进入全屏效果" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="settings.topbar.enableFullscreen" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
页面刷新
|
||||
<el-tooltip content="开启时会阻止原生 F5 键刷新功能,并采用框架提供的刷新模式进行页面刷新" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="settings.topbar.enablePageReload" />
|
||||
</div>
|
||||
<el-divider>底部版权</el-divider>
|
||||
<div class="setting-item">
|
||||
<div class="label">是否启用</div>
|
||||
<el-switch v-model="settings.copyright.enable" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">日期</div>
|
||||
<el-input v-model="settings.copyright.dates" size="small" :disabled="!settings.copyright.enable" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">公司</div>
|
||||
<el-input v-model="settings.copyright.company" size="small" :disabled="!settings.copyright.enable" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">网址</div>
|
||||
<el-input v-model="settings.copyright.website" size="small" :disabled="!settings.copyright.enable" />
|
||||
</div>
|
||||
<el-divider>控制台</el-divider>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
是否开启
|
||||
<el-tooltip content="该功能开启时,登录成功默认进入控制台页面,反之则默认进入导航栏里第一个导航页面" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="settings.dashboard.enable" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">控制台名称</div>
|
||||
<el-input v-model="settings.dashboard.title" size="small" />
|
||||
</div>
|
||||
<el-divider>其它</el-divider>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
组件尺寸
|
||||
<el-tooltip content="全局设置 Element Plus 组件的默认尺寸大小" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-radio-group v-model="settings.app.elementSize" size="small">
|
||||
<el-radio-button label="large">较大</el-radio-button>
|
||||
<el-radio-button label="default">默认</el-radio-button>
|
||||
<el-radio-button label="small">稍小</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">是否启用权限</div>
|
||||
<el-switch v-model="settings.app.enablePermission" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">是否开启后端返回路由数据</div>
|
||||
<el-switch v-model="settings.app.enableBackendReturnRoute" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
载入进度条
|
||||
<el-tooltip content="该功能开启时,跳转路由会看到页面顶部有进度条" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="settings.app.enableProgress" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
动态标题
|
||||
<el-tooltip content="该功能开启时,页面标题会显示当前路由标题,格式为“页面标题 - 网站名称”;关闭时则显示网站名称,网站名称在项目根目录下 .env.* 文件里配置" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="settings.app.enableDynamicTitle" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isSupported" class="action-buttons">
|
||||
<el-button icon="el-icon-document-copy" type="primary" @click="handleCopy">复制配置</el-button>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const { proxy } = getCurrentInstance()
|
||||
const route = useRoute()
|
||||
|
||||
import { useSettingsStore } from '@/store/modules/settings'
|
||||
const settingsStore = useSettingsStore()
|
||||
import { useMenuStore } from '@/store/modules/menu'
|
||||
const menuStore = useMenuStore()
|
||||
|
||||
const isShow = ref(false)
|
||||
|
||||
import globalSettings from '@/settings'
|
||||
const settings = ref(globalSettings)
|
||||
|
||||
watch(() => settings, () => {
|
||||
settingsStore.updateThemeSetting(settings.value)
|
||||
menuStore.switchHeaderActived(0)
|
||||
settings.value.menu.menuMode !== 'single' && menuStore.setHeaderActived(route.fullPath)
|
||||
}, {
|
||||
deep: true
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
proxy.$eventBus.on('global-theme-toggle', () => {
|
||||
isShow.value = !isShow.value
|
||||
})
|
||||
})
|
||||
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
const { copy, copied, isSupported } = useClipboard()
|
||||
|
||||
watch(copied, val => {
|
||||
if (val) {
|
||||
proxy.$message.success('复制成功,请粘贴到 src/settings.custom.json 文件中!')
|
||||
}
|
||||
})
|
||||
|
||||
function handleCopy() {
|
||||
copy(JSON.stringify(settings.value, null, 4))
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-drawer__body) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
padding: 0;
|
||||
}
|
||||
:deep(.el-drawer__header) {
|
||||
margin-bottom: initial;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
.flex-container {
|
||||
.container {
|
||||
padding: 15px;
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
}
|
||||
.action-buttons {
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #ddd;
|
||||
.el-button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-divider) {
|
||||
margin: 36px 0 24px;
|
||||
}
|
||||
.menu-mode {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
padding-bottom: 10px;
|
||||
.mode {
|
||||
position: relative;
|
||||
width: 50px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
background-color: #e1e3e6;
|
||||
box-shadow: 0 0 15px 1px #aaa;
|
||||
transition: 0.3s;
|
||||
&:hover {
|
||||
box-shadow: 0 0 15px 1px #666;
|
||||
}
|
||||
&.active {
|
||||
box-shadow: 0 0 0 2px #409eff;
|
||||
}
|
||||
&::before,
|
||||
&::after {
|
||||
pointer-events: none;
|
||||
}
|
||||
&-side {
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
background-color: #222b45;
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 10px;
|
||||
width: 15px;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
&-head {
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
background-color: #222b45;
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
width: 15px;
|
||||
height: calc(100% - 10px);
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
&-single {
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 15px;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
i {
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
display: none;
|
||||
}
|
||||
&.active i {
|
||||
display: block;
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.setting-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 5px 0;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
i {
|
||||
margin-left: 4px;
|
||||
font-size: 17px;
|
||||
color: #e6a23c;
|
||||
cursor: help;
|
||||
}
|
||||
}
|
||||
.el-switch {
|
||||
height: auto;
|
||||
}
|
||||
.el-input {
|
||||
width: 150px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<transition name="header">
|
||||
<header v-if="settingsStore.mode === 'pc' && settingsStore.menuMode === 'head'">
|
||||
<header v-if="settingsStore.mode === 'pc' && settingsStore.menu.menuMode === 'head'">
|
||||
<div class="header-container">
|
||||
<div class="main">
|
||||
<Logo />
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<router-link :to="to" class="title" :class="{'is-link': settingsStore.enableDashboard}" :title="title">
|
||||
<router-link :to="to" class="title" :class="{'is-link': settingsStore.dashboard.enable}" :title="title">
|
||||
<img v-if="showLogo" :src="logo" class="logo">
|
||||
<span v-if="showTitle">{{ title }}</span>
|
||||
</router-link>
|
||||
@ -27,7 +27,7 @@ const logo = ref(imgLogo)
|
||||
|
||||
const to = computed(() => {
|
||||
let rtn = {}
|
||||
if (settingsStore.enableDashboard) {
|
||||
if (settingsStore.dashboard.enable) {
|
||||
rtn.name = 'dashboard'
|
||||
}
|
||||
return rtn
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<transition name="main-sidebar">
|
||||
<div v-if="settingsStore.menuMode === 'side' || (settingsStore.mode === 'mobile' && settingsStore.menuMode !== 'single')" class="main-sidebar-container">
|
||||
<div v-if="settingsStore.menu.menuMode === 'side' || (settingsStore.mode === 'mobile' && settingsStore.menu.menuMode !== 'single')" class="main-sidebar-container">
|
||||
<Logo :show-title="false" class="sidebar-logo" />
|
||||
<!-- 侧边栏模式(含主导航) -->
|
||||
<div class="nav">
|
||||
|
@ -116,7 +116,7 @@ onMounted(() => {
|
||||
isShow.value = !isShow.value
|
||||
})
|
||||
proxy.$hotkeys('alt+s', e => {
|
||||
if (settingsStore.enableNavSearch) {
|
||||
if (settingsStore.topbar.enableNavSearch) {
|
||||
e.preventDefault()
|
||||
isShow.value = true
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<div v-if="['side', 'head', 'single'].includes(settingsStore.menuMode) || settingsStore.mode === 'mobile'" class="sub-sidebar-container" :class="{'is-collapse': settingsStore.mode === 'pc' && settingsStore.sidebarCollapse}" @scroll="onSidebarScroll">
|
||||
<div v-if="['side', 'head', 'single'].includes(settingsStore.menu.menuMode) || settingsStore.mode === 'mobile'" class="sub-sidebar-container" :class="{'is-collapse': settingsStore.mode === 'pc' && settingsStore.menu.subMenuCollapse}" @scroll="onSidebarScroll">
|
||||
<Logo
|
||||
:show-logo="settingsStore.menuMode === 'single'" :class="{
|
||||
:show-logo="settingsStore.menu.menuMode === 'single'" :class="{
|
||||
'sidebar-logo': true,
|
||||
'sidebar-logo-bg': settingsStore.menuMode === 'single',
|
||||
'sidebar-logo-bg': settingsStore.menu.menuMode === 'single',
|
||||
'shadow': sidebarScrollTop
|
||||
}"
|
||||
/>
|
||||
<!-- 侧边栏模式(无主导航) -->
|
||||
<el-menu
|
||||
:unique-opened="settingsStore.sidebarUniqueOpened" :default-openeds="menuStore.defaultOpenedPaths" :default-active="$route.meta.activeMenu || $route.path" :collapse="settingsStore.mode === 'pc' && settingsStore.sidebarCollapse" :collapse-transition="false" :class="{
|
||||
'is-collapse-without-logo': settingsStore.menuMode !== 'single' && settingsStore.sidebarCollapse
|
||||
:unique-opened="settingsStore.menu.subMenuUniqueOpened" :default-openeds="menuStore.defaultOpenedPaths" :default-active="$route.meta.activeMenu || $route.path" :collapse="settingsStore.mode === 'pc' && settingsStore.menu.subMenuCollapse" :collapse-transition="false" :class="{
|
||||
'is-collapse-without-logo': settingsStore.menu.menuMode !== 'single' && settingsStore.menu.subMenuCollapse
|
||||
}"
|
||||
>
|
||||
<transition-group name="sub-sidebar">
|
||||
|
@ -1,423 +0,0 @@
|
||||
<template>
|
||||
<teleport to="#app">
|
||||
<el-drawer v-model="isShow" title="主题配置" direction="rtl" :size="300">
|
||||
<el-alert title="主题配置可实时预览效果,更多设置请在 src/settings.js 中进行设置,建议在生产环境隐藏主题配置功能" type="error" :closable="false" />
|
||||
<el-divider v-if="settingsStore.mode === 'pc'">导航栏模式</el-divider>
|
||||
<div v-if="settingsStore.mode === 'pc'" class="menu-mode">
|
||||
<el-tooltip content="侧边栏模式(含主导航)" placement="top" :show-after="500" :append-to-body="false">
|
||||
<div class="mode mode-side" :class="{'active': menuMode === 'side'}" @click="menuMode = 'side'">
|
||||
<svg-icon name="el-icon-check" />
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="顶部模式" placement="top" :show-after="500" :append-to-body="false">
|
||||
<div class="mode mode-head" :class="{'active': menuMode === 'head'}" @click="menuMode = 'head'">
|
||||
<svg-icon name="el-icon-check" />
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="侧边栏模式(不含主导航)" placement="top" :show-after="500" :append-to-body="false">
|
||||
<div class="mode mode-single" :class="{'active': menuMode === 'single'}" @click="menuMode = 'single'">
|
||||
<svg-icon name="el-icon-check" />
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-divider>侧边栏</el-divider>
|
||||
<div v-if="settingsStore.mode === 'pc'" class="setting-item">
|
||||
<div class="label">折叠按钮</div>
|
||||
<el-switch v-model="enableSidebarCollapse" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">是否折叠</div>
|
||||
<el-switch v-model="sidebarCollapse" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
切换跳转
|
||||
<el-tooltip content="开启该功能后,切换侧边栏时,页面自动跳转至该侧边栏导航下第一个路由地址" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="switchSidebarAndPageJump" :disabled="['single'].includes(settingsStore.menuMode)" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
保持展开一个
|
||||
<el-tooltip content="开启该功能后,侧边栏只保持一个子菜单的展开" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="sidebarUniqueOpened" />
|
||||
</div>
|
||||
<el-divider>顶栏</el-divider>
|
||||
<div class="setting-item">
|
||||
<div class="label">顶栏固定</div>
|
||||
<el-switch v-model="topbarFixed" />
|
||||
</div>
|
||||
<div v-if="settingsStore.mode === 'pc'" class="setting-item">
|
||||
<div class="label">面包屑导航</div>
|
||||
<el-switch v-model="enableBreadcrumb" />
|
||||
</div>
|
||||
<el-divider>功能按钮</el-divider>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
导航栏搜索
|
||||
<el-tooltip content="对导航栏进行快捷搜索" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="enableNavSearch" />
|
||||
</div>
|
||||
<div v-if="settingsStore.mode === 'pc'" class="setting-item">
|
||||
<div class="label">
|
||||
全屏
|
||||
<el-tooltip content="该功能使用场景极少,用户习惯于通过窗口“最大化”功能来扩大显示区域,以显示更多内容,并且使用 F11 键也可以进入全屏效果" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="enableFullscreen" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
页面刷新
|
||||
<el-tooltip content="开启时会阻止原生 F5 键刷新功能,并采用框架提供的刷新模式进行页面刷新" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="enablePageReload" />
|
||||
</div>
|
||||
<el-divider>其它</el-divider>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
组件尺寸
|
||||
<el-tooltip content="全局设置 Element Plus 组件的默认尺寸大小" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-radio-group v-model="elementSize" size="small">
|
||||
<el-radio-button label="large">较大</el-radio-button>
|
||||
<el-radio-button label="default">默认</el-radio-button>
|
||||
<el-radio-button label="small">稍小</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">底部版权</div>
|
||||
<el-switch v-model="showCopyright" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
加载进度条
|
||||
<el-tooltip content="该功能开启时,跳转路由会看到页面顶部有条蓝色的进度条" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="enableProgress" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
动态标题
|
||||
<el-tooltip content="该功能开启时,页面标题会显示当前路由标题,格式为“页面标题 - 网站名称”;关闭时则显示网站名称,网站名称在项目根目录下 .env.* 文件里配置" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="enableDynamicTitle" />
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
欢迎页
|
||||
<el-tooltip content="欢迎页即控制台页面,该功能开启时,登录成功默认进入控制台页面;关闭时则默认进入侧边栏导航第一个导航页面" placement="top" :append-to-body="false">
|
||||
<svg-icon name="el-icon-question-filled" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="enableDashboard" />
|
||||
</div>
|
||||
</el-drawer>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const { proxy } = getCurrentInstance()
|
||||
const route = useRoute()
|
||||
|
||||
import { useSettingsStore } from '@/store/modules/settings'
|
||||
const settingsStore = useSettingsStore()
|
||||
import { useMenuStore } from '@/store/modules/menu'
|
||||
const menuStore = useMenuStore()
|
||||
|
||||
const isShow = ref(false)
|
||||
|
||||
const menuMode = computed({
|
||||
get: function() {
|
||||
return settingsStore.menuMode
|
||||
},
|
||||
set: function(newValue) {
|
||||
menuStore.switchHeaderActived(0)
|
||||
settingsStore.updateThemeSetting({
|
||||
'menuMode': newValue
|
||||
})
|
||||
settingsStore.menuMode !== 'single' && menuStore.setHeaderActived(route.fullPath)
|
||||
}
|
||||
})
|
||||
const elementSize = computed({
|
||||
get: function() {
|
||||
return settingsStore.elementSize
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'elementSize': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableSidebarCollapse = computed({
|
||||
get: function() {
|
||||
return settingsStore.enableSidebarCollapse
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'enableSidebarCollapse': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const sidebarCollapse = computed({
|
||||
get: function() {
|
||||
return settingsStore.sidebarCollapse
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'sidebarCollapse': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const switchSidebarAndPageJump = computed({
|
||||
get: function() {
|
||||
return settingsStore.switchSidebarAndPageJump
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'switchSidebarAndPageJump': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const sidebarUniqueOpened = computed({
|
||||
get: function() {
|
||||
return settingsStore.sidebarUniqueOpened
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'sidebarUniqueOpened': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const topbarFixed = computed({
|
||||
get: function() {
|
||||
return settingsStore.topbarFixed
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'topbarFixed': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableBreadcrumb = computed({
|
||||
get: function() {
|
||||
return settingsStore.enableBreadcrumb
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'enableBreadcrumb': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const showCopyright = computed({
|
||||
get: function() {
|
||||
return settingsStore.showCopyright
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'showCopyright': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableNavSearch = computed({
|
||||
get: function() {
|
||||
return settingsStore.enableNavSearch
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'enableNavSearch': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableFullscreen = computed({
|
||||
get: function() {
|
||||
return settingsStore.enableFullscreen
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'enableFullscreen': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enablePageReload = computed({
|
||||
get: function() {
|
||||
return settingsStore.enablePageReload
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'enablePageReload': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableProgress = computed({
|
||||
get: function() {
|
||||
return settingsStore.enableProgress
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'enableProgress': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableDynamicTitle = computed({
|
||||
get: function() {
|
||||
return settingsStore.enableDynamicTitle
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'enableDynamicTitle': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableDashboard = computed({
|
||||
get: function() {
|
||||
return settingsStore.enableDashboard
|
||||
},
|
||||
set: function(newValue) {
|
||||
settingsStore.updateThemeSetting({
|
||||
'enableDashboard': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
proxy.$eventBus.on('global-theme-toggle', () => {
|
||||
isShow.value = !isShow.value
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.menu-mode {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
padding-bottom: 10px;
|
||||
.mode {
|
||||
position: relative;
|
||||
width: 50px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
background-color: #e1e3e6;
|
||||
box-shadow: 0 0 15px 1px #aaa;
|
||||
transition: 0.3s;
|
||||
&:hover {
|
||||
box-shadow: 0 0 15px 1px #666;
|
||||
}
|
||||
&.active {
|
||||
box-shadow: 0 0 0 2px #409eff;
|
||||
}
|
||||
&::before,
|
||||
&::after {
|
||||
pointer-events: none;
|
||||
}
|
||||
&-side {
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
background-color: #222b45;
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 10px;
|
||||
width: 15px;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
&-head {
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
background-color: #222b45;
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
width: 15px;
|
||||
height: calc(100% - 10px);
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
&-single {
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 15px;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
i {
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
display: none;
|
||||
}
|
||||
&.active i {
|
||||
display: block;
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.setting-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 5px 0;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
i {
|
||||
margin-left: 4px;
|
||||
font-size: 17px;
|
||||
color: #e6a23c;
|
||||
cursor: help;
|
||||
}
|
||||
}
|
||||
.el-switch {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -5,13 +5,13 @@
|
||||
<svg-icon name="pro" />
|
||||
<span class="title">查看专业版</span>
|
||||
</span>
|
||||
<span v-if="settingsStore.enableNavSearch" class="item" @click="$eventBus.emit('global-search-toggle')">
|
||||
<span v-if="settingsStore.topbar.enableNavSearch" class="item" @click="$eventBus.emit('global-search-toggle')">
|
||||
<svg-icon name="search" />
|
||||
</span>
|
||||
<span v-if="settingsStore.mode === 'pc' && settingsStore.enableFullscreen" class="item" @click="toggle">
|
||||
<span v-if="settingsStore.mode === 'pc' && settingsStore.topbar.enableFullscreen" class="item" @click="toggle">
|
||||
<svg-icon :name="isFullscreen ? 'fullscreen-exit' : 'fullscreen'" />
|
||||
</span>
|
||||
<span v-if="settingsStore.enablePageReload" class="item" @click="reload()">
|
||||
<span v-if="settingsStore.topbar.enablePageReload" class="item" @click="reload()">
|
||||
<svg-icon name="toolbar-reload" />
|
||||
</span>
|
||||
<span v-if="settingsStore.enableThemeSetting" class="item" @click="$eventBus.emit('global-theme-toggle')">
|
||||
@ -28,7 +28,7 @@
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu class="user-dropdown">
|
||||
<el-dropdown-item v-if="settingsStore.enableDashboard" command="dashboard">控制台</el-dropdown-item>
|
||||
<el-dropdown-item v-if="settingsStore.dashboard.enable" command="dashboard">控制台</el-dropdown-item>
|
||||
<el-dropdown-item command="setting">个人设置</el-dropdown-item>
|
||||
<el-dropdown-item divided command="logout">退出登录</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
|
@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div
|
||||
class="topbar-container" :class="{
|
||||
'fixed': settingsStore.topbarFixed,
|
||||
'fixed': settingsStore.topbar.fixed,
|
||||
'shadow': scrollTop
|
||||
}" data-fixed-calc-width
|
||||
>
|
||||
<div class="left-box">
|
||||
<div v-if="enableSidebarCollapse" class="sidebar-collapse" :class="{'is-collapse': settingsStore.sidebarCollapse}" @click="settingsStore.toggleSidebarCollapse()">
|
||||
<div v-if="enableSidebarCollapse" class="sidebar-collapse" :class="{'is-collapse': settingsStore.menu.subMenuCollapse}" @click="settingsStore.toggleSidebarCollapse()">
|
||||
<svg-icon name="toolbar-collapse" />
|
||||
</div>
|
||||
<el-breadcrumb v-if="settingsStore.enableBreadcrumb && settingsStore.mode === 'pc'" separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb v-if="settingsStore.topbar.enableBreadcrumb && settingsStore.mode === 'pc'" separator-class="el-icon-arrow-right">
|
||||
<transition-group name="breadcrumb">
|
||||
<template v-for="(item, index) in breadcrumbList">
|
||||
<el-breadcrumb-item v-if="index < breadcrumbList.length - 1" :key="item.path" :to="pathCompile(item.path)">
|
||||
@ -38,17 +38,17 @@ const settingsStore = useSettingsStore()
|
||||
|
||||
const enableSidebarCollapse = computed(() => {
|
||||
return settingsStore.mode === 'mobile' || (
|
||||
['side', 'head', 'single'].includes(settingsStore.menuMode) &&
|
||||
settingsStore.enableSidebarCollapse
|
||||
['side', 'head', 'single'].includes(settingsStore.menu.menuMode) &&
|
||||
settingsStore.topbar.enableSidebarCollapse
|
||||
)
|
||||
})
|
||||
|
||||
const breadcrumbList = computed(() => {
|
||||
let breadcrumbList = []
|
||||
if (settingsStore.enableDashboard) {
|
||||
if (settingsStore.dashboard.enable) {
|
||||
breadcrumbList.push({
|
||||
path: '/dashboard',
|
||||
title: settingsStore.dashboardTitle
|
||||
title: settingsStore.dashboard.title
|
||||
})
|
||||
}
|
||||
if (route.meta.breadcrumbNeste) {
|
||||
|
@ -3,13 +3,13 @@
|
||||
<div id="app-main">
|
||||
<Header />
|
||||
<div class="wrapper">
|
||||
<div class="sidebar-container" :class="{'show': settingsStore.mode === 'mobile' && !settingsStore.sidebarCollapse}">
|
||||
<div class="sidebar-container" :class="{'show': settingsStore.mode === 'mobile' && !settingsStore.menu.subMenuCollapse}">
|
||||
<MainSidebar />
|
||||
<SubSidebar />
|
||||
</div>
|
||||
<div class="sidebar-mask" :class="{'show': settingsStore.mode === 'mobile' && !settingsStore.sidebarCollapse}" @click="settingsStore.toggleSidebarCollapse()" />
|
||||
<div class="sidebar-mask" :class="{'show': settingsStore.mode === 'mobile' && !settingsStore.menu.subMenuCollapse}" @click="settingsStore.toggleSidebarCollapse()" />
|
||||
<div class="main-container" :style="{'padding-bottom': $route.meta.paddingBottom}">
|
||||
<Topbar v-if="!(settingsStore.menuMode === 'head' && !settingsStore.enableSidebarCollapse && !settingsStore.enableBreadcrumb)" />
|
||||
<Topbar v-if="!(settingsStore.menu.menuMode === 'head' && !settingsStore.topbar.enableSidebarCollapse && !settingsStore.topbar.enableBreadcrumb)" />
|
||||
<div class="main">
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition name="main" mode="out-in" appear>
|
||||
@ -26,7 +26,7 @@
|
||||
<el-backtop :right="20" :bottom="20" title="回到顶部" />
|
||||
</div>
|
||||
<Search />
|
||||
<ThemeSetting />
|
||||
<AppSetting />
|
||||
<BuyIt />
|
||||
</div>
|
||||
</template>
|
||||
@ -37,7 +37,7 @@ import MainSidebar from './components/MainSidebar/index.vue'
|
||||
import SubSidebar from './components/SubSidebar/index.vue'
|
||||
import Topbar from './components/Topbar/index.vue'
|
||||
import Search from './components/Search/index.vue'
|
||||
import ThemeSetting from './components/ThemeSetting/index.vue'
|
||||
import AppSetting from './components/AppSetting/index.vue'
|
||||
import BuyIt from './components/BuyIt/index.vue'
|
||||
import { isExternalLink } from '@/util'
|
||||
|
||||
@ -52,10 +52,10 @@ import { useMenuStore } from '@/store/modules/menu'
|
||||
const menuStore = useMenuStore()
|
||||
|
||||
const showCopyright = computed(() => {
|
||||
return typeof routeInfo.meta.copyright !== 'undefined' ? routeInfo.meta.copyright : settingsStore.showCopyright
|
||||
return typeof routeInfo.meta.copyright !== 'undefined' ? routeInfo.meta.copyright : settingsStore.copyright.enable
|
||||
})
|
||||
|
||||
watch(() => settingsStore.sidebarCollapse, val => {
|
||||
watch(() => settingsStore.menu.subMenuCollapse, val => {
|
||||
if (settingsStore.mode === 'mobile') {
|
||||
if (!val) {
|
||||
document.querySelector('body').classList.add('hidden')
|
||||
@ -67,15 +67,15 @@ watch(() => settingsStore.sidebarCollapse, val => {
|
||||
|
||||
watch(() => routeInfo.path, () => {
|
||||
if (settingsStore.mode === 'mobile') {
|
||||
settingsStore.updateThemeSetting({
|
||||
sidebarCollapse: true
|
||||
settingsStore.$patch(state => {
|
||||
state.menu.subMenuCollapse = true
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
proxy.$hotkeys('f5', e => {
|
||||
if (settingsStore.enablePageReload) {
|
||||
if (settingsStore.topbar.enablePageReload) {
|
||||
e.preventDefault()
|
||||
reload()
|
||||
}
|
||||
@ -91,7 +91,7 @@ function reload() {
|
||||
provide('switchMenu', switchMenu)
|
||||
function switchMenu(index) {
|
||||
menuStore.switchHeaderActived(index)
|
||||
if (settingsStore.switchSidebarAndPageJump) {
|
||||
if (settingsStore.menu.switchMainMenuAndPageJump) {
|
||||
if (isExternalLink(menuStore.sidebarRoutesFirstDeepestPath)) {
|
||||
window.open(menuStore.sidebarRoutesFirstDeepestPath, '_blank')
|
||||
} else {
|
||||
|
@ -19,7 +19,7 @@ for (var key in ElementIcons) {
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
app.use(ElementPlus, {
|
||||
locale: zhCn,
|
||||
size: useSettingsOutsideStore().elementSize
|
||||
size: useSettingsOutsideStore().app.elementSize
|
||||
})
|
||||
|
||||
import globalProperties from '@/util/global.properties'
|
||||
|
@ -30,7 +30,7 @@ const constantRoutes = [
|
||||
meta: {
|
||||
title: () => {
|
||||
const settingsOutsideStore = useSettingsOutsideStore()
|
||||
return settingsOutsideStore.dashboardTitle
|
||||
return settingsOutsideStore.dashboard.title
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -142,13 +142,13 @@ router.beforeEach(async(to, from, next) => {
|
||||
const settingsOutsideStore = useSettingsOutsideStore()
|
||||
const userOutsideStore = useUserOutsideStore()
|
||||
const menuOutsideStore = useMenuOutsideStore()
|
||||
settingsOutsideStore.enableProgress && (isLoading.value = true)
|
||||
settingsOutsideStore.app.enableProgress && (isLoading.value = true)
|
||||
// 是否已登录
|
||||
if (userOutsideStore.isLogin) {
|
||||
// 是否已根据权限动态生成并挂载路由
|
||||
if (menuOutsideStore.isGenerate) {
|
||||
// 导航栏如果不是 single 模式,则需要根据 path 定位主导航的选中状态
|
||||
settingsOutsideStore.menuMode !== 'single' && menuOutsideStore.setHeaderActived(to.path)
|
||||
settingsOutsideStore.menu.menuMode !== 'single' && menuOutsideStore.setHeaderActived(to.path)
|
||||
if (to.name) {
|
||||
if (to.matched.length !== 0) {
|
||||
// 如果已登录状态下,进入登录页会强制跳转到控制台页面
|
||||
@ -157,7 +157,7 @@ router.beforeEach(async(to, from, next) => {
|
||||
name: 'dashboard',
|
||||
replace: true
|
||||
})
|
||||
} else if (!settingsOutsideStore.enableDashboard && to.name == 'dashboard') {
|
||||
} else if (!settingsOutsideStore.dashboard.enable && to.name == 'dashboard') {
|
||||
// 如果未开启控制台页面,则默认进入侧边栏导航第一个模块
|
||||
if (menuOutsideStore.sidebarRoutes.length > 0) {
|
||||
next({
|
||||
@ -181,7 +181,7 @@ router.beforeEach(async(to, from, next) => {
|
||||
}
|
||||
} else {
|
||||
let accessRoutes = []
|
||||
if (!settingsOutsideStore.enableBackendReturnRoute) {
|
||||
if (!settingsOutsideStore.app.enableBackendReturnRoute) {
|
||||
accessRoutes = await menuOutsideStore.generateRoutesAtFront(asyncRoutes)
|
||||
} else {
|
||||
accessRoutes = await menuOutsideStore.generateRoutesAtBack()
|
||||
@ -214,7 +214,7 @@ router.beforeEach(async(to, from, next) => {
|
||||
router.afterEach((to, from) => {
|
||||
const settingsOutsideStore = useSettingsOutsideStore()
|
||||
const keepAliveOutsideStore = useKeepAliveOutsideStore()
|
||||
settingsOutsideStore.enableProgress && (isLoading.value = false)
|
||||
settingsOutsideStore.app.enableProgress && (isLoading.value = false)
|
||||
// 设置页面 title
|
||||
to.meta.title && settingsOutsideStore.setTitle(typeof to.meta.title === 'function' ? to.meta.title() : to.meta.title)
|
||||
// 判断当前页面是否开启缓存,如果开启,则将当前页面的 name 信息存入 keep-alive 全局状态
|
||||
|
1
src/settings.custom.json
Normal file
1
src/settings.custom.json
Normal file
@ -0,0 +1 @@
|
||||
{}
|
136
src/settings.js
136
src/settings.js
@ -1,68 +1,88 @@
|
||||
let globalSettings = {
|
||||
/**
|
||||
* 是否开启权限功能,权限功能提供以下鉴权支持:
|
||||
* 1、路由鉴权
|
||||
* 2、鉴权组件:<Auth></Auth>、<AuthAll></AuthAll>
|
||||
* 3、鉴权指令:v-auth、v-auth-all
|
||||
* 4、鉴权函数:this.$auth()、this.$authAll()
|
||||
*/
|
||||
enablePermission: false,
|
||||
/**
|
||||
* 导航栏模式
|
||||
* side 侧边栏模式(含主导航)
|
||||
* head 顶部模式
|
||||
* single 侧边栏模式(无主导航)
|
||||
*/
|
||||
menuMode: 'side',
|
||||
// Element 组件默认尺寸,支持:large、default、small
|
||||
elementSize: 'default',
|
||||
// 是否开启侧边栏展开收起按钮
|
||||
enableSidebarCollapse: false,
|
||||
// 侧边栏是否收起
|
||||
sidebarCollapse: false,
|
||||
// 切换侧边栏同时跳转页面
|
||||
switchSidebarAndPageJump: false,
|
||||
// 侧边栏只保持一个子菜单的展开
|
||||
sidebarUniqueOpened: true,
|
||||
// 顶栏是否固定
|
||||
topbarFixed: true,
|
||||
// 是否开启面包屑导航
|
||||
enableBreadcrumb: true,
|
||||
// 是否显示底部版权信息,同时在路由 meta 对象里可以单独设置某个路由是否显示底部版权信息
|
||||
showCopyright: true,
|
||||
// 版权信息配置,格式为:Copyright © [dates] <company>, All Rights Reserved
|
||||
copyrightDates: '2020-2021',
|
||||
copyrightCompany: 'Fantastic-admin',
|
||||
copyrightWebsite: 'https://hooray.github.io/fantastic-admin',
|
||||
// 是否开启导航搜索
|
||||
enableNavSearch: true,
|
||||
// 是否开启移动端适配,开启后当页面宽度小于 992px 时自动切换为移动端展示
|
||||
enableMobileAdaptation: true,
|
||||
// 是否开启全屏
|
||||
enableFullscreen: false,
|
||||
// 是否开启页面刷新
|
||||
enablePageReload: false,
|
||||
// 是否开启载入进度条
|
||||
enableProgress: true,
|
||||
// 是否开启动态标题
|
||||
enableDynamicTitle: false,
|
||||
// 是否开启控制台
|
||||
enableDashboard: true,
|
||||
// 控制台名称
|
||||
dashboardTitle: '控制台',
|
||||
// 是否开启后端返回路由数据
|
||||
enableBackendReturnRoute: false,
|
||||
app: {
|
||||
// Element 组件默认尺寸,支持:large、default、small
|
||||
elementSize: 'default',
|
||||
/**
|
||||
* 是否开启权限功能,权限功能提供以下鉴权支持:
|
||||
* 1、路由鉴权
|
||||
* 2、鉴权组件:<Auth></Auth>、<AuthAll></AuthAll>
|
||||
* 3、鉴权指令:v-auth、v-auth-all
|
||||
* 4、鉴权函数:this.$auth()、this.$authAll()
|
||||
*/
|
||||
enablePermission: false,
|
||||
// 是否开启后端返回路由数据
|
||||
enableBackendReturnRoute: false,
|
||||
// 是否开启载入进度条
|
||||
enableProgress: true,
|
||||
// 是否开启动态标题
|
||||
enableDynamicTitle: false
|
||||
},
|
||||
// 控制台
|
||||
dashboard: {
|
||||
// 是否开启
|
||||
enable: true,
|
||||
// 控制台名称
|
||||
title: '控制台'
|
||||
},
|
||||
// 布局
|
||||
layout: {
|
||||
// 是否开启移动端适配,开启后当页面宽度小于 992px 时自动切换为移动端展示
|
||||
enableMobileAdaptation: true
|
||||
},
|
||||
// 导航栏
|
||||
menu: {
|
||||
/**
|
||||
* 导航栏模式
|
||||
* side 侧边栏模式(含主导航)
|
||||
* head 顶部模式
|
||||
* single 侧边栏模式(无主导航)
|
||||
*/
|
||||
menuMode: 'side',
|
||||
// 切换主导航同时跳转页面
|
||||
switchMainMenuAndPageJump: false,
|
||||
// 次导航只保持一个子项的展开
|
||||
subMenuUniqueOpened: true,
|
||||
// 次导航是否收起
|
||||
subMenuCollapse: false
|
||||
},
|
||||
// 顶栏
|
||||
topbar: {
|
||||
// 是否固定
|
||||
fixed: true,
|
||||
// 是否开启侧边栏展开收起按钮
|
||||
enableSidebarCollapse: false,
|
||||
// 是否开启面包屑导航
|
||||
enableBreadcrumb: true,
|
||||
// 是否开启导航搜索
|
||||
enableNavSearch: true,
|
||||
// 是否开启全屏
|
||||
enableFullscreen: false,
|
||||
// 是否开启页面刷新
|
||||
enablePageReload: false
|
||||
},
|
||||
// 底部版权
|
||||
copyright: {
|
||||
// 是否开启,同时在路由 meta 对象里可以单独设置某个路由是否显示底部版权信息
|
||||
enable: true,
|
||||
// 版权信息配置,格式为:Copyright © [dates] <company>, All Rights Reserved
|
||||
dates: '2020-2022',
|
||||
company: 'Fantastic-admin',
|
||||
website: 'https://hooray.github.io/fantastic-admin'
|
||||
},
|
||||
// 是否开启主题配置(建议在生产环境关闭)
|
||||
enableThemeSetting: true
|
||||
}
|
||||
|
||||
import settingsCustom from './settings.custom.json'
|
||||
Object.assign(globalSettings, settingsCustom)
|
||||
|
||||
// 演示&开发环境开启全部功能(这部分代码可删除,仅方便作者打包演示环境)
|
||||
if (import.meta.env.VITE_APP_MODE === 'example' || import.meta.env.MODE === 'development') {
|
||||
globalSettings.enablePermission = true
|
||||
globalSettings.enableSidebarCollapse = true
|
||||
globalSettings.enableFullscreen = true
|
||||
globalSettings.enablePageReload = true
|
||||
globalSettings.enableDynamicTitle = true
|
||||
globalSettings.app.enablePermission = true
|
||||
globalSettings.app.enableDynamicTitle = true
|
||||
globalSettings.topbar.enableSidebarCollapse = true
|
||||
globalSettings.topbar.enableFullscreen = true
|
||||
globalSettings.topbar.enablePageReload = true
|
||||
}
|
||||
|
||||
export default globalSettings
|
||||
|
@ -157,7 +157,7 @@ export const useMenuStore = defineStore(
|
||||
transformRoutes: state => {
|
||||
let routes
|
||||
const settingsStore = useSettingsStore()
|
||||
if (settingsStore.menuMode === 'single') {
|
||||
if (settingsStore.menu.menuMode === 'single') {
|
||||
routes = [{ children: [] }]
|
||||
state.routes.map(item => {
|
||||
routes[0].children.push(...item.children)
|
||||
@ -183,7 +183,7 @@ export const useMenuStore = defineStore(
|
||||
const userStore = useUserStore()
|
||||
let accessedRoutes
|
||||
// 如果权限功能开启,则需要对路由数据进行筛选过滤
|
||||
if (settingsStore.enablePermission) {
|
||||
if (settingsStore.app.enablePermission) {
|
||||
const permissions = await userStore.getPermissions()
|
||||
accessedRoutes = filterAsyncRoutes(asyncRoutes, permissions)
|
||||
} else {
|
||||
@ -231,7 +231,7 @@ export const useMenuStore = defineStore(
|
||||
let asyncRoutes = formatBackRoutes(res.data)
|
||||
let accessedRoutes
|
||||
// 如果权限功能开启,则需要对路由数据进行筛选过滤
|
||||
if (settingsStore.enablePermission) {
|
||||
if (settingsStore.app.enablePermission) {
|
||||
const permissions = await userStore.getPermissions()
|
||||
accessedRoutes = filterAsyncRoutes(asyncRoutes, permissions)
|
||||
} else {
|
||||
|
@ -9,7 +9,7 @@ export const useSettingsStore = defineStore(
|
||||
state: () => ({
|
||||
...settings,
|
||||
// 侧边栏是否收起(用于记录 pc 模式下最后的状态)
|
||||
sidebarCollapseLastStatus: settings.sidebarCollapse,
|
||||
subMenuCollapseLastStatus: settings.menu.subMenuCollapse,
|
||||
// 显示模式,支持:mobile、pc
|
||||
mode: 'pc',
|
||||
// 页面标题
|
||||
@ -18,7 +18,7 @@ export const useSettingsStore = defineStore(
|
||||
actions: {
|
||||
// 设置访问模式
|
||||
setMode(width) {
|
||||
if (this.enableMobileAdaptation) {
|
||||
if (this.layout.enableMobileAdaptation) {
|
||||
// 先判断 UA 是否为移动端设备(手机&平板)
|
||||
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
|
||||
this.mode = 'mobile'
|
||||
@ -40,9 +40,9 @@ export const useSettingsStore = defineStore(
|
||||
},
|
||||
// 切换侧边栏导航展开/收起
|
||||
toggleSidebarCollapse() {
|
||||
this.sidebarCollapse = !this.sidebarCollapse
|
||||
this.menu.subMenuCollapse = !this.menu.subMenuCollapse
|
||||
if (this.mode == 'pc') {
|
||||
this.sidebarCollapseLastStatus = !this.sidebarCollapseLastStatus
|
||||
this.subMenuCollapseLastStatus = !this.subMenuCollapseLastStatus
|
||||
}
|
||||
},
|
||||
// 更新主题配置
|
||||
|
@ -38,7 +38,7 @@ export function deepClone(target) {
|
||||
function hasPermission(permission) {
|
||||
const settingsOutsideStore = useSettingsOutsideStore()
|
||||
const userOutsideStore = useUserOutsideStore()
|
||||
if (settingsOutsideStore.enablePermission) {
|
||||
if (settingsOutsideStore.app.enablePermission) {
|
||||
return userOutsideStore.permissions.some(v => {
|
||||
return v === permission
|
||||
})
|
||||
|
@ -80,7 +80,7 @@
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<Copyright v-if="settingsStore.showCopyright" />
|
||||
<Copyright v-if="settingsStore.copyright.enable" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<page-header title="权限验证" />
|
||||
<page-main>
|
||||
<div v-if="!settingsStore.enablePermission">请到 seeting.js 里打开权限功能,再进入该页面查看演示</div>
|
||||
<div v-if="!settingsStore.app.enablePermission">请到 seeting.js 里打开权限功能,再进入该页面查看演示</div>
|
||||
<div v-else>
|
||||
<h3>切换帐号</h3>
|
||||
<el-radio-group v-model="userStore.account" @change="accountChange">
|
||||
|
Loading…
Reference in New Issue
Block a user