mirror of
https://gitee.com/fantastic-admin/basic.git
synced 2024-12-05 21:47:55 +08:00
layout/ 目录下文件用 script setup 语法糖重写
This commit is contained in:
parent
94d4a23fd2
commit
5d06055af8
@ -44,25 +44,3 @@ $g-sub-sidebar-menu-hover-bg: darken(#fafafa, 10);
|
||||
$g-sub-sidebar-menu-active-color: #e7f4ff;
|
||||
// 菜单选中背景色
|
||||
$g-sub-sidebar-menu-active-bg: #5482ee;
|
||||
// 【导航标记】
|
||||
// 背景色
|
||||
$g-badge-bg: #f56c6c;
|
||||
// 文字颜色
|
||||
$g-badge-color: #fff;
|
||||
// 边框颜色
|
||||
$g-badge-border-color:#fff;
|
||||
// 【标签栏】
|
||||
// 背景色
|
||||
$g-tabbar-bg: #f0f2f5;
|
||||
// 分割线颜色
|
||||
$g-tabbar-dividers-bg: #a9adb0;
|
||||
// 标签文字颜色
|
||||
$g-tabbar-tab-color: #999;
|
||||
// 标签鼠标悬浮文字颜色
|
||||
$g-tabbar-tab-hover-color: #999;
|
||||
// 标签鼠标悬浮背景色
|
||||
$g-tabbar-tab-hover-bg: #dee1e6;
|
||||
// 标签选中文字颜色
|
||||
$g-tabbar-tab-active-color: #97a8be;
|
||||
// 标签选中背景色
|
||||
$g-tabbar-tab-active-bg: #fff;
|
||||
|
@ -23,29 +23,29 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
locationOrigin: () => location.origin
|
||||
},
|
||||
mounted() {
|
||||
this.$notify({
|
||||
type: 'success',
|
||||
title: '温馨提示',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: `
|
||||
<script setup>
|
||||
import { getCurrentInstance, onMounted, ref } from 'vue'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
const locationOrigin = ref(location.href)
|
||||
|
||||
onMounted(() => {
|
||||
proxy.$notify({
|
||||
type: 'success',
|
||||
title: '温馨提示',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: `
|
||||
<p>当前访问的是<b>基础版</b> (Vue3)</p>
|
||||
<p>你可以点<a href="https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/vue3/pro/" target="_blank"><b>这里</b></a>访问专业版 (Vue3)</p>
|
||||
`,
|
||||
position: 'bottom-right',
|
||||
duration: 5000
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
open(url) {
|
||||
window.open(url, 'top')
|
||||
}
|
||||
}
|
||||
position: 'bottom-right',
|
||||
duration: 5000
|
||||
})
|
||||
})
|
||||
|
||||
function open(url) {
|
||||
window.open(url, 'top')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -20,18 +20,12 @@
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import Logo from '../Logo/index.vue'
|
||||
import UserMenu from '../UserMenu/index.vue'
|
||||
import { inject } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'Header',
|
||||
components: {
|
||||
Logo,
|
||||
UserMenu
|
||||
},
|
||||
inject: ['switchMenu']
|
||||
}
|
||||
const switchMenu = inject('switchMenu')
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -1,45 +1,38 @@
|
||||
<template>
|
||||
<router-link :to="to" :class="{
|
||||
'title': true,
|
||||
'is-link': $store.state.settings.enableDashboard
|
||||
}" :title="title"
|
||||
>
|
||||
<router-link :to="to" class="title" :class="{'is-link': $store.state.settings.enableDashboard}" :title="title">
|
||||
<img v-if="showLogo" :src="logo" class="logo">
|
||||
<span v-if="showTitle">{{ title }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import imgLogo from '@/assets/images/logo.png'
|
||||
import { defineProps, ref, computed } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Logo',
|
||||
props: {
|
||||
showLogo: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showTitle: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
const store = useStore()
|
||||
|
||||
defineProps({
|
||||
showLogo: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: import.meta.env.VITE_APP_TITLE,
|
||||
logo: imgLogo
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
to() {
|
||||
let rtn = {}
|
||||
if (this.$store.state.settings.enableDashboard) {
|
||||
rtn.name = 'dashboard'
|
||||
}
|
||||
return rtn
|
||||
}
|
||||
showTitle: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const title = ref(import.meta.env.VITE_APP_TITLE)
|
||||
const logo = ref(imgLogo)
|
||||
|
||||
const to = computed(() => {
|
||||
let rtn = {}
|
||||
if (store.state.settings.enableDashboard) {
|
||||
rtn.name = 'dashboard'
|
||||
}
|
||||
return rtn
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -19,16 +19,11 @@
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import Logo from '../Logo/index.vue'
|
||||
import { inject } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'MainSidebar',
|
||||
components: {
|
||||
Logo
|
||||
},
|
||||
inject: ['switchMenu']
|
||||
}
|
||||
const switchMenu = inject('switchMenu')
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div id="search" :class="{'searching': isShow}" @click="isShow && $eventBus.emit('global-search-toggle')">
|
||||
<div class="container">
|
||||
<div class="search-box" @click.stop>
|
||||
<el-input ref="input" v-model="search" prefix-icon="el-icon-search" placeholder="搜索页面,支持标题、URL模糊查询" clearable @keydown.esc="$eventBus.emit('global-search-toggle')" @keydown.up.prevent="keyUp" @keydown.down.prevent="keyDown" @keydown.enter.prevent="keyEnter" />
|
||||
<el-input ref="input" v-model="searchInput" prefix-icon="el-icon-search" placeholder="搜索页面,支持标题、URL模糊查询" clearable @keydown.esc="$eventBus.emit('global-search-toggle')" @keydown.up.prevent="keyUp" @keydown.down.prevent="keyDown" @keydown.enter.prevent="keyEnter" />
|
||||
<div class="tips">
|
||||
<div class="tip">
|
||||
<span>Alt</span>+<span>S</span>
|
||||
@ -35,7 +35,7 @@
|
||||
<svg-icon v-if="item.isExternal" name="external-link" />
|
||||
</div>
|
||||
<div class="breadcrumb">
|
||||
<span v-for="(bc, index) in item.breadcrumb" :key="index">
|
||||
<span v-for="(bc, bcIndex) in item.breadcrumb" :key="bcIndex">
|
||||
{{ bc }}
|
||||
<i class="el-icon-arrow-right" />
|
||||
</span>
|
||||
@ -49,169 +49,163 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { deepClone } from '@/util'
|
||||
import { computed, getCurrentInstance, onMounted, ref, watch } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Search',
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
isShow: false,
|
||||
search: '',
|
||||
sourceList: [],
|
||||
actived: -1
|
||||
const { proxy } = getCurrentInstance()
|
||||
const store = useStore()
|
||||
|
||||
const isShow = ref(false)
|
||||
const searchInput = ref('')
|
||||
const sourceList = ref([])
|
||||
const actived = ref(-1)
|
||||
|
||||
const resultList = computed(() => {
|
||||
let result = []
|
||||
result = sourceList.value.filter(item => {
|
||||
let flag = false
|
||||
if (item.title.indexOf(searchInput.value) >= 0) {
|
||||
flag = true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
resultList() {
|
||||
let result = []
|
||||
result = this.sourceList.filter(item => {
|
||||
let flag = false
|
||||
if (item.title.indexOf(this.search) >= 0) {
|
||||
flag = true
|
||||
}
|
||||
if (item.path.indexOf(this.search) >= 0) {
|
||||
flag = true
|
||||
}
|
||||
if (item.breadcrumb.some(b => b.indexOf(this.search) >= 0)) {
|
||||
flag = true
|
||||
}
|
||||
return flag
|
||||
})
|
||||
return result
|
||||
if (item.path.indexOf(searchInput.value) >= 0) {
|
||||
flag = true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isShow(val) {
|
||||
if (val) {
|
||||
document.querySelector('body').classList.add('hidden')
|
||||
this.$refs.search.scrollTop = 0
|
||||
// 当搜索显示的时候绑定上、下、回车快捷键,隐藏的时候再解绑。另外当 input 处于 focus 状态时,采用 vue 来绑定键盘事件
|
||||
this.$hotkeys('up', this.keyUp)
|
||||
this.$hotkeys('down', this.keyDown)
|
||||
this.$hotkeys('enter', this.keyEnter)
|
||||
setTimeout(() => {
|
||||
this.$refs.input.$el.children[0].focus()
|
||||
}, 100)
|
||||
if (item.breadcrumb.some(b => b.indexOf(searchInput.value) >= 0)) {
|
||||
flag = true
|
||||
}
|
||||
return flag
|
||||
})
|
||||
return result
|
||||
})
|
||||
|
||||
watch(() => isShow.value, val => {
|
||||
if (val) {
|
||||
document.querySelector('body').classList.add('hidden')
|
||||
proxy.$refs.search.scrollTop = 0
|
||||
// 当搜索显示的时候绑定上、下、回车快捷键,隐藏的时候再解绑。另外当 input 处于 focus 状态时,采用 vue 来绑定键盘事件
|
||||
proxy.$hotkeys('up', keyUp)
|
||||
proxy.$hotkeys('down', keyDown)
|
||||
proxy.$hotkeys('enter', keyEnter)
|
||||
setTimeout(() => {
|
||||
proxy.$refs.input.$el.children[0].focus()
|
||||
}, 100)
|
||||
} else {
|
||||
document.querySelector('body').classList.remove('hidden')
|
||||
proxy.$hotkeys.unbind('up', keyUp)
|
||||
proxy.$hotkeys.unbind('down', keyDown)
|
||||
proxy.$hotkeys.unbind('enter', keyEnter)
|
||||
setTimeout(() => {
|
||||
searchInput.value = ''
|
||||
actived.value = -1
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
watch(() => resultList.value, () => {
|
||||
actived.value = -1
|
||||
scrollTo(0)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
proxy.$eventBus.on('global-search-toggle', () => {
|
||||
isShow.value = !isShow.value
|
||||
})
|
||||
proxy.$hotkeys('alt+s', e => {
|
||||
if (store.state.settings.enableNavSearch) {
|
||||
e.preventDefault()
|
||||
isShow.value = true
|
||||
}
|
||||
})
|
||||
store.state.menu.routes.map(item => {
|
||||
getSourceList(item.children)
|
||||
})
|
||||
})
|
||||
|
||||
function isExternal(path) {
|
||||
return /^(https?:|mailto:|tel:)/.test(path)
|
||||
}
|
||||
function hasChildren(item) {
|
||||
let flag = true
|
||||
if (item.children) {
|
||||
if (item.children.every(i => i.meta.sidebar === false)) {
|
||||
flag = false
|
||||
}
|
||||
} else {
|
||||
flag = false
|
||||
}
|
||||
return flag
|
||||
}
|
||||
function getSourceList(arr) {
|
||||
arr.map(item => {
|
||||
if (item.meta.sidebar !== false) {
|
||||
if (hasChildren(item)) {
|
||||
let baseBreadcrumb = item.meta.baseBreadcrumb ? deepClone(item.meta.baseBreadcrumb) : []
|
||||
baseBreadcrumb.push(item.meta.title)
|
||||
let child = deepClone(item.children)
|
||||
child.map(c => {
|
||||
c.meta.baseIcon = item.meta.icon || item.meta.baseIcon
|
||||
c.meta.baseBreadcrumb = baseBreadcrumb
|
||||
c.meta.basePath = item.meta.basePath ? [item.meta.basePath, item.path].join('/') : item.path
|
||||
})
|
||||
getSourceList(child)
|
||||
} else {
|
||||
document.querySelector('body').classList.remove('hidden')
|
||||
this.$hotkeys.unbind('up', this.keyUp)
|
||||
this.$hotkeys.unbind('down', this.keyDown)
|
||||
this.$hotkeys.unbind('enter', this.keyEnter)
|
||||
setTimeout(() => {
|
||||
this.search = ''
|
||||
this.actived = -1
|
||||
}, 500)
|
||||
let breadcrumb = []
|
||||
if (item.meta.baseBreadcrumb) {
|
||||
breadcrumb = deepClone(item.meta.baseBreadcrumb)
|
||||
}
|
||||
breadcrumb.push(item.meta.title)
|
||||
let path = ''
|
||||
if (isExternal(item.path)) {
|
||||
path = item.path
|
||||
} else {
|
||||
path = item.meta.basePath ? [item.meta.basePath, item.path].join('/') : item.path
|
||||
}
|
||||
sourceList.value.push({
|
||||
icon: item.meta.icon || item.meta.baseIcon,
|
||||
title: item.meta.title,
|
||||
i18n: item.meta.i18n,
|
||||
breadcrumb: breadcrumb,
|
||||
path: path,
|
||||
isExternal: isExternal(item.path)
|
||||
})
|
||||
}
|
||||
},
|
||||
resultList() {
|
||||
this.actived = -1
|
||||
this.scrollTo(0)
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.$eventBus.on('global-search-toggle', () => {
|
||||
this.isShow = !this.isShow
|
||||
})
|
||||
this.$hotkeys('alt+s', e => {
|
||||
if (this.$store.state.settings.enableNavSearch) {
|
||||
e.preventDefault()
|
||||
this.isShow = true
|
||||
}
|
||||
})
|
||||
this.$store.state.menu.routes.map(item => {
|
||||
this.getSourceList(item.children)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
isExternal(path) {
|
||||
return /^(https?:|mailto:|tel:)/.test(path)
|
||||
},
|
||||
hasChildren(item) {
|
||||
let flag = true
|
||||
if (item.children) {
|
||||
if (item.children.every(i => i.meta.sidebar === false)) {
|
||||
flag = false
|
||||
}
|
||||
} else {
|
||||
flag = false
|
||||
}
|
||||
return flag
|
||||
},
|
||||
getSourceList(arr) {
|
||||
arr.map(item => {
|
||||
if (item.meta.sidebar !== false) {
|
||||
if (this.hasChildren(item)) {
|
||||
let baseBreadcrumb = item.meta.baseBreadcrumb ? deepClone(item.meta.baseBreadcrumb) : []
|
||||
baseBreadcrumb.push(item.meta.title)
|
||||
let child = deepClone(item.children)
|
||||
child.map(c => {
|
||||
c.meta.baseIcon = item.meta.icon || item.meta.baseIcon
|
||||
c.meta.baseBreadcrumb = baseBreadcrumb
|
||||
c.meta.basePath = item.meta.basePath ? [item.meta.basePath, item.path].join('/') : item.path
|
||||
})
|
||||
this.getSourceList(child)
|
||||
} else {
|
||||
let breadcrumb = []
|
||||
if (item.meta.baseBreadcrumb) {
|
||||
breadcrumb = deepClone(item.meta.baseBreadcrumb)
|
||||
}
|
||||
breadcrumb.push(item.meta.title)
|
||||
let path = ''
|
||||
if (this.isExternal(item.path)) {
|
||||
path = item.path
|
||||
} else {
|
||||
path = item.meta.basePath ? [item.meta.basePath, item.path].join('/') : item.path
|
||||
}
|
||||
this.sourceList.push({
|
||||
icon: item.meta.icon || item.meta.baseIcon,
|
||||
title: item.meta.title,
|
||||
i18n: item.meta.i18n,
|
||||
breadcrumb: breadcrumb,
|
||||
path: path,
|
||||
isExternal: this.isExternal(item.path)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
function keyUp() {
|
||||
if (resultList.value.length) {
|
||||
actived.value -= 1
|
||||
if (actived.value < 0) {
|
||||
actived.value = resultList.value.length - 1
|
||||
}
|
||||
scrollTo(proxy.$refs[`search-item-${actived.value}`].offsetTop)
|
||||
}
|
||||
}
|
||||
function keyDown() {
|
||||
if (resultList.value.length) {
|
||||
actived.value += 1
|
||||
if (actived.value > resultList.value.length - 1) {
|
||||
actived.value = 0
|
||||
}
|
||||
scrollTo(proxy.$refs[`search-item-${actived.value}`].offsetTop)
|
||||
}
|
||||
}
|
||||
function keyEnter() {
|
||||
if (actived.value !== -1) {
|
||||
proxy.$refs[`search-item-${actived.value}`].click()
|
||||
}
|
||||
}
|
||||
function scrollTo(offsetTop) {
|
||||
if (actived.value !== -1) {
|
||||
if (
|
||||
offsetTop + proxy.$refs[`search-item-${actived.value}`].clientHeight > proxy.$refs['search'].scrollTop + proxy.$refs['search'].clientHeight ||
|
||||
offsetTop + proxy.$refs[`search-item-${actived.value}`].clientHeight <= proxy.$refs['search'].scrollTop
|
||||
) {
|
||||
proxy.$refs['search'].scrollTo({
|
||||
top: offsetTop,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
},
|
||||
keyUp() {
|
||||
if (this.resultList.length) {
|
||||
this.actived -= 1
|
||||
if (this.actived < 0) {
|
||||
this.actived = this.resultList.length - 1
|
||||
}
|
||||
this.scrollTo(this.$refs[`search-item-${this.actived}`].offsetTop)
|
||||
}
|
||||
},
|
||||
keyDown() {
|
||||
if (this.resultList.length) {
|
||||
this.actived += 1
|
||||
if (this.actived > this.resultList.length - 1) {
|
||||
this.actived = 0
|
||||
}
|
||||
this.scrollTo(this.$refs[`search-item-${this.actived}`].offsetTop)
|
||||
}
|
||||
},
|
||||
keyEnter() {
|
||||
if (this.actived !== -1) {
|
||||
this.$refs[`search-item-${this.actived}`].click()
|
||||
}
|
||||
},
|
||||
scrollTo(offsetTop) {
|
||||
if (this.actived !== -1) {
|
||||
if (
|
||||
offsetTop + this.$refs[`search-item-${this.actived}`].clientHeight > this.$refs['search'].scrollTop + this.$refs['search'].clientHeight ||
|
||||
offsetTop + this.$refs[`search-item-${this.actived}`].clientHeight <= this.$refs['search'].scrollTop
|
||||
) {
|
||||
this.$refs['search'].scrollTo({
|
||||
top: offsetTop,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,14 +10,8 @@
|
||||
<router-link v-else-if="!hasChildren" v-slot="{ href, navigate, isActive, isExactActive }" custom :to="resolvePath(item.path)">
|
||||
<a :href="isExternal(resolvePath(item.path)) ? resolvePath(item.path) : href" :class="[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']" :target="isExternal(resolvePath(item.path)) ? '_blank' : '_self'" @click="navigate">
|
||||
<el-menu-item :title="item.meta.title" :index="resolvePath(item.path)">
|
||||
<svg-icon v-if="iconName(isActive || isExactActive, item.meta.icon, item.meta.activeIcon)" :name="iconName(isActive || isExactActive, item.meta.icon, item.meta.activeIcon)" class="icon" />
|
||||
<svg-icon v-if="iconName(isActive || isExactActive, item.meta.icon)" :name="iconName(isActive || isExactActive, item.meta.icon)" class="icon" />
|
||||
<span class="title">{{ item.meta.title }}</span>
|
||||
<span v-if="badge(item.meta.badge).visible" :class="{
|
||||
'badge': true,
|
||||
'badge-dot': badge(item.meta.badge).type === 'dot',
|
||||
'badge-text': badge(item.meta.badge).type === 'text'
|
||||
}"
|
||||
>{{ badge(item.meta.badge).type === 'text' ? badge(item.meta.badge).value : '' }}</span>
|
||||
</el-menu-item>
|
||||
</a>
|
||||
</router-link>
|
||||
@ -26,102 +20,58 @@
|
||||
<svg-icon v-if="item.meta.icon" :name="item.meta.icon" class="icon unactive" />
|
||||
<svg-icon v-if="item.meta.activeIcon || item.meta.icon" :name="item.meta.activeIcon || item.meta.icon" class="icon active" />
|
||||
<span class="title">{{ item.meta.title }}</span>
|
||||
<span v-if="badge(item.meta.badge).visible" :class="{
|
||||
'badge': true,
|
||||
'badge-dot': badge(item.meta.badge).type === 'dot',
|
||||
'badge-text': badge(item.meta.badge).type === 'text'
|
||||
}"
|
||||
>{{ badge(item.meta.badge).type === 'text' ? badge(item.meta.badge).value : '' }}</span>
|
||||
</template>
|
||||
<SidebarItem v-for="route in item.children" :key="route.path" :item="route" :base-path="resolvePath(item.path)" />
|
||||
</el-sub-menu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import SidebarItem from './index.vue'
|
||||
import path from 'path-browserify'
|
||||
import { computed, defineProps } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'SidebarItem',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
basePath: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
hasChildren() {
|
||||
let flag = true
|
||||
if (this.item.children) {
|
||||
if (this.item.children.every(item => item.meta.sidebar === false)) {
|
||||
flag = false
|
||||
}
|
||||
} else {
|
||||
flag = false
|
||||
}
|
||||
return flag
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
isExternal(path) {
|
||||
return /^(https?:|mailto:|tel:)/.test(path)
|
||||
},
|
||||
resolvePath(routePath) {
|
||||
if (this.isExternal(routePath)) {
|
||||
return routePath
|
||||
}
|
||||
if (this.isExternal(this.basePath)) {
|
||||
return this.basePath
|
||||
}
|
||||
return this.basePath ? path.resolve(this.basePath, routePath) : routePath
|
||||
},
|
||||
iconName(isActive, icon, activeIcon) {
|
||||
let name = ''
|
||||
if ((!isActive && icon) || (isActive && !activeIcon)) {
|
||||
name = icon
|
||||
} else if (isActive && activeIcon) {
|
||||
name = activeIcon
|
||||
}
|
||||
return name
|
||||
},
|
||||
badge(badge) {
|
||||
let res = {
|
||||
type: '', // text or dot
|
||||
value: '',
|
||||
visible: false
|
||||
}
|
||||
if (badge) {
|
||||
res.visible = true
|
||||
res.value = typeof badge == 'function' ? badge() : badge
|
||||
if (typeof res.value == 'boolean') {
|
||||
res.type = 'dot'
|
||||
if (!res.value) {
|
||||
res.visible = false
|
||||
}
|
||||
} else if (typeof res.value == 'number') {
|
||||
res.type = 'text'
|
||||
if (res.value <= 0) {
|
||||
res.visible = false
|
||||
}
|
||||
} else {
|
||||
res.type = 'text'
|
||||
if (!res.value) {
|
||||
res.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
basePath: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const hasChildren = computed(() => {
|
||||
let flag = true
|
||||
if (props.item.children) {
|
||||
if (props.item.children.every(item => item.meta.sidebar === false)) {
|
||||
flag = false
|
||||
}
|
||||
} else {
|
||||
flag = false
|
||||
}
|
||||
return flag
|
||||
})
|
||||
|
||||
function isExternal(path) {
|
||||
return /^(https?:|mailto:|tel:)/.test(path)
|
||||
}
|
||||
function resolvePath(routePath) {
|
||||
if (isExternal(routePath)) {
|
||||
return routePath
|
||||
}
|
||||
if (isExternal(props.basePath)) {
|
||||
return props.basePath
|
||||
}
|
||||
return props.basePath ? path.resolve(props.basePath, routePath) : routePath
|
||||
}
|
||||
function iconName(isActive, icon) {
|
||||
let name = ''
|
||||
if (!isActive && icon) {
|
||||
name = icon
|
||||
}
|
||||
return name
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -176,52 +126,6 @@ a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.badge {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
background-color: $g-badge-bg;
|
||||
box-shadow: 0 0 0 1px $g-badge-border-color;
|
||||
@include position-center(y);
|
||||
&-dot {
|
||||
right: 15px;
|
||||
border-radius: 50%;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
&::after {
|
||||
content: '';
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
display: block;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
animation: dot-twinkling 1s infinite ease-in-out;
|
||||
background-color: $g-badge-bg;
|
||||
}
|
||||
}
|
||||
@keyframes dot-twinkling {
|
||||
0% {
|
||||
opacity: 0.6;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(2.4);
|
||||
}
|
||||
}
|
||||
&-text {
|
||||
right: 15px;
|
||||
border-radius: 10px;
|
||||
font-size: 12px;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
padding: 0 6px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
color: $g-badge-color;
|
||||
}
|
||||
}
|
||||
.el-sub-menu__title {
|
||||
> .badge {
|
||||
&-dot {
|
||||
|
@ -20,26 +20,15 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import Logo from '../Logo/index.vue'
|
||||
import SidebarItem from '../SidebarItem/index.vue'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'SubSidebar',
|
||||
components: {
|
||||
Logo,
|
||||
SidebarItem
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sidebarScrollTop: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSidebarScroll(e) {
|
||||
this.sidebarScrollTop = e.target.scrollTop
|
||||
}
|
||||
}
|
||||
const sidebarScrollTop = ref(0)
|
||||
|
||||
function onSidebarScroll(e) {
|
||||
sidebarScrollTop.value = e.target.scrollTop
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -139,178 +139,179 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ThemeSetting',
|
||||
inject: ['reload'],
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
isShow: false
|
||||
}
|
||||
<script setup>
|
||||
import { computed, getCurrentInstance, inject, onMounted, ref } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const store = useStore()
|
||||
const route = useRoute()
|
||||
|
||||
const reload = inject('reload')
|
||||
|
||||
const isShow = ref(false)
|
||||
|
||||
const menuMode = computed({
|
||||
get: function() {
|
||||
return store.state.settings.menuMode
|
||||
},
|
||||
computed: {
|
||||
menuMode: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.menuMode
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('menu/switchHeaderActived', 0)
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'menuMode': newValue
|
||||
})
|
||||
this.$store.state.settings.menuMode !== 'single' && this.$store.commit('menu/setHeaderActived', this.$route.fullPath)
|
||||
}
|
||||
},
|
||||
elementSize: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.elementSize
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$ELEMENT.size = newValue
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'elementSize': newValue
|
||||
})
|
||||
this.reload()
|
||||
}
|
||||
},
|
||||
enableSidebarCollapse: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.enableSidebarCollapse
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'enableSidebarCollapse': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
sidebarCollapse: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.sidebarCollapse
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'sidebarCollapse': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
switchSidebarAndPageJump: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.switchSidebarAndPageJump
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'switchSidebarAndPageJump': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
sidebarUniqueOpened: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.sidebarUniqueOpened
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'sidebarUniqueOpened': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
topbarFixed: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.topbarFixed
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'topbarFixed': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
enableBreadcrumb: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.enableBreadcrumb
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'enableBreadcrumb': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
showCopyright: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.showCopyright
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'showCopyright': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
enableNavSearch: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.enableNavSearch
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'enableNavSearch': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
enableFullscreen: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.enableFullscreen
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'enableFullscreen': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
enablePageReload: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.enablePageReload
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'enablePageReload': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
enableProgress: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.enableProgress
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'enableProgress': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
enableDynamicTitle: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.enableDynamicTitle
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'enableDynamicTitle': newValue
|
||||
})
|
||||
}
|
||||
},
|
||||
enableDashboard: {
|
||||
get: function() {
|
||||
return this.$store.state.settings.enableDashboard
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$store.commit('settings/updateThemeSetting', {
|
||||
'enableDashboard': newValue
|
||||
})
|
||||
}
|
||||
}
|
||||
set: function(newValue) {
|
||||
store.commit('menu/switchHeaderActived', 0)
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'menuMode': newValue
|
||||
})
|
||||
store.state.settings.menuMode !== 'single' && store.commit('menu/setHeaderActived', route.fullPath)
|
||||
}
|
||||
})
|
||||
const elementSize = computed({
|
||||
get: function() {
|
||||
return store.state.settings.elementSize
|
||||
},
|
||||
mounted() {
|
||||
this.$eventBus.on('global-theme-toggle', () => {
|
||||
this.isShow = !this.isShow
|
||||
set: function(newValue) {
|
||||
proxy.$ELEMENT.size = newValue
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'elementSize': newValue
|
||||
})
|
||||
reload()
|
||||
}
|
||||
})
|
||||
const enableSidebarCollapse = computed({
|
||||
get: function() {
|
||||
return store.state.settings.enableSidebarCollapse
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'enableSidebarCollapse': newValue
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
const sidebarCollapse = computed({
|
||||
get: function() {
|
||||
return store.state.settings.sidebarCollapse
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'sidebarCollapse': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const switchSidebarAndPageJump = computed({
|
||||
get: function() {
|
||||
return store.state.settings.switchSidebarAndPageJump
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'switchSidebarAndPageJump': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const sidebarUniqueOpened = computed({
|
||||
get: function() {
|
||||
return store.state.settings.sidebarUniqueOpened
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'sidebarUniqueOpened': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const topbarFixed = computed({
|
||||
get: function() {
|
||||
return store.state.settings.topbarFixed
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'topbarFixed': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableBreadcrumb = computed({
|
||||
get: function() {
|
||||
return store.state.settings.enableBreadcrumb
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'enableBreadcrumb': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const showCopyright = computed({
|
||||
get: function() {
|
||||
return store.state.settings.showCopyright
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'showCopyright': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableNavSearch = computed({
|
||||
get: function() {
|
||||
return store.state.settings.enableNavSearch
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'enableNavSearch': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableFullscreen = computed({
|
||||
get: function() {
|
||||
return store.state.settings.enableFullscreen
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'enableFullscreen': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enablePageReload = computed({
|
||||
get: function() {
|
||||
return store.state.settings.enablePageReload
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'enablePageReload': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableProgress = computed({
|
||||
get: function() {
|
||||
return store.state.settings.enableProgress
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'enableProgress': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableDynamicTitle = computed({
|
||||
get: function() {
|
||||
return store.state.settings.enableDynamicTitle
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'enableDynamicTitle': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
const enableDashboard = computed({
|
||||
get: function() {
|
||||
return store.state.settings.enableDashboard
|
||||
},
|
||||
set: function(newValue) {
|
||||
store.commit('settings/updateThemeSetting', {
|
||||
'enableDashboard': newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
proxy.$eventBus.on('global-theme-toggle', () => {
|
||||
isShow.value = !isShow.value
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -25,57 +25,51 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { compile } from 'path-to-regexp'
|
||||
import { deepClone } from '@/util'
|
||||
import UserMenu from '../UserMenu/index.vue'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
export default {
|
||||
name: 'Topbar',
|
||||
components: {
|
||||
UserMenu
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
scrollTop: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
breadcrumbList() {
|
||||
let breadcrumbList = []
|
||||
if (this.$store.state.settings.enableDashboard) {
|
||||
breadcrumbList.push({
|
||||
path: '/dashboard',
|
||||
title: this.$store.state.settings.dashboardTitle
|
||||
})
|
||||
}
|
||||
if (this.$route.meta.breadcrumbNeste) {
|
||||
this.$route.meta.breadcrumbNeste.map((item, index) => {
|
||||
let tmpItem = deepClone(item)
|
||||
if (index != 0) {
|
||||
tmpItem.path = `${this.$route.meta.breadcrumbNeste[0].path}/${item.path}`
|
||||
}
|
||||
breadcrumbList.push(tmpItem)
|
||||
})
|
||||
}
|
||||
return breadcrumbList
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener('scroll', this.onScroll)
|
||||
},
|
||||
unmounted() {
|
||||
window.removeEventListener('scroll', this.onScroll)
|
||||
},
|
||||
methods: {
|
||||
pathCompile(path) {
|
||||
let toPath = compile(path)
|
||||
return toPath(this.$route.params)
|
||||
},
|
||||
onScroll() {
|
||||
this.scrollTop = document.documentElement.scrollTop || document.body.scrollTop
|
||||
}
|
||||
const store = useStore()
|
||||
const route = useRoute()
|
||||
|
||||
const breadcrumbList = computed(() => {
|
||||
let breadcrumbList = []
|
||||
if (store.state.settings.enableDashboard) {
|
||||
breadcrumbList.push({
|
||||
path: '/dashboard',
|
||||
title: store.state.settings.dashboardTitle
|
||||
})
|
||||
}
|
||||
if (route.meta.breadcrumbNeste) {
|
||||
route.meta.breadcrumbNeste.map((item, index) => {
|
||||
let tmpItem = deepClone(item)
|
||||
if (index != 0) {
|
||||
tmpItem.path = `${route.meta.breadcrumbNeste[0].path}/${item.path}`
|
||||
}
|
||||
breadcrumbList.push(tmpItem)
|
||||
})
|
||||
}
|
||||
return breadcrumbList
|
||||
})
|
||||
|
||||
const scrollTop = ref(0)
|
||||
onMounted(() => {
|
||||
window.addEventListener('scroll', onScroll)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('scroll', onScroll)
|
||||
})
|
||||
function onScroll() {
|
||||
scrollTop.value = document.documentElement.scrollTop || document.body.scrollTop
|
||||
}
|
||||
|
||||
function pathCompile(path) {
|
||||
let toPath = compile(path)
|
||||
return toPath(route.params)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -37,60 +37,59 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import screenfull from 'screenfull'
|
||||
import { computed, inject, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
export default {
|
||||
name: 'UserMenu',
|
||||
inject: ['reload'],
|
||||
data() {
|
||||
return {
|
||||
isFullscreenEnable: screenfull.isEnabled,
|
||||
isFullscreen: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.on('change', this.fullscreenChange)
|
||||
}
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.off('change', this.fullscreenChange)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fullscreen() {
|
||||
screenfull.toggle()
|
||||
},
|
||||
fullscreenChange() {
|
||||
this.isFullscreen = screenfull.isFullscreen
|
||||
},
|
||||
userCommand(command) {
|
||||
switch (command) {
|
||||
case 'dashboard':
|
||||
this.$router.push({
|
||||
name: 'dashboard'
|
||||
})
|
||||
break
|
||||
case 'setting':
|
||||
this.$router.push({
|
||||
name: 'personalSetting'
|
||||
})
|
||||
break
|
||||
case 'logout':
|
||||
this.$store.dispatch('user/logout').then(() => {
|
||||
this.$router.push({
|
||||
name: 'login'
|
||||
})
|
||||
})
|
||||
break
|
||||
}
|
||||
},
|
||||
pro() {
|
||||
window.open(`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/vue3/pro`, 'top')
|
||||
}
|
||||
const reload = inject('reload')
|
||||
const store = useStore()
|
||||
const router = useRouter()
|
||||
|
||||
const isFullscreenEnable = computed(() => screenfull.isEnabled)
|
||||
const isFullscreen = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
if (isFullscreenEnable.value) {
|
||||
screenfull.on('change', fullscreenChange)
|
||||
}
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
if (isFullscreenEnable.value) {
|
||||
screenfull.off('change', fullscreenChange)
|
||||
}
|
||||
})
|
||||
|
||||
function fullscreen() {
|
||||
screenfull.toggle()
|
||||
}
|
||||
function fullscreenChange() {
|
||||
isFullscreen.value = screenfull.isFullscreen
|
||||
}
|
||||
function userCommand(command) {
|
||||
switch (command) {
|
||||
case 'dashboard':
|
||||
router.push({
|
||||
name: 'dashboard'
|
||||
})
|
||||
break
|
||||
case 'setting':
|
||||
router.push({
|
||||
name: 'personalSetting'
|
||||
})
|
||||
break
|
||||
case 'logout':
|
||||
store.dispatch('user/logout').then(() => {
|
||||
router.push({
|
||||
name: 'login'
|
||||
})
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
function pro() {
|
||||
window.open(`https://hooray.${location.origin.includes('gitee') ? 'gitee' : 'github'}.io/fantastic-admin/vue3/pro`, 'top')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user