Merge pull request #2 from PanJiaChen/master

同步更新
This commit is contained in:
MaYuanhai 2019-02-18 12:59:50 +08:00 committed by GitHub
commit 6c8fda9244
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 369 additions and 179 deletions

View File

@ -37,19 +37,19 @@
"axios": "0.18.0", "axios": "0.18.0",
"clipboard": "1.7.1", "clipboard": "1.7.1",
"codemirror": "5.39.2", "codemirror": "5.39.2",
"connect": "3.6.6",
"driver.js": "0.8.1", "driver.js": "0.8.1",
"dropzone": "5.2.0", "dropzone": "5.2.0",
"echarts": "4.1.0", "echarts": "4.1.0",
"element-ui": "2.4.11", "element-ui": "2.4.11",
"file-saver": "1.3.8", "file-saver": "1.3.8",
"fuse.js": "3.4.2",
"js-cookie": "2.2.0", "js-cookie": "2.2.0",
"jsonlint": "1.6.3", "jsonlint": "1.6.3",
"jszip": "3.1.5", "jszip": "3.1.5",
"mockjs": "1.0.1-beta3", "mockjs": "1.0.1-beta3",
"normalize.css": "7.0.0", "normalize.css": "7.0.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"screenfull": "3.3.3", "screenfull": "4.0.0",
"showdown": "1.8.6", "showdown": "1.8.6",
"sortablejs": "1.7.0", "sortablejs": "1.7.0",
"tui-editor": "1.2.7", "tui-editor": "1.2.7",
@ -76,6 +76,7 @@
"babel-preset-stage-2": "6.24.1", "babel-preset-stage-2": "6.24.1",
"chalk": "2.4.1", "chalk": "2.4.1",
"compression-webpack-plugin": "2.0.0", "compression-webpack-plugin": "2.0.0",
"connect": "3.6.6",
"copy-webpack-plugin": "4.5.2", "copy-webpack-plugin": "4.5.2",
"cross-env": "5.2.0", "cross-env": "5.2.0",
"css-loader": "1.0.0", "css-loader": "1.0.0",

View File

@ -63,7 +63,7 @@ export default {
display: inline-block; display: inline-block;
font-size: 14px; font-size: 14px;
line-height: 50px; line-height: 50px;
margin-left: 10px; margin-left: 8px;
.no-redirect { .no-redirect {
color: #97a8be; color: #97a8be;
cursor: text; cursor: text;

View File

@ -1,21 +1,8 @@
<template> <template>
<div v-if="errorLogs.length>0"> <div v-if="errorLogs.length>0">
<el-badge :is-dot="true" style="line-height: 30px;" @click.native="dialogTableVisible=true"> <el-badge :is-dot="true" style="line-height: 25px;margin-top: -5px;" @click.native="dialogTableVisible=true">
<el-button size="small" type="danger" class="bug-btn"> <el-button style="padding: 8px 10px;" size="small" type="danger">
<svg <svg-icon icon-class="bug" />
t="1492682037685"
class="bug-svg"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1863"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="128"
height="128">
<path
d="M969.142857 548.571429q0 14.848-10.861714 25.709714t-25.709714 10.861714l-128 0q0 97.718857-38.290286 165.705143l118.857143 119.442286q10.861714 10.861714 10.861714 25.709714t-10.861714 25.709714q-10.276571 10.861714-25.709714 10.861714t-25.709714-10.861714l-113.152-112.566857q-2.852571 2.852571-8.557714 7.424t-23.990857 16.274286-37.156571 20.845714-46.848 16.566857-55.442286 7.424l0-512-73.142857 0 0 512q-29.147429 0-58.002286-7.716571t-49.700571-18.870857-37.705143-22.272-24.868571-18.578286l-8.557714-8.009143-104.557714 118.272q-11.446857 11.995429-27.428571 11.995429-13.714286 0-24.576-9.142857-10.861714-10.276571-11.702857-25.417143t8.850286-26.587429l115.419429-129.718857q-33.133714-65.133714-33.133714-156.562286l-128 0q-14.848 0-25.709714-10.861714t-10.861714-25.709714 10.861714-25.709714 25.709714-10.861714l128 0 0-168.009143-98.852571-98.852571q-10.861714-10.861714-10.861714-25.709714t10.861714-25.709714 25.709714-10.861714 25.709714 10.861714l98.852571 98.852571 482.304 0 98.852571-98.852571q10.861714-10.861714 25.709714-10.861714t25.709714 10.861714 10.861714 25.709714-10.861714 25.709714l-98.852571 98.852571 0 168.009143 128 0q14.848 0 25.709714 10.861714t10.861714 25.709714zM694.857143 219.428571l-365.714286 0q0-75.995429 53.430857-129.426286t129.426286-53.430857 129.426286 53.430857 53.430857 129.426286z"
p-id="1864"/>
</svg>
</el-button> </el-button>
</el-badge> </el-badge>
@ -67,16 +54,6 @@ export default {
</script> </script>
<style scoped> <style scoped>
.bug-btn.el-button--small {
padding: 9px 10px;
}
.bug-svg {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.message-title { .message-title {
font-size: 16px; font-size: 16px;
color: #333; color: #333;

View File

@ -1,5 +1,5 @@
<template> <template>
<div> <div style="padding: 0 15px;" @click="toggleClick">
<svg <svg
:class="{'is-active':isActive}" :class="{'is-active':isActive}"
class="hamburger" class="hamburger"
@ -7,7 +7,7 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="64" width="64"
height="64" height="64"
@click="toggleClick"> >
<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" /> <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" />
</svg> </svg>
</div> </div>
@ -32,10 +32,11 @@ export default {
<style scoped> <style scoped>
.hamburger { .hamburger {
display: inline-block; display: inline-block;
cursor: pointer; vertical-align: middle;
width: 20px; width: 20px;
height: 20px; height: 20px;
} }
.hamburger.is-active { .hamburger.is-active {
transform: rotate(180deg); transform: rotate(180deg);
} }

View File

@ -0,0 +1,187 @@
<template>
<div :class="{'show':show}" class="header-search">
<svg-icon class-name="search-icon" icon-class="search" @click="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>
import Fuse from 'fuse.js'
import path from 'path'
import i18n from '@/lang'
export default {
name: 'HeaderSearch',
data() {
return {
search: '',
options: [],
searchPool: [],
show: false,
fuse: undefined
}
},
computed: {
routers() {
return this.$store.getters.permission_routers
},
lang() {
return this.$store.getters.language
}
},
watch: {
lang() {
this.searchPool = this.generateRouters(this.routers)
},
routers() {
this.searchPool = this.generateRouters(this.routers)
},
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.generateRouters(this.routers)
},
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
generateRouters(routers, basePath = '/', prefixTitle = []) {
let res = []
for (const router of routers) {
// 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
const i18ntitle = i18n.t(`route.${router.meta.title}`)
data.title = [...data.title, i18ntitle]
if (router.redirect !== 'noredirect') {
// only push the routes with title
// special case: need to exclude parent router without redirect
res.push(data)
}
}
// recursive child routers
if (router.children) {
const tempRouters = this.generateRouters(router.children, data.path, data.title)
if (tempRouters.length >= 1) {
res = [...res, ...tempRouters]
}
}
}
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;
vertical-align: middle;
}
.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>

View File

@ -41,7 +41,7 @@ export default {
} }
} }
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.board-column { .board-column {
min-width: 300px; min-width: 300px;
min-height: 100px; min-height: 100px;
@ -81,7 +81,7 @@ export default {
line-height: 54px; line-height: 54px;
padding: 5px 10px; padding: 5px 10px;
box-sizing: border-box; box-sizing: border-box;
box-shadow: 0px 1px 3px 0 rgba(0,0,0,0.2); box-shadow: 0px 1px 3px 0 rgba(0, 0, 0, 0.2);
} }
} }
} }

View File

@ -30,12 +30,3 @@ export default {
} }
} }
</script> </script>
<style scoped>
.international-icon {
font-size: 20px;
cursor: pointer;
vertical-align: -5px!important;
}
</style>

View File

@ -1,29 +1,6 @@
<template> <template>
<div> <div>
<svg <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
t="1508738709248"
class="screenfull-svg"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2069"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="32"
height="32"
@click="click">
<path
d="M333.493443 428.647617 428.322206 333.832158 262.572184 168.045297 366.707916 64.444754 64.09683 64.444754 63.853283 366.570793 167.283957 262.460644Z"
p-id="2070"/>
<path
d="M854.845439 760.133334 688.61037 593.95864 593.805144 688.764889 759.554142 854.56096 655.44604 958.161503 958.055079 958.161503 958.274066 656.035464Z"
p-id="2071"/>
<path
d="M688.535669 428.550403 854.31025 262.801405 957.935352 366.921787 957.935352 64.34754 655.809313 64.081481 759.919463 167.535691 593.70793 333.731874Z"
p-id="2072"/>
<path
d="M333.590658 594.033341 167.8171 759.804852 64.218604 655.67219 64.218604 958.270996 366.342596 958.502263 262.234493 855.071589 428.421466 688.86108Z"
p-id="2073"/>
</svg>
</div> </div>
</template> </template>
@ -32,25 +9,14 @@ import screenfull from 'screenfull'
export default { export default {
name: 'Screenfull', name: 'Screenfull',
props: {
width: {
type: Number,
default: 22
},
height: {
type: Number,
default: 22
},
fill: {
type: String,
default: '#48576a'
}
},
data() { data() {
return { return {
isFullscreen: false isFullscreen: false
} }
}, },
mounted() {
this.init()
},
methods: { methods: {
click() { click() {
if (!screenfull.enabled) { if (!screenfull.enabled) {
@ -61,6 +27,13 @@ export default {
return false return false
} }
screenfull.toggle() screenfull.toggle()
},
init() {
if (screenfull.enabled) {
screenfull.on('change', () => {
this.isFullscreen = screenfull.isFullscreen
})
}
} }
} }
} }

View File

@ -53,12 +53,3 @@ export default {
} }
</script> </script>
<style scoped>
.size-icon {
font-size: 20px;
cursor: pointer;
vertical-align: -4px!important;
}
</style>

View File

@ -1,5 +1,5 @@
<template> <template>
<svg :class="svgClass" aria-hidden="true"> <svg :class="svgClass" aria-hidden="true" v-on="$listeners">
<use :xlink:href="iconName"/> <use :xlink:href="iconName"/>
</svg> </svg>
</template> </template>

View File

@ -136,7 +136,10 @@ export default {
<style> <style>
.theme-picker .el-color-picker__trigger { .theme-picker .el-color-picker__trigger {
vertical-align: middle; margin-top: 12px;
height: 26px!important;
width: 26px!important;
padding: 2px;
} }
.theme-picker-dropdown .el-color-dropdown__link-btn { .theme-picker-dropdown .el-color-dropdown__link-btn {

View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M49.217 41.329l-.136-35.24c-.06-2.715-2.302-4.345-5.022-4.405h-3.65c-2.712-.06-4.866 2.303-4.806 5.016l.152 19.164-24.151-23.79a6.698 6.698 0 0 0-9.499 0 6.76 6.76 0 0 0 0 9.526l23.93 23.713-18.345.074c-2.712-.069-5.228 1.813-5.64 5.02v3.462c.069 2.721 2.31 4.97 5.022 5.03l35.028-.207c.052.005.087.025.133.025l2.457.054a4.626 4.626 0 0 0 3.436-1.38c.88-.874 1.205-2.096 1.169-3.462l-.262-2.465c0-.048.182-.081.182-.136h.002zm52.523 51.212l18.32-.073c2.713.06 5.224-1.609 5.64-4.815v-3.462c-.068-2.722-2.317-4.97-5.021-5.04l-34.58.21c-.053 0-.086-.021-.138-.021l-2.451-.06a4.64 4.64 0 0 0-3.445 1.381c-.885.868-1.201 2.094-1.174 3.46l.27 2.46c.005.06-.177.095-.177.141l.141 34.697c.069 2.713 2.31 4.338 5.022 4.397l3.45.006c2.705.062 4.867-2.31 4.8-5.026l-.153-18.752 24.151 23.946a6.69 6.69 0 0 0 9.494 0 6.747 6.747 0 0 0 0-9.523L101.74 92.54v.001zM48.125 80.662a4.636 4.636 0 0 0-3.437-1.382l-2.457.06c-.05 0-.082.022-.137.022l-35.025-.21c-2.712.07-4.957 2.318-5.022 5.04v3.462c.409 3.206 2.925 4.874 5.633 4.814l18.554.06-24.132 23.928c-2.62 2.626-2.62 6.89 0 9.524a6.694 6.694 0 0 0 9.496 0l24.155-23.79-.155 18.866c-.06 2.722 2.094 5.093 4.801 5.025h3.65c2.72-.069 4.962-1.685 5.022-4.406l.141-34.956c0-.05-.182-.082-.182-.136l.262-2.46c.03-1.366-.286-2.592-1.166-3.46h-.001zM80.08 47.397a4.62 4.62 0 0 0 3.443 1.374l2.45-.054c.055 0 .088-.02.143-.028l35.08.21c2.712-.062 4.953-2.312 5.021-5.033l.009-3.463c-.417-3.211-2.937-5.084-5.64-5.025l-18.615-.073 23.917-23.715c2.63-2.623 2.63-6.879.008-9.513a6.691 6.691 0 0 0-9.494 0L92.251 26.016l.155-19.312c.065-2.713-2.097-5.085-4.802-5.025h-3.45c-2.713.069-4.954 1.693-5.022 4.406l-.139 35.247c0 .054.18.088.18.136l-.267 2.465c-.028 1.366.288 2.588 1.174 3.463v.001z"/></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M38.47 52L52 38.462l-23.648-23.67L43.209 0H.035L0 43.137l14.757-14.865L38.47 52zm74.773 47.726L89.526 76 76 89.536l23.648 23.672L84.795 128h43.174L128 84.863l-14.757 14.863zM89.538 52l23.668-23.648L128 43.207V.038L84.866 0 99.73 14.76 76 38.472 89.538 52zM38.46 76L14.792 99.651 0 84.794v43.173l43.137.033-14.865-14.757L52 89.53 38.46 76z"/></svg>

After

Width:  |  Height:  |  Size: 421 B

1
src/icons/svg/search.svg Normal file
View 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

View File

@ -58,6 +58,7 @@ export default {
selectExcel: 'Export Selected', selectExcel: 'Export Selected',
uploadExcel: 'Upload Excel', uploadExcel: 'Upload Excel',
zip: 'Zip', zip: 'Zip',
pdf: 'PDF',
exportZip: 'Export Zip', exportZip: 'Export Zip',
theme: 'Theme', theme: 'Theme',
clipboardDemo: 'Clipboard', clipboardDemo: 'Clipboard',
@ -68,7 +69,6 @@ export default {
logOut: 'Log Out', logOut: 'Log Out',
dashboard: 'Dashboard', dashboard: 'Dashboard',
github: 'Github', github: 'Github',
screenfull: 'Screenfull',
theme: 'Theme', theme: 'Theme',
size: 'Global Size' size: 'Global Size'
}, },

View File

@ -58,6 +58,7 @@ export default {
selectExcel: 'Export seleccionado', selectExcel: 'Export seleccionado',
uploadExcel: 'Subir Excel', uploadExcel: 'Subir Excel',
zip: 'Zip', zip: 'Zip',
pdf: 'PDF',
exportZip: 'Exportar a Zip', exportZip: 'Exportar a Zip',
theme: 'Tema', theme: 'Tema',
clipboardDemo: 'Clipboard', clipboardDemo: 'Clipboard',
@ -68,7 +69,6 @@ export default {
logOut: 'Salir', logOut: 'Salir',
dashboard: 'Panel de control', dashboard: 'Panel de control',
github: 'Github', github: 'Github',
screenfull: 'Pantalla completa',
theme: 'Tema', theme: 'Tema',
size: 'Tamaño global' size: 'Tamaño global'
}, },

View File

@ -58,6 +58,7 @@ export default {
selectExcel: 'Export Selected', selectExcel: 'Export Selected',
uploadExcel: 'Upload Excel', uploadExcel: 'Upload Excel',
zip: 'Zip', zip: 'Zip',
pdf: 'PDF',
exportZip: 'Export Zip', exportZip: 'Export Zip',
theme: '换肤', theme: '换肤',
clipboardDemo: 'Clipboard', clipboardDemo: 'Clipboard',
@ -68,7 +69,6 @@ export default {
logOut: '退出登录', logOut: '退出登录',
dashboard: '首页', dashboard: '首页',
github: '项目地址', github: '项目地址',
screenfull: '全屏',
theme: '换肤', theme: '换肤',
size: '布局大小' size: '布局大小'
}, },

View File

@ -12,7 +12,7 @@ import chartsRouter from './modules/charts'
import tableRouter from './modules/table' import tableRouter from './modules/table'
import nestedRouter from './modules/nested' import nestedRouter from './modules/nested'
/** note: Submenu only appear when children.length>=1 /** note: sub-menu only appear when children.length>=1
* detail see https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html * detail see https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
**/ **/
@ -25,10 +25,11 @@ import nestedRouter from './modules/nested'
* name:'router-name' the name is used by <keep-alive> (must set!!!) * name:'router-name' the name is used by <keep-alive> (must set!!!)
* meta : { * meta : {
roles: ['admin','editor'] will control the page roles (you can set multiple roles) roles: ['admin','editor'] will control the page roles (you can set multiple roles)
title: 'title' the name show in submenu and breadcrumb (recommend set) title: 'title' the name show in sub-menu and breadcrumb (recommend set)
icon: 'svg-name' the icon show in the sidebar icon: 'svg-name' the icon show in the sidebar
noCache: true if true, the page will no be cached(default is false) noCache: true if true, the page will no be cached(default is false)
breadcrumb: false if false, the item will hidden in breadcrumb(default is true) breadcrumb: false if false, the item will hidden in breadcrumb(default is true)
affix: true if true, the tag will affix in the tags-view
} }
**/ **/
export const constantRouterMap = [ export const constantRouterMap = [
@ -72,7 +73,7 @@ export const constantRouterMap = [
path: 'dashboard', path: 'dashboard',
component: () => import('@/views/dashboard/index'), component: () => import('@/views/dashboard/index'),
name: 'Dashboard', name: 'Dashboard',
meta: { title: 'dashboard', icon: 'dashboard', noCache: true } meta: { title: 'dashboard', icon: 'dashboard', noCache: true, affix: true }
} }
] ]
}, },
@ -85,7 +86,7 @@ export const constantRouterMap = [
path: 'index', path: 'index',
component: () => import('@/views/documentation/index'), component: () => import('@/views/documentation/index'),
name: 'Documentation', name: 'Documentation',
meta: { title: 'documentation', icon: 'documentation', noCache: true } meta: { title: 'documentation', icon: 'documentation', affix: true }
} }
] ]
}, },
@ -297,13 +298,12 @@ export const asyncRouterMap = [
path: '/pdf', path: '/pdf',
component: Layout, component: Layout,
redirect: '/pdf/index', redirect: '/pdf/index',
meta: { title: 'PDF', icon: 'pdf' },
children: [ children: [
{ {
path: 'index', path: 'index',
component: () => import('@/views/pdf/index'), component: () => import('@/views/pdf/index'),
name: 'PDF', name: 'PDF',
meta: { title: 'PDF' } meta: { title: 'pdf', icon: 'pdf' }
} }
] ]
}, },

View File

@ -38,12 +38,9 @@ const tagsView = {
}, },
DEL_OTHERS_VISITED_VIEWS: (state, view) => { DEL_OTHERS_VISITED_VIEWS: (state, view) => {
for (const [i, v] of state.visitedViews.entries()) { state.visitedViews = state.visitedViews.filter(v => {
if (v.path === view.path) { return v.meta.affix || v.path === view.path
state.visitedViews = state.visitedViews.slice(i, i + 1) })
break
}
}
}, },
DEL_OTHERS_CACHED_VIEWS: (state, view) => { DEL_OTHERS_CACHED_VIEWS: (state, view) => {
for (const i of state.cachedViews) { for (const i of state.cachedViews) {
@ -56,7 +53,9 @@ const tagsView = {
}, },
DEL_ALL_VISITED_VIEWS: state => { DEL_ALL_VISITED_VIEWS: state => {
state.visitedViews = [] // keep affix tags
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 = []

View File

@ -6,24 +6,24 @@
<div class="right-menu"> <div class="right-menu">
<template v-if="device!=='mobile'"> <template v-if="device!=='mobile'">
<error-log class="errLog-container right-menu-item"/> <search class="right-menu-item" />
<el-tooltip :content="$t('navbar.screenfull')" effect="dark" placement="bottom"> <error-log class="errLog-container right-menu-item hover-effect"/>
<screenfull class="screenfull right-menu-item"/>
</el-tooltip> <screenfull class="right-menu-item hover-effect"/>
<el-tooltip :content="$t('navbar.size')" effect="dark" placement="bottom"> <el-tooltip :content="$t('navbar.size')" effect="dark" placement="bottom">
<size-select class="international right-menu-item"/> <size-select class="right-menu-item hover-effect"/>
</el-tooltip> </el-tooltip>
<lang-select class="international right-menu-item"/> <lang-select class="right-menu-item hover-effect"/>
<el-tooltip :content="$t('navbar.theme')" effect="dark" placement="bottom"> <el-tooltip :content="$t('navbar.theme')" effect="dark" placement="bottom">
<theme-picker class="theme-switch right-menu-item"/> <theme-picker class="right-menu-item hover-effect"/>
</el-tooltip> </el-tooltip>
</template> </template>
<el-dropdown class="avatar-container right-menu-item" trigger="click"> <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
<div class="avatar-wrapper"> <div class="avatar-wrapper">
<img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar"> <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar">
<i class="el-icon-caret-bottom"/> <i class="el-icon-caret-bottom"/>
@ -57,6 +57,7 @@ import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect' import SizeSelect from '@/components/SizeSelect'
import LangSelect from '@/components/LangSelect' import LangSelect from '@/components/LangSelect'
import ThemePicker from '@/components/ThemePicker' import ThemePicker from '@/components/ThemePicker'
import Search from '@/components/HeaderSearch'
export default { export default {
components: { components: {
@ -66,7 +67,8 @@ export default {
Screenfull, Screenfull,
SizeSelect, SizeSelect,
LangSelect, LangSelect,
ThemePicker ThemePicker,
Search
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([
@ -92,52 +94,70 @@ export default {
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>
.navbar { .navbar {
height: 50px; height: 50px;
line-height: 50px; overflow: hidden;
border-radius: 0px !important;
.hamburger-container { .hamburger-container {
line-height: 58px; line-height: 46px;
height: 50px; height: 100%;
float: left; float: left;
padding: 0 10px; cursor: pointer;
transition: background .3s;
&:hover {
background: rgba(0, 0, 0, .025)
} }
.breadcrumb-container{ }
.breadcrumb-container {
float: left; float: left;
} }
.errLog-container { .errLog-container {
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;
} }
.right-menu { .right-menu {
float: right; float: right;
height: 100%; height: 100%;
&:focus{ line-height: 50px;
&:focus {
outline: none; outline: none;
} }
.right-menu-item { .right-menu-item {
display: inline-block; display: inline-block;
margin: 0 8px; padding: 0 8px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background .3s;
&:hover {
background: rgba(0, 0, 0, .025)
} }
.screenfull {
height: 20px;
} }
.international{
vertical-align: top;
}
.theme-switch {
vertical-align: 15px;
} }
.avatar-container { .avatar-container {
height: 50px;
margin-right: 30px; margin-right: 30px;
.avatar-wrapper { .avatar-wrapper {
margin-top: 5px; margin-top: 5px;
position: relative; position: relative;
.user-avatar { .user-avatar {
cursor: pointer; cursor: pointer;
width: 40px; width: 40px;
height: 40px; height: 40px;
border-radius: 10px; border-radius: 10px;
} }
.el-icon-caret-bottom { .el-icon-caret-bottom {
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;

View File

@ -5,16 +5,16 @@ export default {
} }
}, },
mounted() { mounted() {
// In order to fix the click on menu on the ios device will trigger the mouseeleave bug // In order to fix the click on menu on the ios device will trigger the mouseleave bug
// https://github.com/PanJiaChen/vue-element-admin/issues/1135 // https://github.com/PanJiaChen/vue-element-admin/issues/1135
this.fixBugIniOS() this.fixBugIniOS()
}, },
methods: { methods: {
fixBugIniOS() { fixBugIniOS() {
const $submenu = this.$refs.submenu const $subMenu = this.$refs.subMenu
if ($submenu) { if ($subMenu) {
const handleMouseleave = $submenu.handleMouseleave const handleMouseleave = $subMenu.handleMouseleave
$submenu.handleMouseleave = (e) => { $subMenu.handleMouseleave = (e) => {
if (this.device === 'mobile') { if (this.device === 'mobile') {
return return
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<!-- eslint-disable vue/require-component-is--> <!-- eslint-disable vue/require-component-is -->
<component v-bind="linkProps(to)"> <component v-bind="linkProps(to)">
<slot/> <slot/>
</component> </component>
@ -17,11 +17,8 @@ export default {
} }
}, },
methods: { methods: {
isExternalLink(routePath) {
return isExternal(routePath)
},
linkProps(url) { linkProps(url) {
if (this.isExternalLink(url)) { if (isExternal(url)) {
return { return {
is: 'a', is: 'a',
href: url, href: url,

View File

@ -9,12 +9,13 @@
</app-link> </app-link>
</template> </template>
<el-submenu v-else ref="submenu" :index="resolvePath(item.path)"> <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)">
<template slot="title"> <template slot="title">
<item v-if="item.meta" :icon="item.meta.icon" :title="generateTitle(item.meta.title)" /> <item v-if="item.meta" :icon="item.meta.icon" :title="generateTitle(item.meta.title)" />
</template> </template>
<template v-for="child in item.children" v-if="!child.hidden"> <template v-for="child in item.children">
<template v-if="!child.hidden">
<sidebar-item <sidebar-item
v-if="child.children&&child.children.length>0" v-if="child.children&&child.children.length>0"
:is-nest="true" :is-nest="true"
@ -29,6 +30,7 @@
</el-menu-item> </el-menu-item>
</app-link> </app-link>
</template> </template>
</template>
</el-submenu> </el-submenu>
</div> </div>

View File

@ -1,7 +1,6 @@
<template> <template>
<el-scrollbar wrap-class="scrollbar-wrapper"> <el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu <el-menu
:show-timeout="200"
:default-active="$route.path" :default-active="$route.path"
:collapse="isCollapse" :collapse="isCollapse"
:background-color="variables.menuBg" :background-color="variables.menuBg"

View File

@ -12,14 +12,15 @@
@click.middle.native="closeSelectedTag(tag)" @click.middle.native="closeSelectedTag(tag)"
@contextmenu.prevent.native="openMenu(tag,$event)"> @contextmenu.prevent.native="openMenu(tag,$event)">
{{ generateTitle(tag.title) }} {{ generateTitle(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)">{{ $t('tagsView.refresh') }}</li> <li @click="refreshSelectedTag(selectedTag)">{{ $t('tagsView.refresh') }}</li>
<li @click="closeSelectedTag(selectedTag)">{{ $t('tagsView.close') }}</li> <li v-if="!(selectedTag.meta&&selectedTag.meta.affix)" @click="closeSelectedTag(selectedTag)">{{
$t('tagsView.close') }}</li>
<li @click="closeOthersTags">{{ $t('tagsView.closeOthers') }}</li> <li @click="closeOthersTags">{{ $t('tagsView.closeOthers') }}</li>
<li @click="closeAllTags">{{ $t('tagsView.closeAll') }}</li> <li @click="closeAllTags(selectedTag)">{{ $t('tagsView.closeAll') }}</li>
</ul> </ul>
</div> </div>
</template> </template>
@ -27,6 +28,7 @@
<script> <script>
import ScrollPane from '@/components/ScrollPane' import ScrollPane from '@/components/ScrollPane'
import { generateTitle } from '@/utils/i18n' import { generateTitle } from '@/utils/i18n'
import path from 'path'
export default { export default {
components: { ScrollPane }, components: { ScrollPane },
@ -35,17 +37,21 @@ export default {
visible: false, visible: false,
top: 0, top: 0,
left: 0, left: 0,
selectedTag: {} selectedTag: {},
affixTags: []
} }
}, },
computed: { computed: {
visitedViews() { visitedViews() {
return this.$store.state.tagsView.visitedViews return this.$store.state.tagsView.visitedViews
},
routers() {
return this.$store.state.permission.routers
} }
}, },
watch: { watch: {
$route() { $route() {
this.addViewTags() this.addTags()
this.moveToCurrentTag() this.moveToCurrentTag()
}, },
visible(value) { visible(value) {
@ -57,14 +63,44 @@ export default {
} }
}, },
mounted() { mounted() {
this.addViewTags() this.initTags()
this.addTags()
}, },
methods: { methods: {
generateTitle, // generateTitle by vue-i18n generateTitle, // generateTitle by vue-i18n
isActive(route) { isActive(route) {
return route.path === this.$route.path return route.path === this.$route.path
}, },
addViewTags() { filterAffixTags(routes, basePath = '/') {
let tags = []
routes.forEach(route => {
if (route.meta && route.meta.affix) {
tags.push({
path: path.resolve(basePath, route.path),
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(this.routers)
for (const tag of affixTags) {
// Must have tag name
if (tag.name) {
this.$store.dispatch('addVisitedView', tag)
}
}
},
addTags() {
const { name } = this.$route const { name } = this.$route
if (name) { if (name) {
this.$store.dispatch('addView', this.$route) this.$store.dispatch('addView', this.$route)
@ -101,12 +137,7 @@ export default {
closeSelectedTag(view) { closeSelectedTag(view) {
this.$store.dispatch('delView', view).then(({ visitedViews }) => { this.$store.dispatch('delView', view).then(({ visitedViews }) => {
if (this.isActive(view)) { if (this.isActive(view)) {
const latestView = visitedViews.slice(-1)[0] this.toLastView(visitedViews)
if (latestView) {
this.$router.push(latestView)
} else {
this.$router.push('/')
}
} }
}) })
}, },
@ -116,9 +147,22 @@ export default {
this.moveToCurrentTag() this.moveToCurrentTag()
}) })
}, },
closeAllTags() { closeAllTags(view) {
this.$store.dispatch('delAllViews') this.$store.dispatch('delAllViews').then(({ visitedViews }) => {
if (this.affixTags.some(tag => tag.path === view.path)) {
return
}
this.toLastView(visitedViews)
})
},
toLastView(visitedViews) {
const latestView = visitedViews.slice(-1)[0]
if (latestView) {
this.$router.push(latestView)
} else {
// You can set another route
this.$router.push('/') this.$router.push('/')
}
}, },
openMenu(tag, e) { openMenu(tag, e) {
const menuMinWidth = 105 const menuMinWidth = 105

View File

@ -262,8 +262,10 @@ $light_gray:#eee;
.set-language { .set-language {
color: #fff; color: #fff;
position: absolute; position: absolute;
top: 5px; top: 3px;
font-size:18px;
right: 0px; right: 0px;
cursor: pointer;
} }
} }
.show-pwd { .show-pwd {

View File

@ -46,7 +46,7 @@
</el-table-column> </el-table-column>
<el-table-column align="center" label="Drag" width="80"> <el-table-column align="center" label="Drag" width="80">
<template slot-scope="scope"> <template slot-scope="{}">
<svg-icon class="drag-handler" icon-class="drag"/> <svg-icon class="drag-handler" icon-class="drag"/>
</template> </template>
</el-table-column> </el-table-column>