Merge branch 'hotfix/from1.4.8'
Former-commit-id: a3f063630e5c8094dc5579c42e0137a769c109e8
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
||||
# travis
|
||||
|
||||
# 页面 title 前缀
|
||||
VUE_APP_TITLE=D2Admin Preview
|
||||
|
||||
# 页面 指定使用的模式
|
||||
NODE_ENV=production
|
||||
|
||||
# 标记当前编译版本
|
||||
VUE_APP_TRAVIS=TRUE
|
||||
+1
-1
@@ -9,7 +9,7 @@ branches:
|
||||
- master
|
||||
|
||||
script:
|
||||
- npm run build
|
||||
- npm run build:travis
|
||||
|
||||
deploy:
|
||||
provider: pages
|
||||
|
||||
Generated
+1196
-1176
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -1,16 +1,18 @@
|
||||
{
|
||||
"name": "d2-admin",
|
||||
"version": "1.3.0",
|
||||
"version": "1.4.8",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve --open",
|
||||
"start": "vue-cli-service serve --open",
|
||||
"dev": "vue-cli-service serve --open",
|
||||
"build": "vue-cli-service build",
|
||||
"build:travis": "vue-cli-service build --mode travis",
|
||||
"lint": "vue-cli-service lint --fix",
|
||||
"test:unit": "vue-cli-service test:unit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@d2-projects/d2-crud": "^1.2.0",
|
||||
"axios": "^0.17.1",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"better-scroll": "^1.12.1",
|
||||
@@ -23,6 +25,7 @@
|
||||
"lodash": "^4.17.10",
|
||||
"lowdb": "^1.0.0",
|
||||
"mockjs": "^1.0.1-beta3",
|
||||
"nprogress": "^0.2.0",
|
||||
"particles.js": "^2.0.0",
|
||||
"screenfull": "^3.3.2",
|
||||
"ua-parser-js": "^0.7.18",
|
||||
@@ -48,9 +51,6 @@
|
||||
"text-loader": "0.0.1",
|
||||
"vue-template-compiler": "^2.5.17"
|
||||
},
|
||||
"gitHooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"vue-cli-service lint",
|
||||
|
||||
+3
-2
@@ -146,8 +146,9 @@
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
<script src="./script/ua-parser.min.js"></script>
|
||||
<script src="./script/ua.js"></script>
|
||||
<!-- ua -->
|
||||
<script src="<%= BASE_URL %>script/ua-parser.min.js"></script>
|
||||
<script src="<%= BASE_URL %>script/ua.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#nprogress {
|
||||
.bar {
|
||||
background: $color-primary !important;
|
||||
}
|
||||
.peg {
|
||||
box-shadow: 0 0 10px $color-primary, 0 0 5px $color-primary !important;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
@import '~@/assets/style/fixed/base.scss';
|
||||
// 补丁 element
|
||||
@import '~@/assets/style/fixed/element.scss';
|
||||
// 补丁 n-progress
|
||||
@import '~@/assets/style/fixed/n-progress.scss';
|
||||
|
||||
// 动画
|
||||
@import '~@/assets/style/animate/vue-transition.scss';
|
||||
|
||||
@@ -26,9 +26,51 @@
|
||||
// 内容层
|
||||
.d2-layout-header-aside-content {
|
||||
@extend %full;
|
||||
$d2-theme-header-height: 60px;
|
||||
.d2-theme-header {
|
||||
height: $d2-theme-header-height;
|
||||
height: 60px;
|
||||
.d2-theme-header-menu {
|
||||
overflow: hidden;
|
||||
&.is-scrollable {
|
||||
position: relative;
|
||||
padding: 0 20px;
|
||||
.d2-theme-header-menu__prev, .d2-theme-header-menu__next {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.d2-theme-header-menu__content {
|
||||
overflow: hidden;
|
||||
.d2-theme-header-menu__scroll {
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
-webkit-transition: -webkit-transform .3s;
|
||||
transition: -webkit-transform .3s;
|
||||
transition: transform .3s;
|
||||
transition: transform .3s, -webkit-transform .3s;
|
||||
transition: transform .3s,-webkit-transform .3s;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
.d2-theme-header-menu__prev, .d2-theme-header-menu__next {
|
||||
height: 60px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
}
|
||||
.d2-theme-header-menu__prev {
|
||||
left: 0;
|
||||
border-top-left-radius: 2px;
|
||||
border-bottom-left-radius: 2px;
|
||||
}
|
||||
.d2-theme-header-menu__next {
|
||||
right: 0;
|
||||
border-top-right-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.d2-theme-container {
|
||||
.d2-theme-container-aside {
|
||||
@@ -58,13 +100,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 主题公用
|
||||
.d2-layout-header-aside-group {
|
||||
&.grayMode {
|
||||
@@ -135,7 +170,6 @@
|
||||
padding: 14px 12px;
|
||||
border-radius: 4px;
|
||||
margin: 0px !important;
|
||||
margin-left: 10px !important;
|
||||
}
|
||||
.el-dropdown {
|
||||
@extend %unable-select;
|
||||
|
||||
@@ -63,6 +63,17 @@
|
||||
|
||||
// 顶栏
|
||||
.d2-theme-header {
|
||||
// 顶栏菜单空间不足时显示的滚动控件
|
||||
.d2-theme-header-menu {
|
||||
.d2-theme-header-menu__prev, .d2-theme-header-menu__next {
|
||||
color: $theme-header-item-color;
|
||||
background: $theme-header-item-background-color;
|
||||
&:hover {
|
||||
color: $theme-header-item-color-hover;
|
||||
background: $theme-header-item-background-color-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 切换按钮
|
||||
.toggle-aside-btn {
|
||||
i {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<template>
|
||||
<el-menu-item :index="menu.path || uniqueId">
|
||||
<i v-if="menu.icon" :class="`fa fa-${menu.icon}`"></i>
|
||||
<!-- <i v-else-if="menu.iconSvg">
|
||||
<d2-icon-svg :name="menu.iconSvg"/>
|
||||
</i> -->
|
||||
<d2-icon-svg v-else-if="menu.iconSvg" :name="menu.iconSvg"/>
|
||||
<i v-else class="fa fa-file-o"></i>
|
||||
<span slot="title">{{menu.title || '未命名菜单'}}</span>
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
<el-submenu :index="menu.path || uniqueId">
|
||||
<template slot="title">
|
||||
<i v-if="menu.icon" :class="`fa fa-${menu.icon}`"></i>
|
||||
<!-- <i v-else-if="menu.iconSvg">
|
||||
<d2-icon-svg :name="menu.iconSvg"/>
|
||||
</i> -->
|
||||
<d2-icon-svg v-else-if="menu.iconSvg" :name="menu.iconSvg"/>
|
||||
<i v-else class="fa fa-folder-o"></i>
|
||||
<span slot="title">{{menu.title}}</span>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
import { mapState, mapActions } from 'vuex'
|
||||
export default {
|
||||
computed: {
|
||||
...mapState('d2admin/fullscreen', [
|
||||
@@ -19,7 +19,7 @@ export default {
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('d2admin/fullscreen', [
|
||||
...mapActions('d2admin/fullscreen', [
|
||||
'toggle'
|
||||
])
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<el-dropdown placement="bottom" size="small" @command="handleChange">
|
||||
<el-button class="d2-mr btn-text can-hover" type="text">
|
||||
<d2-icon name="font" style="font-size: 16px;"/>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="default">
|
||||
<d2-icon :name="iconName('default')" class="d2-mr-5"/>默认
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="medium">
|
||||
<d2-icon :name="iconName('medium')" class="d2-mr-5"/>中
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="small">
|
||||
<d2-icon :name="iconName('small')" class="d2-mr-5"/>小
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="mini">
|
||||
<d2-icon :name="iconName('mini')" class="d2-mr-5"/>最小
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations, mapActions } from 'vuex'
|
||||
export default {
|
||||
name: 'd2-header-size',
|
||||
computed: {
|
||||
...mapState('d2admin/size', [
|
||||
'value'
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
// 注意 这里是关键
|
||||
// 因为需要访问 this.$ELEMENT 所以只能在这里使用这种方式
|
||||
value: {
|
||||
handler (val) {
|
||||
if (this.$ELEMENT.size !== val) {
|
||||
// 设置 element 全局尺寸
|
||||
this.$ELEMENT.size = val
|
||||
// 清空缓存设置
|
||||
this.pageKeepAliveClean()
|
||||
// 刷新此页面
|
||||
const { path, query } = this.$route
|
||||
this.$router.replace({
|
||||
path: '/redirect/' + JSON.stringify({ path, query })
|
||||
})
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
pageKeepAliveClean: 'd2admin/page/keepAliveClean'
|
||||
}),
|
||||
...mapActions({
|
||||
sizeSet: 'd2admin/size/set'
|
||||
}),
|
||||
handleChange (value) {
|
||||
this.sizeSet(value)
|
||||
},
|
||||
iconName (name) {
|
||||
return name === this.value ? 'dot-circle-o' : 'circle-o'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -18,7 +18,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
import { mapState, mapActions } from 'vuex'
|
||||
export default {
|
||||
name: 'd2-theme-list',
|
||||
data () {
|
||||
@@ -36,7 +36,7 @@ export default {
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('d2admin/theme', [
|
||||
...mapActions('d2admin/theme', [
|
||||
'set'
|
||||
]),
|
||||
handleSelectTheme (name) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dropdown class="d2-mr">
|
||||
<el-dropdown size="small" class="d2-mr">
|
||||
<span class="btn-text">你好 {{info.name}}</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item @click.native="logOff">
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
<template>
|
||||
<div class="d2-theme-header-menu" ref="page" :class="{'is-scrollable': isScroll}" flex="cross:center">
|
||||
<div class="d2-theme-header-menu__content" ref="content" flex-box="1" flex>
|
||||
<div class="d2-theme-header-menu__scroll" ref="scroll" flex-box="0" :style="'transform: translateX(' + currentTranslateX + 'px);'">
|
||||
<el-menu mode="horizontal" :default-active="active" @select="handleMenuSelect">
|
||||
<template v-for="(menu, menuIndex) in header">
|
||||
<d2-layout-header-aside-menu-item v-if="menu.children === undefined" :menu="menu" :key="menuIndex"/>
|
||||
<d2-layout-header-aside-menu-sub v-else :menu="menu" :key="menuIndex"/>
|
||||
</template>
|
||||
</el-menu>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isScroll" class="d2-theme-header-menu__prev" flex-box="0" @click="scroll('left')" flex="main:center cross:center">
|
||||
<i class="el-icon-arrow-left"></i>
|
||||
</div>
|
||||
<div v-if="isScroll" class="d2-theme-header-menu__next" flex-box="0" @click="scroll('right')" flex="cross:center">
|
||||
<i class="el-icon-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { throttle } from 'lodash'
|
||||
import { mapState } from 'vuex'
|
||||
import menuMixin from '../mixin/menu'
|
||||
import d2LayoutMainMenuItem from '../components/menu-item/index.vue'
|
||||
@@ -28,7 +41,12 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
active: ''
|
||||
active: '',
|
||||
isScroll: false,
|
||||
scrollWidth: 0,
|
||||
contentWidth: 0,
|
||||
currentTranslateX: 0,
|
||||
throttledCheckScroll: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -38,6 +56,67 @@ export default {
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
scroll (direction) {
|
||||
if (direction === 'left') {
|
||||
// 向右滚动
|
||||
this.currentTranslateX = 0
|
||||
} else {
|
||||
// 向左滚动
|
||||
if (this.contentWidth * 2 - this.currentTranslateX <= this.scrollWidth) {
|
||||
this.currentTranslateX -= this.contentWidth
|
||||
} else {
|
||||
this.currentTranslateX = this.contentWidth - this.scrollWidth
|
||||
}
|
||||
}
|
||||
},
|
||||
checkScroll () {
|
||||
let contentWidth = this.$refs.content.clientWidth
|
||||
let scrollWidth = this.$refs.scroll.clientWidth
|
||||
if (this.isScroll) {
|
||||
// 页面依旧允许滚动的情况,需要更新width
|
||||
if (this.contentWidth - this.scrollWidth === this.currentTranslateX) {
|
||||
// currentTranslateX 也需要相应变化【在右端到头的情况时】
|
||||
this.currentTranslateX = contentWidth - scrollWidth
|
||||
// 快速的滑动依旧存在判断和计算时对应的contentWidth变成正数,所以需要限制一下
|
||||
if (this.currentTranslateX > 0) {
|
||||
this.currentTranslateX = 0
|
||||
}
|
||||
}
|
||||
// 更新元素数据
|
||||
this.contentWidth = contentWidth
|
||||
this.scrollWidth = scrollWidth
|
||||
// 判断何时滚动消失: 当page > content + btns(40)
|
||||
if (contentWidth > scrollWidth + 40) {
|
||||
this.isScroll = false
|
||||
}
|
||||
}
|
||||
// 判断何时滚动出现: 当page < content
|
||||
if (!this.isScroll && contentWidth < scrollWidth) {
|
||||
this.isScroll = true
|
||||
// 注意,当isScroll变为true,对应的元素盒子大小会发生变化
|
||||
this.$nextTick(() => {
|
||||
contentWidth = this.$refs.content.clientWidth
|
||||
scrollWidth = this.$refs.scroll.clientWidth
|
||||
this.contentWidth = contentWidth
|
||||
this.scrollWidth = scrollWidth
|
||||
this.currentTranslateX = 0
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// 初始化判断
|
||||
// 默认判断父元素和子元素的大小,以确定初始情况是否显示滚动
|
||||
this.checkScroll()
|
||||
// 全局窗口变化监听,判断父元素和子元素的大小,从而控制isScroll的开关
|
||||
this.throttledCheckScroll = throttle(this.checkScroll, 300)
|
||||
window.addEventListener('resize', this.throttledCheckScroll)
|
||||
},
|
||||
beforeDestroy () {
|
||||
// 取消监听
|
||||
window.removeEventListener('resize', this.throttledCheckScroll)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
<template>
|
||||
<div class="panel-search" flex="dir:top">
|
||||
<div class="panel-search__input-group" flex-box="0" flex="dir:top main:center cross:center">
|
||||
<div
|
||||
class="panel-search"
|
||||
flex="dir:top">
|
||||
<div
|
||||
class="panel-search__input-group"
|
||||
flex-box="0"
|
||||
flex="dir:top main:center cross:center"
|
||||
@click.self="handlePanelClick">
|
||||
<d2-icon-svg
|
||||
class="panel-search__logo"
|
||||
name="d2-admin-text"/>
|
||||
@@ -15,7 +21,9 @@
|
||||
:clearable="true"
|
||||
@keydown.esc.native="handleEsc"
|
||||
@select="handleSelect">
|
||||
<d2-panel-search-item slot-scope="{ item }" :item="item"/>
|
||||
<d2-panel-search-item
|
||||
slot-scope="{ item }"
|
||||
:item="item"/>
|
||||
</el-autocomplete>
|
||||
<div class="panel-search__tip">
|
||||
您可以使用快捷键
|
||||
@@ -155,6 +163,12 @@ export default {
|
||||
this.$refs.input.activated = false
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @augments 接收用户点击空白区域的关闭
|
||||
*/
|
||||
handlePanelClick () {
|
||||
this.handleEsc()
|
||||
},
|
||||
/**
|
||||
* @augments 接收用户触发的关闭
|
||||
*/
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
class="d2-multiple-page-control-btn"
|
||||
flex-box="0">
|
||||
<el-dropdown
|
||||
size="default"
|
||||
split-button
|
||||
@click="handleControlBtnClick"
|
||||
@command="command => handleControlItemClick(command)">
|
||||
@@ -58,7 +59,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
import { mapState, mapActions } from 'vuex'
|
||||
export default {
|
||||
components: {
|
||||
D2Contextmenu: () => import('../contextmenu'),
|
||||
@@ -88,7 +89,7 @@ export default {
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('d2admin/page', [
|
||||
...mapActions('d2admin/page', [
|
||||
'close',
|
||||
'closeLeft',
|
||||
'closeRight',
|
||||
@@ -100,7 +101,6 @@ export default {
|
||||
*/
|
||||
handleContextmenu (event) {
|
||||
let target = event.target
|
||||
|
||||
// 解决 https://github.com/d2-projects/d2-admin/issues/54
|
||||
let flag = false
|
||||
if (target.className.indexOf('el-tabs__item') > -1) flag = true
|
||||
@@ -108,7 +108,6 @@ export default {
|
||||
target = target.parentNode
|
||||
flag = true
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
@@ -11,24 +11,26 @@
|
||||
<div
|
||||
class="d2-theme-header"
|
||||
:style="{
|
||||
opacity: this.searchActive ? 0.3 : 1
|
||||
opacity: this.searchActive ? 0.5 : 1
|
||||
}"
|
||||
flex-box="0">
|
||||
<div class="logo-group" :style="{width: asideCollapse ? asideWidthCollapse : asideWidth}">
|
||||
flex-box="0"
|
||||
flex>
|
||||
<div class="logo-group" :style="{width: asideCollapse ? asideWidthCollapse : asideWidth}" flex-box="0">
|
||||
<img v-if="asideCollapse" :src="`${$baseUrl}image/theme/${themeActiveSetting.name}/logo/icon-only.png`">
|
||||
<img v-else :src="`${$baseUrl}image/theme/${themeActiveSetting.name}/logo/all.png`">
|
||||
</div>
|
||||
<div class="toggle-aside-btn" @click="handleToggleAside">
|
||||
<div class="toggle-aside-btn" @click="handleToggleAside" flex-box="0">
|
||||
<d2-icon name="bars"/>
|
||||
</div>
|
||||
<d2-menu-header/>
|
||||
<d2-menu-header flex-box="1"/>
|
||||
<!-- 顶栏右侧 -->
|
||||
<div class="d2-header-right">
|
||||
<div class="d2-header-right" flex-box="0">
|
||||
<!-- 如果你只想在开发环境显示这个按钮请添加 v-if="$env === 'development'" -->
|
||||
<d2-header-search @click="handleSearchClick"/>
|
||||
<d2-header-error-log/>
|
||||
<d2-header-fullscreen/>
|
||||
<d2-header-theme/>
|
||||
<d2-header-size/>
|
||||
<d2-header-user/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -41,7 +43,7 @@
|
||||
class="d2-theme-container-aside"
|
||||
:style="{
|
||||
width: asideCollapse ? asideWidthCollapse : asideWidth,
|
||||
opacity: this.searchActive ? 0.3 : 1
|
||||
opacity: this.searchActive ? 0.5 : 1
|
||||
}">
|
||||
<d2-menu-side/>
|
||||
</div>
|
||||
@@ -79,7 +81,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters, mapMutations } from 'vuex'
|
||||
import { mapState, mapGetters, mapActions } from 'vuex'
|
||||
import mixinSearch from './mixins/search'
|
||||
export default {
|
||||
name: 'd2-layout-header-aside',
|
||||
@@ -92,6 +94,7 @@ export default {
|
||||
'd2-tabs': () => import('./components/tabs'),
|
||||
'd2-header-fullscreen': () => import('./components/header-fullscreen'),
|
||||
'd2-header-search': () => import('./components/header-search'),
|
||||
'd2-header-size': () => import('./components/header-size'),
|
||||
'd2-header-theme': () => import('./components/header-theme'),
|
||||
'd2-header-user': () => import('./components/header-user'),
|
||||
'd2-header-error-log': () => import('./components/header-error-log')
|
||||
@@ -106,12 +109,12 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapState('d2admin', {
|
||||
keepAlive: state => state.page.keepAlive,
|
||||
grayActive: state => state.gray.active,
|
||||
transitionActive: state => state.transition.active,
|
||||
asideCollapse: state => state.menu.asideCollapse
|
||||
}),
|
||||
...mapGetters('d2admin', {
|
||||
keepAlive: 'page/keepAlive',
|
||||
themeActiveSetting: 'theme/activeSetting'
|
||||
}),
|
||||
/**
|
||||
@@ -126,14 +129,14 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
menuAsideCollapseToggle: 'd2admin/menu/asideCollapseToggle'
|
||||
}),
|
||||
...mapActions('d2admin/menu', [
|
||||
'asideCollapseToggle'
|
||||
]),
|
||||
/**
|
||||
* 接收点击切换侧边栏的按钮
|
||||
*/
|
||||
handleToggleAside () {
|
||||
this.menuAsideCollapseToggle()
|
||||
this.asideCollapseToggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-4
@@ -12,6 +12,9 @@ import i18n from './i18n'
|
||||
// 核心插件
|
||||
import d2Admin from '@/plugin/d2admin'
|
||||
|
||||
// [ 可选插件组件 ]D2-Crud
|
||||
import D2Crud from '@d2-projects/d2-crud'
|
||||
|
||||
// 菜单和路由设置
|
||||
import router from './router'
|
||||
import menuHeader from '@/menu/header'
|
||||
@@ -21,6 +24,9 @@ import { frameInRoutes } from '@/router/routes'
|
||||
// 核心插件
|
||||
Vue.use(d2Admin)
|
||||
|
||||
// 可选插件组件
|
||||
Vue.use(D2Crud)
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
@@ -39,13 +45,11 @@ new Vue({
|
||||
mounted () {
|
||||
// 展示系统信息
|
||||
this.$store.commit('d2admin/releases/versionShow')
|
||||
// 检查最新版本
|
||||
this.$store.dispatch('d2admin/releases/checkUpdate')
|
||||
// 用户登录后从数据库加载一系列的设置
|
||||
this.$store.commit('d2admin/account/load')
|
||||
this.$store.dispatch('d2admin/account/load')
|
||||
// 获取并记录用户 UA
|
||||
this.$store.commit('d2admin/ua/get')
|
||||
// 初始化全屏监听
|
||||
this.$store.commit('d2admin/fullscreen/listen')
|
||||
this.$store.dispatch('d2admin/fullscreen/listen')
|
||||
}
|
||||
}).$mount('#app')
|
||||
|
||||
Executable → Regular
Executable → Regular
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div class="d2-badge">
|
||||
<p align="center">
|
||||
<a><img src="https://img.shields.io/github/release/d2-projects/d2-admin.svg"/></a>
|
||||
<a><img src="https://img.shields.io/github/forks/d2-projects/d2-admin.svg"/></a>
|
||||
<a><img src="https://img.shields.io/github/stars/d2-projects/d2-admin.svg"/></a>
|
||||
<a><img src="https://img.shields.io/github/issues/d2-projects/d2-admin.svg"/></a>
|
||||
<a><img src="https://img.shields.io/github/issues-closed/d2-projects/d2-admin.svg"/></a>
|
||||
<a><img src="https://img.shields.io/github/issues-pr/d2-projects/d2-admin.svg"/></a>
|
||||
<a><img src="https://img.shields.io/github/issues-pr-closed/d2-projects/d2-admin.svg"/></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a><img src="https://img.shields.io/npm/v/@d2-admin/ice-scaffold.svg"/></a>
|
||||
<a href="https://www.travis-ci.org/d2-projects/d2-admin"><img src="https://www.travis-ci.org/d2-projects/d2-admin.svg?branch=master"/></a>
|
||||
<a><img src="https://img.shields.io/github/last-commit/d2-projects/d2-admin.svg"/></a>
|
||||
<a><img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg"/></a>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.d2-badge {
|
||||
margin-bottom: 20px;
|
||||
p {
|
||||
margin: 0px;
|
||||
margin-bottom: 2px;
|
||||
:nth-last-child() {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
a {
|
||||
display: inline-block;
|
||||
margin: 0px 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -27,7 +27,8 @@
|
||||
</p>
|
||||
</el-popover>
|
||||
</div>
|
||||
<d2-help-btn class="d2-mt"/>
|
||||
<d2-badge/>
|
||||
<d2-help-btn/>
|
||||
</template>
|
||||
</d2-page-cover>
|
||||
</d2-container>
|
||||
@@ -35,9 +36,11 @@
|
||||
|
||||
<script>
|
||||
import D2HelpBtn from './components/d2-help-btn'
|
||||
import D2Badge from './components/d2-badge'
|
||||
export default {
|
||||
components: {
|
||||
D2HelpBtn
|
||||
D2HelpBtn,
|
||||
D2Badge
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -48,6 +51,8 @@ export default {
|
||||
.page__btn-group {
|
||||
color: $color-text-placehoder;
|
||||
font-size: 12px;
|
||||
margin-top: -10px;
|
||||
margin-bottom: 20px;
|
||||
span {
|
||||
color: $color-text-sub;
|
||||
&:hover {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<!-- 表单部分 -->
|
||||
<div class="form-group">
|
||||
<el-card>
|
||||
<el-form ref="loginForm" label-position="top" :rules="rules" :model="formLogin">
|
||||
<el-form ref="loginForm" label-position="top" :rules="rules" :model="formLogin" size="default">
|
||||
<el-form-item prop="username">
|
||||
<el-input type="text" v-model="formLogin.username" placeholder="用户名">
|
||||
<i slot="prepend" class="fa fa-user-circle-o"></i>
|
||||
@@ -28,12 +28,12 @@
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-button @click="submit" type="primary" class="button-login">登录</el-button>
|
||||
<el-button size="default" @click="submit" type="primary" class="button-login">登录</el-button>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 快速登录按钮 -->
|
||||
<el-button type="info" class="button-help" @click="dialogVisible = true">
|
||||
<el-button size="default" type="info" class="button-help" @click="dialogVisible = true">
|
||||
快速选择用户(测试功能)
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
<script>
|
||||
// 跳板页面
|
||||
export default {
|
||||
beforeCreate () {
|
||||
const path = this.$route.params.path
|
||||
this.$router.replace(JSON.parse(path))
|
||||
},
|
||||
render: function (h) {
|
||||
return h()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -3,6 +3,8 @@ import ElementUI from 'element-ui'
|
||||
import 'element-ui/lib/theme-chalk/index.css'
|
||||
// flex 布局库
|
||||
import 'flex.css'
|
||||
// store
|
||||
import store from '@/store/index'
|
||||
// 组件
|
||||
import '@/components'
|
||||
// svg 图标
|
||||
@@ -13,9 +15,18 @@ import pluginLog from '@/plugin/log'
|
||||
import pluginOpen from '@/plugin/open'
|
||||
|
||||
export default {
|
||||
install (Vue, options) {
|
||||
async install (Vue, options) {
|
||||
// 获得用户设置的全局尺寸
|
||||
const size = await store.dispatch('d2admin/db/get', {
|
||||
dbName: 'sys',
|
||||
path: 'size.value',
|
||||
defaultValue: '',
|
||||
user: true
|
||||
})
|
||||
// Element
|
||||
Vue.use(ElementUI)
|
||||
Vue.use(ElementUI, {
|
||||
size
|
||||
})
|
||||
// 插件
|
||||
Vue.use(pluginError)
|
||||
Vue.use(pluginLog)
|
||||
|
||||
+9
-1
@@ -1,6 +1,10 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
|
||||
// 进度条
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'
|
||||
|
||||
import store from '@/store/index'
|
||||
|
||||
import util from '@/libs/util.js'
|
||||
@@ -20,6 +24,8 @@ const router = new VueRouter({
|
||||
* 权限验证
|
||||
*/
|
||||
router.beforeEach((to, from, next) => {
|
||||
// 进度条
|
||||
NProgress.start()
|
||||
// 关闭搜索面板
|
||||
store.commit('d2admin/search/set', false)
|
||||
// 验证当前路由所有的匹配中是否需要有登录验证的
|
||||
@@ -45,11 +51,13 @@ router.beforeEach((to, from, next) => {
|
||||
})
|
||||
|
||||
router.afterEach(to => {
|
||||
// 进度条
|
||||
NProgress.done()
|
||||
// 需要的信息
|
||||
const app = router.app
|
||||
const { name, params, query } = to
|
||||
// 多页控制 打开新的页面
|
||||
app.$store.commit('d2admin/page/open', { name, params, query })
|
||||
app.$store.dispatch('d2admin/page/open', { name, params, query })
|
||||
// 更改标题
|
||||
util.title(to.meta.title)
|
||||
})
|
||||
|
||||
@@ -44,7 +44,12 @@ const frameIn = [
|
||||
* 在主框架之外显示
|
||||
*/
|
||||
const frameOut = [
|
||||
// 登陆
|
||||
// 页面重定向使用 必须保留
|
||||
{
|
||||
path: '/redirect/:path*',
|
||||
component: () => import('@/pages/redirect')
|
||||
},
|
||||
// 登录
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
|
||||
@@ -11,6 +11,7 @@ import gray from './modules/gray'
|
||||
import page from './modules/page'
|
||||
import transition from './modules/transition'
|
||||
import search from './modules/search'
|
||||
import size from './modules/size'
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
@@ -27,6 +28,7 @@ export default {
|
||||
gray,
|
||||
page,
|
||||
transition,
|
||||
search
|
||||
search,
|
||||
size
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,7 @@ export default {
|
||||
* @param {Object} param password {String} 密码
|
||||
* @param {Object} param route {Object} 登录成功后定向的路由对象
|
||||
*/
|
||||
login ({
|
||||
commit
|
||||
}, {
|
||||
login ({ dispatch }, {
|
||||
vm,
|
||||
username,
|
||||
password,
|
||||
@@ -27,7 +25,7 @@ export default {
|
||||
username,
|
||||
password
|
||||
})
|
||||
.then(res => {
|
||||
.then(async res => {
|
||||
// 设置 cookie 一定要存 uuid 和 token 两个 cookie
|
||||
// 整个系统依赖这两个数据进行校验和存储
|
||||
// uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复
|
||||
@@ -36,11 +34,11 @@ export default {
|
||||
util.cookies.set('uuid', res.uuid)
|
||||
util.cookies.set('token', res.token)
|
||||
// 设置 vuex 用户信息
|
||||
commit('d2admin/user/set', {
|
||||
await dispatch('d2admin/user/set', {
|
||||
name: res.name
|
||||
}, { root: true })
|
||||
// 用户登录后从持久化数据加载一系列的设置
|
||||
commit('load')
|
||||
await dispatch('load')
|
||||
// 更新路由 尝试去获取 cookie 里保存的需要重定向的页面完整地址
|
||||
const path = util.cookies.get('redirect')
|
||||
// 根据是否存有重定向页面判断如何重定向
|
||||
@@ -49,9 +47,7 @@ export default {
|
||||
util.cookies.remove('redirect')
|
||||
})
|
||||
.catch(err => {
|
||||
console.group('登录结果')
|
||||
console.log('err: ', err)
|
||||
console.groupEnd()
|
||||
})
|
||||
},
|
||||
/**
|
||||
@@ -92,24 +88,28 @@ export default {
|
||||
} else {
|
||||
logout()
|
||||
}
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
/**
|
||||
* @description 用户登录后从持久化数据加载一系列的设置
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
load (state) {
|
||||
load ({ commit, dispatch }) {
|
||||
return new Promise(async resolve => {
|
||||
// DB -> store 加载用户名
|
||||
this.commit('d2admin/user/load')
|
||||
await dispatch('d2admin/user/load', null, { root: true })
|
||||
// DB -> store 加载主题
|
||||
this.commit('d2admin/theme/load')
|
||||
await dispatch('d2admin/theme/load', null, { root: true })
|
||||
// DB -> store 加载页面过渡效果设置
|
||||
this.commit('d2admin/transition/load')
|
||||
await dispatch('d2admin/transition/load', null, { root: true })
|
||||
// DB -> store 持久化数据加载上次退出时的多页列表
|
||||
this.commit('d2admin/page/openedLoad')
|
||||
// DB -> store 持久化数据加载这个用户之前设置的侧边栏折叠状态
|
||||
this.commit('d2admin/menu/asideCollapseLoad')
|
||||
await dispatch('d2admin/page/openedLoad', null, { root: true })
|
||||
// DB -> store 持久化数据加载侧边栏折叠状态
|
||||
await dispatch('d2admin/menu/asideCollapseLoad', null, { root: true })
|
||||
// DB -> store 持久化数据加载全局尺寸
|
||||
await dispatch('d2admin/size/load', null, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,31 +6,42 @@ export default {
|
||||
// 全屏激活
|
||||
active: false
|
||||
},
|
||||
mutations: {
|
||||
actions: {
|
||||
/**
|
||||
* @description 初始化监听
|
||||
*/
|
||||
listen () {
|
||||
listen ({ commit }) {
|
||||
return new Promise(resolve => {
|
||||
if (screenfull.enabled) {
|
||||
screenfull.on('change', () => {
|
||||
console.log('1')
|
||||
if (!screenfull.isFullscreen) {
|
||||
this.commit('d2admin/fullscreen/set', false)
|
||||
commit('set', false)
|
||||
}
|
||||
})
|
||||
}
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 切换全屏
|
||||
*/
|
||||
toggle () {
|
||||
toggle ({ commit }) {
|
||||
return new Promise(resolve => {
|
||||
if (screenfull.isFullscreen) {
|
||||
screenfull.exit()
|
||||
this.commit('d2admin/fullscreen/set', false)
|
||||
commit('set', false)
|
||||
} else {
|
||||
screenfull.request()
|
||||
this.commit('d2admin/fullscreen/set', true)
|
||||
commit('set', true)
|
||||
}
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
/**
|
||||
* @description 设置 store 里的全屏状态
|
||||
* @param {Object} state vuex state
|
||||
|
||||
@@ -24,16 +24,6 @@ export default {
|
||||
return state.list.filter(l => l.type === 'error').length
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
/**
|
||||
* @description 清空日志
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
clean (state) {
|
||||
// store 赋值
|
||||
state.list = []
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
/**
|
||||
* @description 添加一个日志
|
||||
@@ -70,5 +60,15 @@ export default {
|
||||
info: toString(info)
|
||||
}))
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
/**
|
||||
* @description 清空日志
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
clean (state) {
|
||||
// store 赋值
|
||||
state.list = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,64 @@ export default {
|
||||
// 侧边栏收缩
|
||||
asideCollapse: setting.menu.asideCollapse
|
||||
},
|
||||
actions: {
|
||||
/**
|
||||
* 设置侧边栏展开或者收缩
|
||||
* @param {Object} state vuex state
|
||||
* @param {Boolean} collapse is collapse
|
||||
*/
|
||||
asideCollapseSet ({ state, dispatch }, collapse) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
state.asideCollapse = collapse
|
||||
// 持久化
|
||||
await dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'menu.asideCollapse',
|
||||
value: state.asideCollapse,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 切换侧边栏展开和收缩
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
asideCollapseToggle ({ state, dispatch }) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
state.asideCollapse = !state.asideCollapse
|
||||
// 持久化
|
||||
await dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'menu.asideCollapse',
|
||||
value: state.asideCollapse,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 从持久化数据读取侧边栏展开或者收缩
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
asideCollapseLoad ({ state, dispatch }) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
state.asideCollapse = await dispatch('d2admin/db/get', {
|
||||
dbName: 'sys',
|
||||
path: 'menu.asideCollapse',
|
||||
defaultValue: setting.menu.asideCollapse,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
/**
|
||||
* @description 设置顶栏菜单
|
||||
@@ -29,50 +87,6 @@ export default {
|
||||
asideSet (state, menu) {
|
||||
// store 赋值
|
||||
state.aside = menu
|
||||
},
|
||||
/**
|
||||
* 设置侧边栏展开或者收缩
|
||||
* @param {Object} state vuex state
|
||||
* @param {Boolean} collapse is collapse
|
||||
*/
|
||||
asideCollapseSet (state, collapse) {
|
||||
// store 赋值
|
||||
state.asideCollapse = collapse
|
||||
// 持久化
|
||||
this.dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'menu.asideCollapse',
|
||||
value: state.asideCollapse,
|
||||
user: true
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 切换侧边栏展开和收缩
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
asideCollapseToggle (state) {
|
||||
// store 赋值
|
||||
state.asideCollapse = !state.asideCollapse
|
||||
// 持久化
|
||||
this.dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'menu.asideCollapse',
|
||||
value: state.asideCollapse,
|
||||
user: true
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 从持久化数据读取侧边栏展开或者收缩
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
async asideCollapseLoad (state) {
|
||||
// store 赋值
|
||||
state.asideCollapse = await this.dispatch('d2admin/db/get', {
|
||||
dbName: 'sys',
|
||||
path: 'menu.asideCollapse',
|
||||
defaultValue: setting.menu.asideCollapse,
|
||||
user: true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { remove, get } from 'lodash'
|
||||
|
||||
// 设置文件
|
||||
import setting from '@/setting.js'
|
||||
|
||||
@@ -9,110 +11,25 @@ export default {
|
||||
// 当前显示的多页面列表
|
||||
opened: setting.page.opened,
|
||||
// 当前页面
|
||||
current: ''
|
||||
},
|
||||
getters: {
|
||||
/**
|
||||
* @description 从当前所有打开的多标签页里返回需要缓存的页面 name
|
||||
* @param {*} state vuex state
|
||||
*/
|
||||
keepAlive (state) {
|
||||
return state.opened.filter(item => {
|
||||
if (item.meta) {
|
||||
if (item.meta.notCache) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}).map(e => e.name)
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
/**
|
||||
* @class current
|
||||
* @description 打开一个新的页面
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param { name, params, query } 路由信息
|
||||
*/
|
||||
open (state, { name, params, query }) {
|
||||
// 已经打开的页面
|
||||
let opened = state.opened
|
||||
// 判断此页面是否已经打开 并且记录位置
|
||||
let pageOpendIndex = 0
|
||||
const pageOpend = opened.find((page, index) => {
|
||||
const same = page.name === name
|
||||
pageOpendIndex = same ? index : pageOpendIndex
|
||||
return same
|
||||
})
|
||||
if (pageOpend) {
|
||||
// 页面以前打开过 但是新的页面可能 name 一样,参数不一样
|
||||
this.commit('d2admin/page/openedUpdate', {
|
||||
index: pageOpendIndex,
|
||||
params,
|
||||
query
|
||||
})
|
||||
} else {
|
||||
// 页面以前没有打开过
|
||||
let page = state.pool.find(t => t.name === name)
|
||||
if (page) {
|
||||
this.commit('d2admin/page/add', {
|
||||
tag: page,
|
||||
params,
|
||||
query
|
||||
})
|
||||
}
|
||||
}
|
||||
this.commit('d2admin/page/currentSet', name)
|
||||
},
|
||||
/**
|
||||
* @class current
|
||||
* @description 设置当前激活的页面 name
|
||||
* @param {Object} state vuex state
|
||||
* @param {String} name new name
|
||||
*/
|
||||
currentSet (state, name) {
|
||||
state.current = name
|
||||
},
|
||||
/**
|
||||
* @class opened
|
||||
* @description 更新页面列表上的某一项
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param { index, params, query } 路由信息
|
||||
*/
|
||||
openedUpdate (state, { index, params, query }) {
|
||||
// 更新页面列表某一项
|
||||
let page = state.opened[index]
|
||||
page.params = params || page.params
|
||||
page.query = query || page.query
|
||||
state.opened.splice(index, 1, page)
|
||||
// 持久化
|
||||
this.commit('d2admin/page/opend2db')
|
||||
},
|
||||
/**
|
||||
* 将 opened 属性赋值并持久化 在这之前请先确保已经更新了 state.opened
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
opend2db (state) {
|
||||
this.dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'page.opened',
|
||||
value: state.opened,
|
||||
user: true
|
||||
})
|
||||
current: '',
|
||||
// 需要缓存的页面 name
|
||||
keepAlive: []
|
||||
},
|
||||
actions: {
|
||||
/**
|
||||
* @class opened
|
||||
* @description 从持久化数据载入分页列表
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
async openedLoad (state) {
|
||||
openedLoad ({ state, commit, dispatch }) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
const value = await this.dispatch('d2admin/db/get', {
|
||||
const value = await dispatch('d2admin/db/get', {
|
||||
dbName: 'sys',
|
||||
path: 'page.opened',
|
||||
defaultValue: setting.page.opened,
|
||||
user: true
|
||||
})
|
||||
}, { root: true })
|
||||
// 在处理函数中进行数据优化 过滤掉现在已经失效的页签或者已经改变了信息的页签
|
||||
// 以 name 字段为准
|
||||
// 如果页面过多的话可能需要优化算法
|
||||
@@ -133,6 +50,49 @@ export default {
|
||||
// 新的数据中一般不会携带 params 和 query, 所以旧的参数会留存
|
||||
return Object.assign({}, opened, find)
|
||||
}).filter((opened, index) => valid[index] === 1)
|
||||
// 根据 opened 数据生成缓存设置
|
||||
commit('keepAliveRefresh')
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 将 opened 属性赋值并持久化 在这之前请先确保已经更新了 state.opened
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
opend2db ({ state, dispatch }) {
|
||||
return new Promise(async resolve => {
|
||||
// 设置数据
|
||||
dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'page.opened',
|
||||
value: state.opened,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @class opened
|
||||
* @description 更新页面列表上的某一项
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param { index, params, query } 路由信息
|
||||
*/
|
||||
openedUpdate ({ state, commit, dispatch }, { index, params, query }) {
|
||||
return new Promise(async resolve => {
|
||||
// 更新页面列表某一项
|
||||
let page = state.opened[index]
|
||||
page.params = params || page.params
|
||||
page.query = query || page.query
|
||||
state.opened.splice(index, 1, page)
|
||||
// 增加缓存设置
|
||||
commit('keepAlivePush', page.name)
|
||||
// 持久化
|
||||
await dispatch('opend2db')
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @class opened
|
||||
@@ -140,15 +100,63 @@ export default {
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param new tag info
|
||||
*/
|
||||
add (state, { tag, params, query }) {
|
||||
add ({ state, commit, dispatch }, { tag, params, query }) {
|
||||
return new Promise(async resolve => {
|
||||
// 设置新的 tag 在新打开一个以前没打开过的页面时使用
|
||||
let newTag = tag
|
||||
newTag.params = params || newTag.params
|
||||
newTag.query = query || newTag.query
|
||||
// 添加进当前显示的页面数组
|
||||
state.opened.push(newTag)
|
||||
// 如果这个页面需要缓存 将其添加到缓存设置
|
||||
if (get(newTag, 'meta.requiresAuth', false)) {
|
||||
commit('keepAlivePush', tag.name)
|
||||
}
|
||||
// 持久化
|
||||
this.commit('d2admin/page/opend2db')
|
||||
await dispatch('opend2db')
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @class current
|
||||
* @description 打开一个新的页面
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param { name, params, query } 路由信息
|
||||
*/
|
||||
open ({ state, commit, dispatch }, { name, params, query }) {
|
||||
return new Promise(async resolve => {
|
||||
// 已经打开的页面
|
||||
let opened = state.opened
|
||||
// 判断此页面是否已经打开 并且记录位置
|
||||
let pageOpendIndex = 0
|
||||
const pageOpend = opened.find((page, index) => {
|
||||
const same = page.name === name
|
||||
pageOpendIndex = same ? index : pageOpendIndex
|
||||
return same
|
||||
})
|
||||
if (pageOpend) {
|
||||
// 页面以前打开过 但是新的页面可能 name 一样,参数不一样
|
||||
await dispatch('openedUpdate', {
|
||||
index: pageOpendIndex,
|
||||
params,
|
||||
query
|
||||
})
|
||||
} else {
|
||||
// 页面以前没有打开过
|
||||
let page = state.pool.find(t => t.name === name)
|
||||
if (page) {
|
||||
await dispatch('add', {
|
||||
tag: page,
|
||||
params,
|
||||
query
|
||||
})
|
||||
}
|
||||
}
|
||||
commit('currentSet', name)
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @class opened
|
||||
@@ -156,7 +164,8 @@ export default {
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param { tagName: 要关闭的标签名字, vm: vue }
|
||||
*/
|
||||
close (state, { tagName, vm }) {
|
||||
close ({ state, commit, dispatch }, { tagName, vm }) {
|
||||
return new Promise(async resolve => {
|
||||
// 下个新的页面
|
||||
let newPage = state.opened[0]
|
||||
const isCurrent = state.current === tagName
|
||||
@@ -178,10 +187,13 @@ export default {
|
||||
// 找到这个页面在已经打开的数据里是第几个
|
||||
const index = state.opened.findIndex(page => page.name === tagName)
|
||||
if (index >= 0) {
|
||||
// 更新数据 删除关闭的页面
|
||||
state.opened.splice(index, 1)
|
||||
// 如果这个页面是缓存的页面 将其在缓存设置中删除
|
||||
commit('keepAliveRemove', tagName)
|
||||
}
|
||||
// 持久化
|
||||
this.commit('d2admin/page/opend2db')
|
||||
await dispatch('opend2db')
|
||||
// 最后需要判断是否需要跳到首页
|
||||
if (isCurrent) {
|
||||
const { name = '', params = {}, query = {} } = newPage
|
||||
@@ -192,6 +204,9 @@ export default {
|
||||
}
|
||||
vm.$router.push(routerObj)
|
||||
}
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @class opened
|
||||
@@ -199,7 +214,8 @@ export default {
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param { pageSelect: 当前选中的tagName, vm: vue }
|
||||
*/
|
||||
closeLeft (state, { pageSelect, vm } = {}) {
|
||||
closeLeft ({ state, commit, dispatch }, { pageSelect, vm } = {}) {
|
||||
return new Promise(async resolve => {
|
||||
const pageAim = pageSelect || state.current
|
||||
let currentIndex = 0
|
||||
state.opened.forEach((page, index) => {
|
||||
@@ -208,7 +224,8 @@ export default {
|
||||
}
|
||||
})
|
||||
if (currentIndex > 0) {
|
||||
state.opened.splice(1, currentIndex - 1)
|
||||
// 删除打开的页面 并在缓存设置中删除
|
||||
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name))
|
||||
}
|
||||
state.current = pageAim
|
||||
if (vm && vm.$route.name !== pageAim) {
|
||||
@@ -217,7 +234,10 @@ export default {
|
||||
})
|
||||
}
|
||||
// 持久化
|
||||
this.commit('d2admin/page/opend2db')
|
||||
await dispatch('opend2db')
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @class opened
|
||||
@@ -225,7 +245,8 @@ export default {
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param { pageSelect: 当前选中的tagName, vm: vue }
|
||||
*/
|
||||
closeRight (state, { pageSelect, vm } = {}) {
|
||||
closeRight ({ state, commit, dispatch }, { pageSelect, vm } = {}) {
|
||||
return new Promise(async resolve => {
|
||||
const pageAim = pageSelect || state.current
|
||||
let currentIndex = 0
|
||||
state.opened.forEach((page, index) => {
|
||||
@@ -233,7 +254,9 @@ export default {
|
||||
currentIndex = index
|
||||
}
|
||||
})
|
||||
state.opened.splice(currentIndex + 1)
|
||||
// 删除打开的页面 并在缓存设置中删除
|
||||
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name))
|
||||
// 设置当前的页面
|
||||
state.current = pageAim
|
||||
if (vm && vm.$route.name !== pageAim) {
|
||||
vm.$router.push({
|
||||
@@ -241,7 +264,10 @@ export default {
|
||||
})
|
||||
}
|
||||
// 持久化
|
||||
this.commit('d2admin/page/opend2db')
|
||||
await dispatch('opend2db')
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @class opened
|
||||
@@ -249,7 +275,8 @@ export default {
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param { pageSelect: 当前选中的tagName, vm: vue }
|
||||
*/
|
||||
closeOther (state, { pageSelect, vm } = {}) {
|
||||
closeOther ({ state, commit, dispatch }, { pageSelect, vm } = {}) {
|
||||
return new Promise(async resolve => {
|
||||
const pageAim = pageSelect || state.current
|
||||
let currentIndex = 0
|
||||
state.opened.forEach((page, index) => {
|
||||
@@ -257,12 +284,14 @@ export default {
|
||||
currentIndex = index
|
||||
}
|
||||
})
|
||||
// 删除打开的页面数据 并更新缓存设置
|
||||
if (currentIndex === 0) {
|
||||
state.opened.splice(1)
|
||||
state.opened.splice(1).forEach(({ name }) => commit('keepAliveRemove', name))
|
||||
} else {
|
||||
state.opened.splice(currentIndex + 1)
|
||||
state.opened.splice(1, currentIndex - 1)
|
||||
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name))
|
||||
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name))
|
||||
}
|
||||
// 设置新的页面
|
||||
state.current = pageAim
|
||||
if (vm && vm.$route.name !== pageAim) {
|
||||
vm.$router.push({
|
||||
@@ -270,7 +299,10 @@ export default {
|
||||
})
|
||||
}
|
||||
// 持久化
|
||||
this.commit('d2admin/page/opend2db')
|
||||
await dispatch('opend2db')
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @class opened
|
||||
@@ -278,16 +310,74 @@ export default {
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} vm vue
|
||||
*/
|
||||
closeAll (state, vm) {
|
||||
state.opened.splice(1)
|
||||
closeAll ({ state, commit, dispatch }, vm) {
|
||||
return new Promise(async resolve => {
|
||||
// 删除打开的页面 并在缓存设置中删除
|
||||
state.opened.splice(1).forEach(({ name }) => commit('keepAliveRemove', name))
|
||||
// 持久化
|
||||
this.commit('d2admin/page/opend2db')
|
||||
await dispatch('opend2db')
|
||||
// 关闭所有的标签页后需要判断一次现在是不是在首页
|
||||
if (vm.$route.name !== 'index') {
|
||||
vm.$router.push({
|
||||
name: 'index'
|
||||
})
|
||||
}
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
/**
|
||||
* @class keepAlive
|
||||
* @description 从已经打开的页面记录中更新需要缓存的页面记录
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
keepAliveRefresh (state) {
|
||||
state.keepAlive = state.opened.filter(item => {
|
||||
if (item.meta) {
|
||||
if (item.meta.notCache) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}).map(e => e.name)
|
||||
},
|
||||
/**
|
||||
* @description 删除一个页面的缓存设置
|
||||
* @param {Object} state vuex state
|
||||
* @param {String} name name
|
||||
*/
|
||||
keepAliveRemove (state, name) {
|
||||
const list = [ ...state.keepAlive ]
|
||||
remove(list, item => item === name)
|
||||
state.keepAlive = list
|
||||
},
|
||||
/**
|
||||
* @description 增加一个页面的缓存设置
|
||||
* @param {Object} state vuex state
|
||||
* @param {String} name name
|
||||
*/
|
||||
keepAlivePush (state, name) {
|
||||
const keep = [ ...state.keepAlive ]
|
||||
keep.push(name)
|
||||
state.keepAlive = Array.from(new Set(keep))
|
||||
},
|
||||
/**
|
||||
* @description 清空页面缓存设置
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
keepAliveClean (state) {
|
||||
state.keepAlive = []
|
||||
},
|
||||
/**
|
||||
* @class current
|
||||
* @description 设置当前激活的页面 name
|
||||
* @param {Object} state vuex state
|
||||
* @param {String} name new name
|
||||
*/
|
||||
currentSet (state, name) {
|
||||
state.current = name
|
||||
},
|
||||
/**
|
||||
* @class pool
|
||||
@@ -302,9 +392,11 @@ export default {
|
||||
if (route.children) {
|
||||
push(route.children)
|
||||
} else {
|
||||
if (!route.hidden) {
|
||||
const { meta, name, path } = route
|
||||
pool.push({ meta, name, path })
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
push(routes)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
// 尺寸
|
||||
value: '' // medium small mini
|
||||
},
|
||||
actions: {
|
||||
/**
|
||||
* @description 设置尺寸
|
||||
* @param {Object} state vuex state
|
||||
* @param {String} size 尺寸
|
||||
*/
|
||||
set ({ state, dispatch }, size) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
state.value = size
|
||||
// 持久化
|
||||
await dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'size.value',
|
||||
value: state.value,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 从持久化数据读取尺寸设置
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
load ({ state, dispatch }) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
state.value = await dispatch('d2admin/db/get', {
|
||||
dbName: 'sys',
|
||||
path: 'size.value',
|
||||
defaultValue: 'default',
|
||||
user: true
|
||||
}, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,40 +18,50 @@ export default {
|
||||
return state.list.find(theme => theme.name === state.activeName)
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
actions: {
|
||||
/**
|
||||
* @description 激活一个主题
|
||||
* @param {Object} state vuex state
|
||||
* @param {String} themeValue 需要激活的主题名称
|
||||
*/
|
||||
set (state, themeName) {
|
||||
set ({ state, commit, dispatch }, themeName) {
|
||||
return new Promise(async resolve => {
|
||||
// 检查这个主题在主题列表里是否存在
|
||||
state.activeName = state.list.find(e => e.name === themeName) ? themeName : state.list[0].name
|
||||
// 将 vuex 中的主题应用到 dom
|
||||
this.commit('d2admin/theme/dom')
|
||||
commit('dom')
|
||||
// 持久化
|
||||
this.dispatch('d2admin/db/set', {
|
||||
await dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'theme.activeName',
|
||||
value: state.activeName,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 从持久化数据加载主题设置
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
async load (state) {
|
||||
load ({ state, commit, dispatch }) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
state.activeName = await this.dispatch('d2admin/db/get', {
|
||||
state.activeName = await dispatch('d2admin/db/get', {
|
||||
dbName: 'sys',
|
||||
path: 'theme.activeName',
|
||||
defaultValue: state.list[0].name,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// 将 vuex 中的主题应用到 dom
|
||||
commit('dom')
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
// 更新到页面
|
||||
this.commit('d2admin/theme/dom')
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
/**
|
||||
* @description 将 vuex 中的主题应用到 dom
|
||||
* @param {Object} state vuex state
|
||||
|
||||
@@ -7,34 +7,42 @@ export default {
|
||||
// 是否开启页面过度动画
|
||||
active: setting.transition.active
|
||||
},
|
||||
mutations: {
|
||||
actions: {
|
||||
/**
|
||||
* @description 设置开启状态
|
||||
* @param {Object} state vuex state
|
||||
* @param {Boolean} active 新的状态
|
||||
*/
|
||||
set (state, active) {
|
||||
set ({ state, dispatch }, active) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
state.active = active
|
||||
// 持久化
|
||||
this.dispatch('d2admin/db/set', {
|
||||
await dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'transition.active',
|
||||
value: state.active,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 从数据库读取页面过渡动画设置
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
async load (state) {
|
||||
load ({ state, dispatch }) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
state.active = await this.dispatch('d2admin/db/get', {
|
||||
state.active = await dispatch('d2admin/db/get', {
|
||||
dbName: 'sys',
|
||||
path: 'transition.active',
|
||||
defaultValue: setting.transition.active,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,34 +7,42 @@ export default {
|
||||
// 用户信息
|
||||
info: setting.user.info
|
||||
},
|
||||
mutations: {
|
||||
actions: {
|
||||
/**
|
||||
* @description 设置用户数据
|
||||
* @param {Object} state vuex state
|
||||
* @param {*} info info
|
||||
*/
|
||||
set (state, info) {
|
||||
set ({ state, dispatch }, info) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
state.info = info
|
||||
// 持久化
|
||||
this.dispatch('d2admin/db/set', {
|
||||
await dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'user.info',
|
||||
value: info,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 从数据库取用户数据
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
async load (state) {
|
||||
load ({ state, dispatch }) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
state.info = await this.dispatch('d2admin/db/get', {
|
||||
state.info = await dispatch('d2admin/db/get', {
|
||||
dbName: 'sys',
|
||||
path: 'user.info',
|
||||
defaultValue: setting.user.info,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -6,7 +6,9 @@ function resolve (dir) {
|
||||
}
|
||||
|
||||
// 基础路径 注意发布之前要先修改这里
|
||||
const baseUrl = '/d2-admin-start-kit/'
|
||||
let baseUrl = '/'
|
||||
// 演示项目自动构建使用
|
||||
if (process.env.VUE_APP_TRAVIS === 'TRUE') baseUrl = '/d2-admin-start-kit/'
|
||||
|
||||
module.exports = {
|
||||
baseUrl: baseUrl, // 根据你的实际情况更改这里
|
||||
@@ -14,9 +16,11 @@ module.exports = {
|
||||
devServer: {
|
||||
publicPath: baseUrl // 和 baseUrl 保持一致
|
||||
},
|
||||
// webpack 设置
|
||||
// 默认设置: https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-service/lib/config/base.js
|
||||
chainWebpack: config => {
|
||||
// 解决 cli3 热更新失效 https://github.com/vuejs/vue-cli/issues/1559
|
||||
config.resolve
|
||||
.symlinks(true)
|
||||
// markdown
|
||||
config.module
|
||||
.rule('md')
|
||||
|
||||
Reference in New Issue
Block a user