1.8 版本
This commit is contained in:
@@ -38,7 +38,8 @@
|
|||||||
"stompjs": "2.3.3",
|
"stompjs": "2.3.3",
|
||||||
"wangeditor": ">=3.0.0",
|
"wangeditor": ">=3.0.0",
|
||||||
"codemirror": "^5.38.0",
|
"codemirror": "^5.38.0",
|
||||||
"mavon-editor": "^2.7.0"
|
"mavon-editor": "^2.7.0",
|
||||||
|
"path-to-regexp": "2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "8.5.0",
|
"autoprefixer": "8.5.0",
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a href="https://github.com/elunez/eladmin" target="_blank" class="github-corner" aria-label="View source on Github">
|
|
||||||
<svg
|
|
||||||
width="80"
|
|
||||||
height="80"
|
|
||||||
viewBox="0 0 250 250"
|
|
||||||
style="fill:#40c9c6; color:#fff;"
|
|
||||||
aria-hidden="true">
|
|
||||||
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"/>
|
|
||||||
<path
|
|
||||||
d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
|
|
||||||
fill="currentColor"
|
|
||||||
style="transform-origin: 130px 106px;"
|
|
||||||
class="octo-arm"/>
|
|
||||||
<path
|
|
||||||
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
|
|
||||||
fill="currentColor"
|
|
||||||
class="octo-body"/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.github-corner:hover .octo-arm {
|
|
||||||
animation: octocat-wave 560ms ease-in-out
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes octocat-wave {
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
transform: rotate(0)
|
|
||||||
}
|
|
||||||
20%,
|
|
||||||
60% {
|
|
||||||
transform: rotate(-25deg)
|
|
||||||
}
|
|
||||||
40%,
|
|
||||||
80% {
|
|
||||||
transform: rotate(10deg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width:500px) {
|
|
||||||
.github-corner:hover .octo-arm {
|
|
||||||
animation: none
|
|
||||||
}
|
|
||||||
.github-corner .octo-arm {
|
|
||||||
animation: octocat-wave 560ms ease-in-out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -4,24 +4,14 @@
|
|||||||
:class="{'is-active':isActive}"
|
:class="{'is-active':isActive}"
|
||||||
t="1492500959545"
|
t="1492500959545"
|
||||||
class="hamburger"
|
class="hamburger"
|
||||||
style=""
|
|
||||||
viewBox="0 0 1024 1024"
|
viewBox="0 0 1024 1024"
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
version="1.1"
|
||||||
p-id="1691"
|
p-id="1691"
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
width="64"
|
width="64"
|
||||||
height="64"
|
height="64"
|
||||||
@click="toggleClick">
|
@click="toggleClick">
|
||||||
<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="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
|
|
||||||
p-id="1692" />
|
|
||||||
<path
|
|
||||||
d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z"
|
|
||||||
p-id="1693" />
|
|
||||||
<path
|
|
||||||
d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
|
|
||||||
p-id="1694" />
|
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -48,11 +38,10 @@ export default {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
transform: rotate(90deg);
|
|
||||||
transition: .38s;
|
transition: .38s;
|
||||||
transform-origin: 50% 50%;
|
transform-origin: 50% 50%;
|
||||||
}
|
}
|
||||||
.hamburger.is-active {
|
.hamburger.is-active {
|
||||||
transform: rotate(0deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
181
src/components/HeaderSearch/index.vue
Normal file
181
src/components/HeaderSearch/index.vue
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="{'show':show}" class="header-search">
|
||||||
|
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
|
||||||
|
<el-select
|
||||||
|
ref="headerSearchSelect"
|
||||||
|
v-model="search"
|
||||||
|
:remote-method="querySearch"
|
||||||
|
filterable
|
||||||
|
default-first-option
|
||||||
|
remote
|
||||||
|
placeholder="Search"
|
||||||
|
class="header-search-select"
|
||||||
|
@change="change"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// fuse is a lightweight fuzzy-search module
|
||||||
|
// make search results more in line with expectations
|
||||||
|
import Fuse from 'fuse.js'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HeaderSearch',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
search: '',
|
||||||
|
options: [],
|
||||||
|
searchPool: [],
|
||||||
|
show: false,
|
||||||
|
fuse: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
routes() {
|
||||||
|
return this.$store.getters.permission_routes
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
routes() {
|
||||||
|
this.searchPool = this.generateRoutes(this.routes)
|
||||||
|
},
|
||||||
|
searchPool(list) {
|
||||||
|
this.initFuse(list)
|
||||||
|
},
|
||||||
|
show(value) {
|
||||||
|
if (value) {
|
||||||
|
document.body.addEventListener('click', this.close)
|
||||||
|
} else {
|
||||||
|
document.body.removeEventListener('click', this.close)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.searchPool = this.generateRoutes(this.routes)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click() {
|
||||||
|
this.show = !this.show
|
||||||
|
if (this.show) {
|
||||||
|
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
|
||||||
|
this.options = []
|
||||||
|
this.show = false
|
||||||
|
},
|
||||||
|
change(val) {
|
||||||
|
this.$router.push(val.path)
|
||||||
|
this.search = ''
|
||||||
|
this.options = []
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.show = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
initFuse(list) {
|
||||||
|
this.fuse = new Fuse(list, {
|
||||||
|
shouldSort: true,
|
||||||
|
threshold: 0.4,
|
||||||
|
location: 0,
|
||||||
|
distance: 100,
|
||||||
|
maxPatternLength: 32,
|
||||||
|
minMatchCharLength: 1,
|
||||||
|
keys: [{
|
||||||
|
name: 'title',
|
||||||
|
weight: 0.7
|
||||||
|
}, {
|
||||||
|
name: 'path',
|
||||||
|
weight: 0.3
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// Filter out the routes that can be displayed in the sidebar
|
||||||
|
// And generate the internationalized title
|
||||||
|
generateRoutes(routes, basePath = '/', prefixTitle = []) {
|
||||||
|
let res = []
|
||||||
|
|
||||||
|
for (const router of routes) {
|
||||||
|
// skip hidden router
|
||||||
|
if (router.hidden) { continue }
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
path: path.resolve(basePath, router.path),
|
||||||
|
title: [...prefixTitle]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (router.meta && router.meta.title) {
|
||||||
|
// generate internationalized title
|
||||||
|
|
||||||
|
data.title = [...data.title, router.meta.title]
|
||||||
|
|
||||||
|
if (router.redirect !== 'noRedirect') {
|
||||||
|
// only push the routes with title
|
||||||
|
// special case: need to exclude parent router without redirect
|
||||||
|
res.push(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursive child routes
|
||||||
|
if (router.children) {
|
||||||
|
const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
|
||||||
|
if (tempRoutes.length >= 1) {
|
||||||
|
res = [...res, ...tempRoutes]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
querySearch(query) {
|
||||||
|
if (query !== '') {
|
||||||
|
this.options = this.fuse.search(query)
|
||||||
|
} else {
|
||||||
|
this.options = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.header-search {
|
||||||
|
font-size: 0 !important;
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-search-select {
|
||||||
|
font-size: 18px;
|
||||||
|
transition: width 0.2s;
|
||||||
|
width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
/deep/ .el-input__inner {
|
||||||
|
border-radius: 0;
|
||||||
|
border: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
box-shadow: none !important;
|
||||||
|
border-bottom: 1px solid #d9d9d9;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.show {
|
||||||
|
.header-search-select {
|
||||||
|
width: 210px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
157
src/components/RightPanel/index.vue
Normal file
157
src/components/RightPanel/index.vue
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
|
||||||
|
<div class="rightPanel-background" />
|
||||||
|
<div class="rightPanel">
|
||||||
|
<div :style="{'top':buttonTop+'px'}" @click="show=!show"/>
|
||||||
|
<div class="rightPanel-items">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { addClass, removeClass } from '@/utils'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'RightPanel',
|
||||||
|
props: {
|
||||||
|
clickNotClose: {
|
||||||
|
default: false,
|
||||||
|
type: Boolean
|
||||||
|
},
|
||||||
|
buttonTop: {
|
||||||
|
default: 250,
|
||||||
|
type: Number
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
theme: '#fff'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
show: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.settings.showRightPanel
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.dispatch('changeSetting', {
|
||||||
|
key: 'showRightPanel',
|
||||||
|
value: val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
show(value) {
|
||||||
|
if (value && !this.clickNotClose) {
|
||||||
|
this.addEventClick()
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
addClass(document.body, 'showRightPanel')
|
||||||
|
} else {
|
||||||
|
removeClass(document.body, 'showRightPanel')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.insertToBody()
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
const elx = this.$refs.rightPanel
|
||||||
|
elx.remove()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addEventClick() {
|
||||||
|
window.addEventListener('click', this.closeSidebar)
|
||||||
|
},
|
||||||
|
closeSidebar(evt) {
|
||||||
|
const parent = evt.target.closest('.rightPanel')
|
||||||
|
if (!parent) {
|
||||||
|
this.show = false
|
||||||
|
window.removeEventListener('click', this.closeSidebar)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
insertToBody() {
|
||||||
|
const elx = this.$refs.rightPanel
|
||||||
|
const body = document.querySelector('body')
|
||||||
|
body.insertBefore(elx, body.firstChild)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.showRightPanel {
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
width: calc(100% - 15px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.rightPanel-background {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
|
||||||
|
background: rgba(0, 0, 0, .2);
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
position: fixed;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rightPanel {
|
||||||
|
background: #fff;
|
||||||
|
position: fixed;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 260px;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
|
||||||
|
transition: all .25s cubic-bezier(.7, .3, .1, 1);
|
||||||
|
transform: translate(100%);
|
||||||
|
z-index: 40000;
|
||||||
|
left: auto;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show {
|
||||||
|
transition: all .3s cubic-bezier(.7, .3, .1, 1);
|
||||||
|
|
||||||
|
.rightPanel-background {
|
||||||
|
z-index: 20000;
|
||||||
|
opacity: 1;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rightPanel {
|
||||||
|
transform: translate(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.handle-button {
|
||||||
|
position: absolute;
|
||||||
|
left: -48px;
|
||||||
|
border-radius: 6px 0 0 6px !important;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
pointer-events: auto;
|
||||||
|
z-index: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
pointer-events: auto;
|
||||||
|
font-size: 24px;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 48px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 48px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -11,28 +11,27 @@
|
|||||||
width="32"
|
width="32"
|
||||||
height="32"
|
height="32"
|
||||||
@click="click"><path d="M921.9 468.6H749.6c-9.4 0-18.4 3.8-25 10.5-6.6 6.7-10.3 15.7-10.3 25.1v11.1c0 19.6 15.9 35.5 35.4 35.5h172.2c19.5 0 35.3-15.9 35.3-35.5v-11.1c0-9.4-3.7-18.4-10.3-25.1-6.6-6.7-15.6-10.5-25-10.5zM522.4 163.9c-53.6 42.6-165.7 102.3-246.3 159.8h-0.1c-0.9 0.6-1.8 3.8-2.8 4.3-9.5 5.4-13.8 20.1-65.6 20.1h-101c-26 0-42 12.2-42 39.6V631c0 27.4 14.7 40.9 42 40.9H208c51.5 0.1 55.7 14.8 65.2 20.1 0.9 0.5 1.8 3.7 2.7 4.3h0.1c78.2 57.5 191 121.8 246.4 162.7 16.7 12.3 72.1 33.9 72.1-42.1v-614c0-76.1-55.9-51.8-72.1-39z m159 167.8c9.2 16.1 27.3 20.2 40.5 9l141.5-119.3c13.3-11.1 16.5-33.2 7.4-49.4l-5.2-9.1c-9.1-16.1-27.3-20.1-40.5-9L683.6 273.2c-13.2 11.2-16.5 33.2-7.4 49.4l5.2 9.1z m40.4 347.4c-13.2-11.1-31.3-7-40.4 9l-5.2 9.1c-9.1 16.1-5.8 38.2 7.4 49.4L825.1 866c13.2 11.1 31.3 7.1 40.4-9l5.2-9.1c9.1-16.1 5.8-38.2-7.4-49.4L721.8 679.1z m0 0" p-id="1259"/></svg>
|
@click="click"><path d="M921.9 468.6H749.6c-9.4 0-18.4 3.8-25 10.5-6.6 6.7-10.3 15.7-10.3 25.1v11.1c0 19.6 15.9 35.5 35.4 35.5h172.2c19.5 0 35.3-15.9 35.3-35.5v-11.1c0-9.4-3.7-18.4-10.3-25.1-6.6-6.7-15.6-10.5-25-10.5zM522.4 163.9c-53.6 42.6-165.7 102.3-246.3 159.8h-0.1c-0.9 0.6-1.8 3.8-2.8 4.3-9.5 5.4-13.8 20.1-65.6 20.1h-101c-26 0-42 12.2-42 39.6V631c0 27.4 14.7 40.9 42 40.9H208c51.5 0.1 55.7 14.8 65.2 20.1 0.9 0.5 1.8 3.7 2.7 4.3h0.1c78.2 57.5 191 121.8 246.4 162.7 16.7 12.3 72.1 33.9 72.1-42.1v-614c0-76.1-55.9-51.8-72.1-39z m159 167.8c9.2 16.1 27.3 20.2 40.5 9l141.5-119.3c13.3-11.1 16.5-33.2 7.4-49.4l-5.2-9.1c-9.1-16.1-27.3-20.1-40.5-9L683.6 273.2c-13.2 11.2-16.5 33.2-7.4 49.4l5.2 9.1z m40.4 347.4c-13.2-11.1-31.3-7-40.4 9l-5.2 9.1c-9.1 16.1-5.8 38.2 7.4 49.4L825.1 866c13.2 11.1 31.3 7.1 40.4-9l5.2-9.1c9.1-16.1 5.8-38.2-7.4-49.4L721.8 679.1z m0 0" p-id="1259"/></svg>
|
||||||
<el-dialog :visible.sync="dialogTableVisible" width="60%" title="更新公告">
|
<el-dialog :append-to-body="true" :visible.sync="dialogTableVisible" width="60%" title="更新公告">
|
||||||
<blockquote class="my-blockquote">1.7版本更新说明</blockquote>
|
<blockquote class="my-blockquote">1.7版本更新说明</blockquote>
|
||||||
<div class="my-code">
|
<div class="my-code">
|
||||||
<div style="font-weight: bold">一、后端</div>
|
<div style="font-weight: bold">一、后端</div>
|
||||||
<ol>
|
<ol>
|
||||||
<li>完成部门管理,岗位管理,字典管理,完成数据权限</li>
|
<li>修复用户存在多角色时登录失败的bug</li>
|
||||||
<li>用户权限加入到缓存,避免重复请求数据库</li>
|
<li>修复在修改用户角色时缓存不刷新的bug</li>
|
||||||
<li>修复七牛云存储中文名下载失败的bug</li>
|
<li>修复修改邮箱配置需要重新启动才生效的bug</li>
|
||||||
<li>修复上级目录选择自己导致列表不显示的bug</li>
|
<li>修复上级目录选择自己导致列表不显示的bug</li>
|
||||||
<li>大量细节优化</li>
|
<li>新增部分工具类的单元测试</li>
|
||||||
<li>【文档】已更新至1.7版本,访问地址:<a target="_blank" href="https://docs.auauz.net" style="color: #317EF3">https://docs.auauz.net</a></li>
|
<li>common模块新增 SecurityUtils 工具类、可获取当前用户的 id和 username</li>
|
||||||
|
<li>配置文件新增 Swagger 的开启开关</li>
|
||||||
</ol>
|
</ol>
|
||||||
<div style="font-weight: bold">二、前端</div>
|
<div style="font-weight: bold">二、前端</div>
|
||||||
<ol>
|
<ol>
|
||||||
<li>优化实时控制台全屏后高宽自适应</li>
|
<li>新增系统设置,可设置logo、</li>
|
||||||
<li>七牛云列表显示添加【文件类型】字段</li>
|
<li>新增首屏加载动画</li>
|
||||||
<li>sm.ms图床列表添加【缩略图】显示</li>
|
<li>新增系统Logo显示</li>
|
||||||
<li>提供外链嵌入内部菜单的组件(可参考Sql监控或者接口文档菜单)</li>
|
<li>优化首页的 Tag 不可删除,由 affix 属性控制</li>
|
||||||
<li>重新设计个人中心页面</li>
|
<li>修复顶级部门不能修改的问题</li>
|
||||||
<li>取消无意义的前端MD5加密</li>
|
<li>其他细节优化</li>
|
||||||
<li>前端新增全局配置文件,文件位于src/config 下,目前可配置:网站名称、Cookie过期天数、TokenKey、请求超时时间</li>
|
|
||||||
<li>大量细节优化</li>
|
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|||||||
@@ -22,5 +22,20 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* @description 请求超时时间,毫秒(默认2分钟)
|
* @description 请求超时时间,毫秒(默认2分钟)
|
||||||
*/
|
*/
|
||||||
timeout: 1200000
|
timeout: 1200000,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 是否显示 tagsView
|
||||||
|
*/
|
||||||
|
tagsView: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 固定头部
|
||||||
|
*/
|
||||||
|
fixedHeader: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 是否显示logo
|
||||||
|
*/
|
||||||
|
sidebarLogo: true
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/icons/svg/search.svg
Normal file
1
src/icons/svg/search.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M124.884 109.812L94.256 79.166c-.357-.357-.757-.629-1.129-.914a50.366 50.366 0 0 0 8.186-27.59C101.327 22.689 78.656 0 50.67 0 22.685 0 0 22.688 0 50.663c0 27.989 22.685 50.663 50.656 50.663 10.186 0 19.643-3.03 27.6-8.201.286.385.557.771.9 1.114l30.628 30.632a10.633 10.633 0 0 0 7.543 3.129c2.728 0 5.457-1.043 7.543-3.115 4.171-4.157 4.171-10.915.014-15.073M50.671 85.338C31.557 85.338 16 69.78 16 50.663c0-19.102 15.557-34.661 34.67-34.661 19.115 0 34.657 15.559 34.657 34.675 0 19.102-15.557 34.661-34.656 34.661"/></svg>
|
||||||
|
After Width: | Height: | Size: 600 B |
@@ -55,7 +55,7 @@ export const constantRouterMap = [
|
|||||||
path: 'dashboard',
|
path: 'dashboard',
|
||||||
component: () => import('@/views/dashboard/index'),
|
component: () => import('@/views/dashboard/index'),
|
||||||
name: '首页',
|
name: '首页',
|
||||||
meta: { title: '首页', icon: 'index', noCache: true }
|
meta: { title: '首页', icon: 'index', noCache: true, affix: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import api from './modules/api'
|
|||||||
import user from './modules/user'
|
import user from './modules/user'
|
||||||
import tagsView from './modules/tagsView'
|
import tagsView from './modules/tagsView'
|
||||||
import permission from './modules/permission'
|
import permission from './modules/permission'
|
||||||
|
import settings from './modules/settings'
|
||||||
import getters from './getters'
|
import getters from './getters'
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
@@ -15,7 +16,8 @@ const store = new Vuex.Store({
|
|||||||
api,
|
api,
|
||||||
user,
|
user,
|
||||||
tagsView,
|
tagsView,
|
||||||
permission
|
permission,
|
||||||
|
settings
|
||||||
},
|
},
|
||||||
getters
|
getters
|
||||||
})
|
})
|
||||||
|
|||||||
23
src/store/modules/settings.js
Normal file
23
src/store/modules/settings.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import Config from '@/config'
|
||||||
|
|
||||||
|
const settings = {
|
||||||
|
state: {
|
||||||
|
showRightPanel: false,
|
||||||
|
tagsView: Config.tagsView,
|
||||||
|
fixedHeader: Config.fixedHeader,
|
||||||
|
sidebarLogo: Config.sidebarLogo
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
CHANGE_SETTING: (state, { key, value }) => {
|
||||||
|
if (state.hasOwnProperty(key)) {
|
||||||
|
state[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
changeSetting({ commit }, data) {
|
||||||
|
commit('CHANGE_SETTING', data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default settings
|
||||||
@@ -56,7 +56,8 @@ const tagsView = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
DEL_ALL_VISITED_VIEWS: state => {
|
DEL_ALL_VISITED_VIEWS: state => {
|
||||||
state.visitedViews = []
|
const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
|
||||||
|
state.visitedViews = affixTags
|
||||||
},
|
},
|
||||||
DEL_ALL_CACHED_VIEWS: state => {
|
DEL_ALL_CACHED_VIEWS: state => {
|
||||||
state.cachedViews = []
|
state.cachedViews = []
|
||||||
@@ -129,7 +130,6 @@ const tagsView = {
|
|||||||
resolve([...state.cachedViews])
|
resolve([...state.cachedViews])
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
delAllViews({ dispatch, state }, view) {
|
delAllViews({ dispatch, state }, view) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
dispatch('delAllVisitedViews', view)
|
dispatch('delAllVisitedViews', view)
|
||||||
|
|||||||
@@ -1,4 +1,27 @@
|
|||||||
//sidebar
|
//sidebar
|
||||||
|
$menuText:#bfcbd9;
|
||||||
|
$menuActiveText:#409EFF;
|
||||||
|
$subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951
|
||||||
|
|
||||||
$menuBg:#304156;
|
$menuBg:#304156;
|
||||||
|
$menuHover:#263445;
|
||||||
|
|
||||||
$subMenuBg:#1f2d3d;
|
$subMenuBg:#1f2d3d;
|
||||||
$menuHover:#001528;
|
$subMenuHover:#001528;
|
||||||
|
|
||||||
|
$sideBarWidth: 180px;
|
||||||
|
|
||||||
|
$hideSidebarWidth: 38px;
|
||||||
|
|
||||||
|
// the :export directive is the magic sauce for webpack
|
||||||
|
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
|
||||||
|
:export {
|
||||||
|
menuText: $menuText;
|
||||||
|
menuActiveText: $menuActiveText;
|
||||||
|
subMenuActiveText: $subMenuActiveText;
|
||||||
|
menuBg: $menuBg;
|
||||||
|
menuHover: $menuHover;
|
||||||
|
subMenuBg: $subMenuBg;
|
||||||
|
subMenuHover: $subMenuHover;
|
||||||
|
sideBarWidth: $sideBarWidth;
|
||||||
|
}
|
||||||
|
|||||||
@@ -116,3 +116,34 @@ export function regMobile(mobile) {
|
|||||||
}
|
}
|
||||||
return new_mobile
|
return new_mobile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an element has a class
|
||||||
|
* @param {HTMLElement} elm
|
||||||
|
* @param {string} cls
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function hasClass(ele, cls) {
|
||||||
|
return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add class to element
|
||||||
|
* @param {HTMLElement} elm
|
||||||
|
* @param {string} cls
|
||||||
|
*/
|
||||||
|
export function addClass(ele, cls) {
|
||||||
|
if (!hasClass(ele, cls)) ele.className += ' ' + cls
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove class from element
|
||||||
|
* @param {HTMLElement} elm
|
||||||
|
* @param {string} cls
|
||||||
|
*/
|
||||||
|
export function removeClass(ele, cls) {
|
||||||
|
if (hasClass(ele, cls)) {
|
||||||
|
const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
|
||||||
|
ele.className = ele.className.replace(reg, ' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="dashboard-editor-container">
|
<div class="dashboard-editor-container">
|
||||||
|
|
||||||
<github-corner style="position: absolute; top: 0px; border: 0; right: 0;"/>
|
|
||||||
|
|
||||||
<panel-group/>
|
<panel-group/>
|
||||||
|
|
||||||
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
|
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
|
||||||
@@ -30,7 +27,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import GithubCorner from '@/components/GithubCorner'
|
|
||||||
import PanelGroup from './components/PanelGroup'
|
import PanelGroup from './components/PanelGroup'
|
||||||
import LineChart from './components/LineChart'
|
import LineChart from './components/LineChart'
|
||||||
import RaddarChart from './components/RaddarChart'
|
import RaddarChart from './components/RaddarChart'
|
||||||
@@ -39,7 +35,6 @@ import BarChart from './components/BarChart'
|
|||||||
export default {
|
export default {
|
||||||
name: 'DashboardAdmin',
|
name: 'DashboardAdmin',
|
||||||
components: {
|
components: {
|
||||||
GithubCorner,
|
|
||||||
PanelGroup,
|
PanelGroup,
|
||||||
LineChart,
|
LineChart,
|
||||||
RaddarChart,
|
RaddarChart,
|
||||||
@@ -51,7 +46,7 @@ export default {
|
|||||||
|
|
||||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
.dashboard-editor-container {
|
.dashboard-editor-container {
|
||||||
padding: 32px;
|
padding: 18px 22px 22px 22px;
|
||||||
background-color: rgb(240, 242, 245);
|
background-color: rgb(240, 242, 245);
|
||||||
.chart-wrapper {
|
.chart-wrapper {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
|||||||
@@ -1,34 +1,44 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="classObj" class="app-wrapper">
|
<div :class="classObj" class="app-wrapper">
|
||||||
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
|
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
||||||
<sidebar class="sidebar-container"/>
|
<sidebar class="sidebar-container" />
|
||||||
<div class="main-container">
|
<div :class="{hasTagsView:needTagsView}" class="main-container">
|
||||||
<navbar/>
|
<div :class="{'fixed-header':fixedHeader}">
|
||||||
<tags-view/>
|
<navbar />
|
||||||
<app-main/>
|
<tags-view v-if="needTagsView" />
|
||||||
|
</div>
|
||||||
|
<app-main />
|
||||||
|
<right-panel>
|
||||||
|
<settings />
|
||||||
|
</right-panel>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Navbar, Sidebar, AppMain, TagsView } from './components'
|
import RightPanel from '@/components/RightPanel'
|
||||||
|
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
|
||||||
import ResizeMixin from './mixin/ResizeHandler'
|
import ResizeMixin from './mixin/ResizeHandler'
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Layout',
|
name: 'Layout',
|
||||||
components: {
|
components: {
|
||||||
Navbar,
|
|
||||||
Sidebar,
|
|
||||||
AppMain,
|
AppMain,
|
||||||
TagsView
|
Navbar,
|
||||||
|
Settings,
|
||||||
|
Sidebar,
|
||||||
|
TagsView,
|
||||||
|
RightPanel
|
||||||
},
|
},
|
||||||
mixins: [ResizeMixin],
|
mixins: [ResizeMixin],
|
||||||
computed: {
|
computed: {
|
||||||
sidebar() {
|
...mapState({
|
||||||
return this.$store.state.app.sidebar
|
sidebar: state => state.app.sidebar,
|
||||||
},
|
device: state => state.app.device,
|
||||||
device() {
|
needTagsView: state => state.settings.tagsView,
|
||||||
return this.$store.state.app.device
|
fixedHeader: state => state.settings.fixedHeader
|
||||||
},
|
}),
|
||||||
classObj() {
|
classObj() {
|
||||||
return {
|
return {
|
||||||
hideSidebar: !this.sidebar.opened,
|
hideSidebar: !this.sidebar.opened,
|
||||||
@@ -40,24 +50,28 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleClickOutside() {
|
handleClickOutside() {
|
||||||
this.$store.dispatch('closeSideBar', { withoutAnimation: false })
|
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "~@/styles/mixin.scss";
|
@import "~@/styles/mixin.scss";
|
||||||
|
@import "~@/styles/variables.scss";
|
||||||
|
|
||||||
.app-wrapper {
|
.app-wrapper {
|
||||||
@include clearfix;
|
@include clearfix;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
&.mobile.openSidebar{
|
|
||||||
|
&.mobile.openSidebar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.drawer-bg {
|
.drawer-bg {
|
||||||
background: #000;
|
background: #000;
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
@@ -67,4 +81,22 @@ export default {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fixed-header {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
background: #ffffff;
|
||||||
|
z-index: 99;
|
||||||
|
width: calc(100% - #{$sideBarWidth});
|
||||||
|
transition: width 0.28s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hideSidebar .fixed-header {
|
||||||
|
width: calc(100% - #{$hideSidebarWidth})
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile .fixed-header {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss" scoped>
|
||||||
.app-main {
|
.app-main {
|
||||||
z-index: 88;
|
z-index: 88;
|
||||||
/*84 = navbar + tags-view = 50 +34 */
|
/*84 = navbar + tags-view = 50 +34 */
|
||||||
@@ -31,5 +31,19 @@ export default {
|
|||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fixed-header+.app-main {
|
||||||
|
padding-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hasTagsView {
|
||||||
|
.app-main {
|
||||||
|
min-height: calc(100vh - 84px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fixed-header+.app-main {
|
||||||
|
padding-top: 84px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -4,28 +4,30 @@
|
|||||||
<breadcrumb class="breadcrumb-container"/>
|
<breadcrumb class="breadcrumb-container"/>
|
||||||
|
|
||||||
<div class="right-menu">
|
<div class="right-menu">
|
||||||
<template>
|
<template v-if="device!=='mobile'">
|
||||||
<el-tooltip content="更新公告" effect="dark" placement="bottom">
|
<el-tooltip content="更新公告" effect="dark" placement="bottom">
|
||||||
<Placard class="screenfull right-menu-item"/>
|
<Placard class="screenfull right-menu-item"/>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
|
||||||
<template v-if="device!=='mobile'">
|
|
||||||
<el-tooltip content="全屏" effect="dark" placement="bottom">
|
<el-tooltip content="全屏" effect="dark" placement="bottom">
|
||||||
<screenfull class="screenfull right-menu-item"/>
|
<screenfull class="screenfull right-menu-item"/>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-dropdown class="avatar-container right-menu-item" trigger="click">
|
<el-dropdown class="avatar-container right-menu-item" trigger="click">
|
||||||
<div class="avatar-wrapper">
|
<div class="avatar-wrapper">
|
||||||
<img :src="user.avatar" class="user-avatar">
|
<img :src="user.avatar" class="user-avatar">
|
||||||
<i class="el-icon-caret-bottom"/>
|
<i class="el-icon-caret-bottom"/>
|
||||||
</div>
|
</div>
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
<router-link to="/">
|
<a target="_blank" href="https://docs.auauz.net/">
|
||||||
<el-dropdown-item>
|
<el-dropdown-item>
|
||||||
首页
|
项目文档
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</router-link>
|
</a>
|
||||||
|
<span style="display:block;" @click="show = true">
|
||||||
|
<el-dropdown-item>
|
||||||
|
布局设置
|
||||||
|
</el-dropdown-item>
|
||||||
|
</span>
|
||||||
<router-link to="/user/center">
|
<router-link to="/user/center">
|
||||||
<el-dropdown-item>
|
<el-dropdown-item>
|
||||||
个人中心
|
个人中心
|
||||||
@@ -59,7 +61,18 @@ export default {
|
|||||||
'sidebar',
|
'sidebar',
|
||||||
'user',
|
'user',
|
||||||
'device'
|
'device'
|
||||||
])
|
]),
|
||||||
|
show: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.settings.showRightPanel
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.dispatch('changeSetting', {
|
||||||
|
key: 'showRightPanel',
|
||||||
|
value: val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleSideBar() {
|
toggleSideBar() {
|
||||||
|
|||||||
91
src/views/layout/components/Settings/index.vue
Normal file
91
src/views/layout/components/Settings/index.vue
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<div class="drawer-container">
|
||||||
|
<div>
|
||||||
|
<h3 class="drawer-title">系统布局配置</h3>
|
||||||
|
<div class="drawer-item">
|
||||||
|
<span>开启 Tags-Views</span>
|
||||||
|
<el-switch v-model="tagsView" class="drawer-switch" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-item">
|
||||||
|
<span>固定 Header</span>
|
||||||
|
<el-switch v-model="fixedHeader" class="drawer-switch" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-item">
|
||||||
|
<span>显示 Logo</span>
|
||||||
|
<el-switch v-model="sidebarLogo" class="drawer-switch" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
fixedHeader: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.settings.fixedHeader
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.dispatch('changeSetting', {
|
||||||
|
key: 'fixedHeader',
|
||||||
|
value: val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tagsView: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.settings.tagsView
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.dispatch('changeSetting', {
|
||||||
|
key: 'tagsView',
|
||||||
|
value: val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sidebarLogo: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.settings.sidebarLogo
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.dispatch('changeSetting', {
|
||||||
|
key: 'sidebarLogo',
|
||||||
|
value: val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.drawer-container {
|
||||||
|
padding: 24px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.5;
|
||||||
|
word-wrap: break-word;
|
||||||
|
|
||||||
|
.drawer-title {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: rgba(0, 0, 0, .85);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-item {
|
||||||
|
color: rgba(0, 0, 0, .65);
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-switch {
|
||||||
|
float: right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
39
src/views/layout/components/Sidebar/Logo.vue
Normal file
39
src/views/layout/components/Sidebar/Logo.vue
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<template>
|
||||||
|
<el-menu-item v-if="sidebarLogo" :class="{'submenu-title-noDropdown':isCollapse}" index="0" style="pointer-events: none;">
|
||||||
|
<!-- 缩小时显示的logo,可以自定义,这里直接使用图标库中的 -->
|
||||||
|
<svg-icon v-if="isCollapse" icon-class="run" />
|
||||||
|
<!--正常状态下显示的,可以使用本地的logoImg-->
|
||||||
|
<div class="logo-con">
|
||||||
|
<img src="https://aurora-1255840532.cos.ap-chengdu.myqcloud.com/logo.png">
|
||||||
|
<!--<img :src="logoImg">-->
|
||||||
|
</div>
|
||||||
|
</el-menu-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// import logoImg from '@/assets/logo/logo.png'
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
export default {
|
||||||
|
name: 'Logo',
|
||||||
|
props: {
|
||||||
|
isCollapse: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// logoImg: logoImg
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
sidebarLogo: state => state.settings.sidebarLogo
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -9,15 +9,7 @@
|
|||||||
text-color="#bfcbd9"
|
text-color="#bfcbd9"
|
||||||
active-text-color="#409EFF"
|
active-text-color="#409EFF"
|
||||||
>
|
>
|
||||||
<!-- 修改logo -->
|
<Logo :is-collapse="isCollapse"/>
|
||||||
<el-menu-item :class="{'submenu-title-noDropdown':isCollapse}" index="0" style="pointer-events: none;">
|
|
||||||
<!-- 缩小时显示的logo,可以自定义,这里直接使用图标库中的 -->
|
|
||||||
<svg-icon v-if="isCollapse" icon-class="run" />
|
|
||||||
<!--正常状态下显示的,可以使用本地的logoImg-->
|
|
||||||
<div class="logo-con">
|
|
||||||
<img src="https://aurora-1255840532.cos.ap-chengdu.myqcloud.com/logo.png">
|
|
||||||
</div>
|
|
||||||
</el-menu-item>
|
|
||||||
<sidebar-item v-for="route in permission_routers" :key="route.path" :item="route" :base-path="route.path"/>
|
<sidebar-item v-for="route in permission_routers" :key="route.path" :item="route" :base-path="route.path"/>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
@@ -26,14 +18,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import SidebarItem from './SidebarItem'
|
import SidebarItem from './SidebarItem'
|
||||||
// import logoImg from '@/assets/logo/logo.png'
|
import Logo from './Logo'
|
||||||
export default {
|
export default {
|
||||||
components: { SidebarItem },
|
components: { SidebarItem, Logo },
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
// logoImg: logoImg
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters([
|
...mapGetters([
|
||||||
'permission_routers',
|
'permission_routers',
|
||||||
|
|||||||
@@ -12,21 +12,22 @@
|
|||||||
@click.middle.native="closeSelectedTag(tag)"
|
@click.middle.native="closeSelectedTag(tag)"
|
||||||
@contextmenu.prevent.native="openMenu(tag,$event)">
|
@contextmenu.prevent.native="openMenu(tag,$event)">
|
||||||
{{ tag.title }}
|
{{ tag.title }}
|
||||||
<span class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
|
<span v-if="!tag.meta.affix" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
|
||||||
</router-link>
|
</router-link>
|
||||||
</scroll-pane>
|
</scroll-pane>
|
||||||
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
|
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
|
||||||
<li @click="refreshSelectedTag(selectedTag)">刷新</li>
|
<li @click="refreshSelectedTag(selectedTag)">刷新</li>
|
||||||
<li @click="closeSelectedTag(selectedTag)">关闭</li>
|
<li v-if="!(selectedTag.meta&&selectedTag.meta.affix)" @click="closeSelectedTag(selectedTag)">关闭</li>
|
||||||
<li @click="closeOthersTags">关闭其他</li>
|
<li @click="closeOthersTags">关闭其他</li>
|
||||||
<li @click="closeAllTags">关闭所有</li>
|
<li @click="closeAllTags(selectedTag)">关闭所有</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ScrollPane from '@/components/ScrollPane'
|
import ScrollPane from '@/components/ScrollPane'
|
||||||
|
import path from 'path'
|
||||||
|
import { constantRouterMap } from '@/router'
|
||||||
export default {
|
export default {
|
||||||
components: { ScrollPane },
|
components: { ScrollPane },
|
||||||
data() {
|
data() {
|
||||||
@@ -34,6 +35,7 @@ export default {
|
|||||||
visible: false,
|
visible: false,
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
|
affixTags: [],
|
||||||
selectedTag: {}
|
selectedTag: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -56,12 +58,43 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.initTags()
|
||||||
this.addViewTags()
|
this.addViewTags()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isActive(route) {
|
isActive(route) {
|
||||||
return route.path === this.$route.path
|
return route.path === this.$route.path
|
||||||
},
|
},
|
||||||
|
filterAffixTags(routes, basePath = '/') {
|
||||||
|
let tags = []
|
||||||
|
routes.forEach(route => {
|
||||||
|
if (route.meta && route.meta.affix) {
|
||||||
|
const tagPath = path.resolve(basePath, route.path)
|
||||||
|
tags.push({
|
||||||
|
fullPath: tagPath,
|
||||||
|
path: tagPath,
|
||||||
|
name: route.name,
|
||||||
|
meta: { ...route.meta }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (route.children) {
|
||||||
|
const tempTags = this.filterAffixTags(route.children, route.path)
|
||||||
|
if (tempTags.length >= 1) {
|
||||||
|
tags = [...tags, ...tempTags]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return tags
|
||||||
|
},
|
||||||
|
initTags() {
|
||||||
|
const affixTags = this.affixTags = this.filterAffixTags(constantRouterMap)
|
||||||
|
for (const tag of affixTags) {
|
||||||
|
// Must have tag name
|
||||||
|
if (tag.name) {
|
||||||
|
this.$store.dispatch('addVisitedView', tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
addViewTags() {
|
addViewTags() {
|
||||||
const { name } = this.$route
|
const { name } = this.$route
|
||||||
if (name) {
|
if (name) {
|
||||||
@@ -114,9 +147,28 @@ export default {
|
|||||||
this.moveToCurrentTag()
|
this.moveToCurrentTag()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
closeAllTags() {
|
closeAllTags(view) {
|
||||||
this.$store.dispatch('delAllViews')
|
this.$store.dispatch('delAllViews').then(({ visitedViews }) => {
|
||||||
this.$router.push('/')
|
if (this.affixTags.some(tag => tag.path === view.path)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.toLastView(visitedViews, view)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
toLastView(visitedViews, view) {
|
||||||
|
const latestView = visitedViews.slice(-1)[0]
|
||||||
|
if (latestView) {
|
||||||
|
this.$router.push(latestView)
|
||||||
|
} else {
|
||||||
|
// now the default is to redirect to the home page if there is no tags-view,
|
||||||
|
// you can adjust it according to your needs.
|
||||||
|
if (view.name === '首页') {
|
||||||
|
// to reload home page
|
||||||
|
this.$router.replace({ path: '/redirect' + view.fullPath })
|
||||||
|
} else {
|
||||||
|
this.$router.push('/')
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
openMenu(tag, e) {
|
openMenu(tag, e) {
|
||||||
const menuMinWidth = 105
|
const menuMinWidth = 105
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ export { default as Navbar } from './Navbar'
|
|||||||
export { default as Sidebar } from './Sidebar'
|
export { default as Sidebar } from './Sidebar'
|
||||||
export { default as AppMain } from './AppMain'
|
export { default as AppMain } from './AppMain'
|
||||||
export { default as TagsView } from './TagsView'
|
export { default as TagsView } from './TagsView'
|
||||||
|
export { default as Settings } from './Settings'
|
||||||
|
|||||||
Reference in New Issue
Block a user