feat: 1.9.1

This commit is contained in:
FairyEver
2020-04-24 14:19:14 +08:00
parent 24e676cc09
commit df79ed41ff
14 changed files with 224 additions and 190 deletions
+2
View File
@@ -7,6 +7,8 @@
![Deploy preview](https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20preview/badge.svg)
[![Netlify Status](https://api.netlify.com/api/v1/badges/08ff8c93-f0a8-497a-a081-440b31fb3aa4/deploy-status)](https://app.netlify.com/sites/d2-admin-start-kit/deploys)
The following access addresses are built and deployed by the latest master branch code at the same time. The access effect is completely consistent. Please select the appropriate access link according to your own network situation.
| server | link | server |
| --- | --- | --- |
| d2.pub | [d2.pub/d2-admin-start-kit/preview](https://d2.pub/d2-admin-start-kit/preview) | China server |
+2
View File
@@ -7,6 +7,8 @@
![Deploy preview](https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20preview/badge.svg)
[![Netlify Status](https://api.netlify.com/api/v1/badges/08ff8c93-f0a8-497a-a081-440b31fb3aa4/deploy-status)](https://app.netlify.com/sites/d2-admin-start-kit/deploys)
下列访问地址均由最新的 master 分支代码同时构建部署,访问效果完全一致,请根据自身网络情况选择合适的访问链接。
| 位置 | 链接 | 部署位置 |
| --- | --- | --- |
| d2.pub | [preview](https://d2.pub/d2-admin-start-kit/preview) | 中国服务器 |
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "d2-admin-start-kit",
"version": "1.8.4",
"version": "1.9.1",
"scripts": {
"serve": "vue-cli-service serve --open",
"start": "npm run serve",
+1 -1
View File
@@ -1,6 +1,6 @@
import request from '@/plugin/axios'
export function AccountLogin (data) {
export function accountLogin (data) {
return request({
url: '/login',
method: 'post',
+12
View File
@@ -17,3 +17,15 @@
.el-tabs__item:focus.is-active.is-focus:not(:active) {
box-shadow: none !important;
}
// 修复IE宽度不能撑满
.el-table__body,
.el-table__header {
width: 100% !important;
}
// Chrome下表格头部错位修复
.el-table th.gutter,
.el-table colgroup.gutter {
display: table-cell !important;
}
+6 -2
View File
@@ -74,13 +74,15 @@
}
.d2-theme-container {
.d2-theme-container-aside {
transition: width .3s;
position: relative;
.d2-layout-header-aside-menu-side {
@extend %full;
overflow: hidden;
}
}
.d2-theme-container-transition {
transition: width .3s;
}
.d2-theme-container-main {
padding: 0px;
position: relative;
@@ -116,13 +118,15 @@
.d2-theme-header {
// logo区域
.logo-group {
transition: width .3s;
float: left;
text-align: center;
img {
height: 60px;
}
}
.logo-transition {
transition: width .3s;
}
// 折叠侧边栏切换按钮
.toggle-aside-btn {
float: left;
@@ -1,32 +1,32 @@
// 创建 el-menu-item
export function elMenuItem (createElement, menu) {
return createElement('el-menu-item', { key: menu.path, props: { index: menu.path } }, [
export function elMenuItem (h, menu) {
return h('el-menu-item', { key: menu.path, props: { index: menu.path } }, [
...menu.icon ? [
createElement('i', { attrs: { class: `fa fa-${menu.icon}` } })
h('i', { attrs: { class: `fa fa-${menu.icon}` } })
] : [],
...menu.icon === undefined & !menu.iconSvg ? [
createElement('i', { attrs: { class: 'fa fa-file-o' } })
h('i', { attrs: { class: 'fa fa-file-o' } })
] : [],
...menu.iconSvg ? [
createElement('d2-icon-svg', { props: { name: menu.iconSvg } })
h('d2-icon-svg', { props: { name: menu.iconSvg } })
] : [],
createElement('span', { slot: 'title' }, menu.title || '未命名菜单')
h('span', { slot: 'title' }, menu.title || '未命名菜单')
])
}
// 创建 el-submenu
export function elSubmenu (createElement, menu) {
return createElement('el-submenu', { key: menu.path, props: { index: menu.path } }, [
export function elSubmenu (h, menu) {
return h('el-submenu', { key: menu.path, props: { index: menu.path } }, [
...menu.icon ? [
createElement('i', { slot: 'title', attrs: { class: `fa fa-${menu.icon}` } })
h('i', { slot: 'title', attrs: { class: `fa fa-${menu.icon}` } })
] : [],
...menu.icon === undefined & !menu.iconSvg ? [
createElement('i', { slot: 'title', attrs: { class: 'fa fa-folder-o' } })
h('i', { slot: 'title', attrs: { class: 'fa fa-folder-o' } })
] : [],
...menu.iconSvg ? [
createElement('d2-icon-svg', { slot: 'title', props: { name: menu.iconSvg } })
h('d2-icon-svg', { slot: 'title', props: { name: menu.iconSvg } })
] : [],
createElement('span', { slot: 'title' }, menu.title || '未命名菜单'),
...menu.children.map((child, childIndex) => (child.children === undefined ? elMenuItem : elSubmenu).call(this, createElement, child))
h('span', { slot: 'title' }, menu.title || '未命名菜单'),
...menu.children.map((child, childIndex) => (child.children === undefined ? elMenuItem : elSubmenu).call(this, h, child))
])
}
@@ -8,39 +8,39 @@ export default {
mixins: [
menuMixin
],
render (createElement) {
return createElement('div', {
render (h) {
return h('div', {
attrs: { flex: 'cross:center' },
class: { 'd2-theme-header-menu': true, 'is-scrollable': this.isScroll },
ref: 'page'
}, [
createElement('div', {
h('div', {
attrs: { class: 'd2-theme-header-menu__content', flex: '', 'flex-box': '1' },
ref: 'content'
}, [
createElement('div', {
h('div', {
attrs: { class: 'd2-theme-header-menu__scroll', 'flex-box': '0' },
style: { transform: `translateX(${this.currentTranslateX}px)` },
ref: 'scroll'
}, [
createElement('el-menu', {
h('el-menu', {
props: { mode: 'horizontal', defaultActive: this.active },
on: { select: this.handleMenuSelect }
}, this.header.map(menu => (menu.children === undefined ? elMenuItem : elSubmenu).call(this, createElement, menu)))
}, this.header.map(menu => (menu.children === undefined ? elMenuItem : elSubmenu).call(this, h, menu)))
])
]),
...this.isScroll ? [
createElement('div', {
h('div', {
attrs: { class: 'd2-theme-header-menu__prev', flex: 'main:center cross:center', 'flex-box': '0' },
on: { click: () => this.scroll('left') }
}, [
createElement('i', { attrs: { class: 'el-icon-arrow-left' } })
h('i', { attrs: { class: 'el-icon-arrow-left' } })
]),
createElement('div', {
h('div', {
attrs: { class: 'd2-theme-header-menu__next', flex: 'main:center cross:center', 'flex-box': '0' },
on: { click: () => this.scroll('right') }
}, [
createElement('i', { attrs: { class: 'el-icon-arrow-right' } })
h('i', { attrs: { class: 'el-icon-arrow-right' } })
])
] : []
])
@@ -8,17 +8,17 @@ export default {
mixins: [
menuMixin
],
render (createElement) {
return createElement('div', { attrs: { class: 'd2-layout-header-aside-menu-side' } }, [
createElement('el-menu', {
props: { collapse: this.asideCollapse, uniqueOpened: true, defaultActive: this.$route.fullPath },
render (h) {
return h('div', { attrs: { class: 'd2-layout-header-aside-menu-side' } }, [
h('el-menu', {
props: { collapse: this.asideCollapse, collapseTransition: this.asideTransition, uniqueOpened: true, defaultActive: this.$route.fullPath },
ref: 'menu',
on: { select: this.handleMenuSelect }
}, this.aside.map(menu => (menu.children === undefined ? elMenuItem : elSubmenu).call(this, createElement, menu))),
}, this.aside.map(menu => (menu.children === undefined ? elMenuItem : elSubmenu).call(this, h, menu))),
...this.aside.length === 0 && !this.asideCollapse ? [
createElement('div', { attrs: { class: 'd2-layout-header-aside-menu-empty', flex: 'dir:top main:center cross:center' } }, [
createElement('d2-icon', { props: { name: 'inbox' } }),
createElement('span', {}, '没有侧栏菜单')
h('div', { attrs: { class: 'd2-layout-header-aside-menu-empty', flex: 'dir:top main:center cross:center' } }, [
h('d2-icon', { props: { name: 'inbox' } }),
h('span', {}, '没有侧栏菜单')
])
] : []
])
@@ -32,7 +32,8 @@ export default {
computed: {
...mapState('d2admin/menu', [
'aside',
'asideCollapse'
'asideCollapse',
'asideTransition'
])
},
watch: {
+15 -3
View File
@@ -6,7 +6,11 @@
<div class="d2-layout-header-aside-content" flex="dir:top">
<!-- 顶栏 -->
<div class="d2-theme-header" :style="{ opacity: this.searchActive ? 0.5 : 1 }" flex-box="0" flex>
<router-link to="/index" class="logo-group" :style="{width: asideCollapse ? asideWidthCollapse : asideWidth}" flex-box="0">
<router-link
to="/index"
:class="{'logo-group': true, 'logo-transition': asideTransition}"
: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`">
</router-link>
@@ -30,7 +34,14 @@
<!-- 下面 主体 -->
<div class="d2-theme-container" flex-box="1" flex>
<!-- 主体 侧边栏 -->
<div flex-box="0" ref="aside" class="d2-theme-container-aside" :style="{ width: asideCollapse ? asideWidthCollapse : asideWidth, opacity: this.searchActive ? 0.5 : 1 }">
<div
flex-box="0"
ref="aside"
:class="{'d2-theme-container-aside': true, 'd2-theme-container-transition': asideTransition}"
:style="{
width: asideCollapse ? asideWidthCollapse : asideWidth,
opacity: this.searchActive ? 0.5 : 1
}">
<d2-menu-side/>
</div>
<!-- 主体 -->
@@ -109,7 +120,8 @@ export default {
keepAlive: state => state.page.keepAlive,
grayActive: state => state.gray.active,
transitionActive: state => state.transition.active,
asideCollapse: state => state.menu.asideCollapse
asideCollapse: state => state.menu.asideCollapse,
asideTransition: state => state.menu.asideTransition
}),
...mapGetters('d2admin', {
themeActiveSetting: 'theme/activeSetting'
+3 -2
View File
@@ -7,9 +7,10 @@ export default {
close: 'esc'
}
},
// 侧边栏默认折叠状态
// 侧边栏默认配置
menu: {
asideCollapse: false
asideCollapse: false,
asideTransition: true
},
// 在读取持久化数据失败时默认页面
page: {
+32 -58
View File
@@ -1,7 +1,7 @@
import { Message, MessageBox } from 'element-ui'
import util from '@/libs/util.js'
import router from '@/router'
import { AccountLogin } from '@api/sys.login'
import { accountLogin } from '@api/sys.login'
export default {
namespaced: true,
@@ -13,38 +13,22 @@ export default {
* @param {Object} payload password {String} 密码
* @param {Object} payload route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式
*/
login ({ dispatch }, {
async login ({ dispatch }, {
username = '',
password = ''
} = {}) {
return new Promise((resolve, reject) => {
// 开始请求登录接口
AccountLogin({
username,
password
})
.then(async res => {
// 设置 cookie 一定要存 uuid 和 token 两个 cookie
// 整个系统依赖这两个数据进行校验和存储
// uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复
// token 代表用户当前登录状态 建议在网络请求中携带 token
// 如有必要 token 需要定时更新,默认保存一天
util.cookies.set('uuid', res.uuid)
util.cookies.set('token', res.token)
// 设置 vuex 用户信息
await dispatch('d2admin/user/set', {
name: res.name
}, { root: true })
// 用户登录后从持久化数据加载一系列的设置
await dispatch('load')
// 结束
resolve()
})
.catch(err => {
console.log('err: ', err)
reject(err)
})
})
const res = await accountLogin({ username, password })
// 设置 cookie 一定要存 uuid 和 token 两个 cookie
// 整个系统依赖这两个数据进行校验和存储
// uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复
// token 代表用户当前登录状态 建议在网络请求中携带 token
// 如有必要 token 需要定时更新,默认保存一天
util.cookies.set('uuid', res.uuid)
util.cookies.set('token', res.token)
// 设置 vuex 用户信息
await dispatch('d2admin/user/set', { name: res.name }, { root: true })
// 用户登录后从持久化数据加载一系列的设置
await dispatch('load')
},
/**
* @description 注销用户并返回登录页面
@@ -62,25 +46,19 @@ export default {
// 清空 vuex 用户信息
await dispatch('d2admin/user/set', {}, { root: true })
// 跳转路由
router.push({
name: 'login'
})
router.push({ name: 'login' })
}
// 判断是否需要确认
if (confirm) {
commit('d2admin/gray/set', true, { root: true })
MessageBox.confirm('确定要注销当前用户吗', '注销用户', {
type: 'warning'
})
MessageBox.confirm('确定要注销当前用户吗', '注销用户', { type: 'warning' })
.then(() => {
commit('d2admin/gray/set', false, { root: true })
logout()
})
.catch(() => {
commit('d2admin/gray/set', false, { root: true })
Message({
message: '取消注销操作'
})
Message({ message: '取消注销操作' })
})
} else {
logout()
@@ -90,25 +68,21 @@ export default {
* @description 用户登录后从持久化数据加载一系列的设置
* @param {Object} context
*/
load ({ dispatch }) {
return new Promise(async resolve => {
// DB -> store 加载用户名
await dispatch('d2admin/user/load', null, { root: true })
// DB -> store 加载主题
await dispatch('d2admin/theme/load', null, { root: true })
// DB -> store 加载页面过渡效果设置
await dispatch('d2admin/transition/load', null, { root: true })
// DB -> store 持久化数据加载上次退出时的多页列表
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 })
// DB -> store 持久化数据加载颜色设置
await dispatch('d2admin/color/load', null, { root: true })
// end
resolve()
})
async load ({ dispatch }) {
// 加载用户名
await dispatch('d2admin/user/load', null, { root: true })
// 加载主题
await dispatch('d2admin/theme/load', null, { root: true })
// 加载页面过渡效果设置
await dispatch('d2admin/transition/load', null, { root: true })
// 持久化数据加载上次退出时的多页列表
await dispatch('d2admin/page/openedLoad', null, { root: true })
// 持久化数据加载侧边栏配置
await dispatch('d2admin/menu/asideLoad', null, { root: true })
// 持久化数据加载全局尺寸
await dispatch('d2admin/size/load', null, { root: true })
// 持久化数据加载颜色设置
await dispatch('d2admin/color/load', null, { root: true })
}
}
}
+67 -60
View File
@@ -1,22 +1,6 @@
import { uniqueId } from 'lodash'
// 设置文件
import setting from '@/setting.js'
/**
* 给菜单数据补充上 path 字段
* https://github.com/d2-projects/d2-admin/issues/209
* @param {Array} menu 原始的菜单数据
*/
function supplementMenuPath (menu) {
return menu.map(e => ({
...e,
path: e.path || uniqueId('d2-menu-empty-'),
...e.children ? {
children: supplementMenuPath(e.children)
} : {}
}))
}
export default {
namespaced: true,
state: {
@@ -25,7 +9,9 @@ export default {
// 侧栏菜单
aside: [],
// 侧边栏收缩
asideCollapse: setting.menu.asideCollapse
asideCollapse: setting.menu.asideCollapse,
// 侧边栏折叠动画
asideTransition: setting.menu.asideTransition
},
actions: {
/**
@@ -33,56 +19,77 @@ export default {
* @param {Object} context
* @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()
})
async asideCollapseSet ({ state, dispatch }, collapse) {
// store 赋值
state.asideCollapse = collapse
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'menu.asideCollapse',
value: state.asideCollapse,
user: true
}, { root: true })
},
/**
* 切换侧边栏展开和收缩
* @param {Object} context
*/
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()
})
async asideCollapseToggle ({ state, dispatch }) {
// store 赋值
state.asideCollapse = !state.asideCollapse
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'menu.asideCollapse',
value: state.asideCollapse,
user: true
}, { root: true })
},
/**
* 从持久化数据读取侧边栏展开或者收缩
* 设置侧边栏折叠动画
* @param {Object} context
* @param {Boolean} transition is transition
*/
async asideTransitionSet ({ state, dispatch }, transition) {
// store 赋值
state.asideTransition = transition
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'menu.asideTransition',
value: state.asideTransition,
user: true
}, { root: true })
},
/**
* 切换侧边栏折叠动画
* @param {Object} context
*/
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()
})
async asideTransitionToggle ({ state, dispatch }) {
// store 赋值
state.asideTransition = !state.asideTransition
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'menu.asideTransition',
value: state.asideTransition,
user: true
}, { root: true })
},
/**
* 持久化数据加载侧边栏设置
* @param {Object} context
*/
async asideLoad ({ state, dispatch }) {
// store 赋值
const menu = await dispatch('d2admin/db/get', {
dbName: 'sys',
path: 'menu',
defaultValue: setting.menu,
user: true
}, { root: true })
state.asideCollapse = menu.asideCollapse !== undefined ? menu.asideCollapse : setting.menu.asideCollapse
state.asideTransition = menu.asideTransition !== undefined ? menu.asideTransition : setting.menu.asideTransition
}
},
mutations: {
@@ -93,7 +100,7 @@ export default {
*/
headerSet (state, menu) {
// store 赋值
state.header = supplementMenuPath(menu)
state.header = menu
},
/**
* @description 设置侧边栏菜单
@@ -102,7 +109,7 @@ export default {
*/
asideSet (state, menu) {
// store 赋值
state.aside = supplementMenuPath(menu)
state.aside = menu
}
}
}
+49 -30
View File
@@ -183,17 +183,16 @@ export default {
* @param {Object} payload { tagName: 要关闭的标签名字 }
*/
async close ({ state, commit, dispatch }, { tagName }) {
// 下个新的页面
let newPage = state.opened[0]
// 预定下个新页面
let newPage = {}
const isCurrent = state.current === tagName
// 如果关闭的页面就是当前显示的页面
if (isCurrent) {
// 去找一个新的页面
let len = state.opened.length
for (let i = 1; i < len; i++) {
for (let i = 0; i < len; i++) {
if (state.opened[i].fullPath === tagName) {
if (i < len - 1) newPage = state.opened[i + 1]
else newPage = state.opened[i - 1]
newPage = i < len - 1 ? state.opened[i + 1] : state.opened[i - 1]
break
}
}
@@ -208,15 +207,11 @@ export default {
}
// 持久化
await dispatch('opened2db')
// 最后需要判断是否需要跳到首页
// 决定最后停留的页面
if (isCurrent) {
const { name = '', params = {}, query = {} } = newPage
let routerObj = {
name,
params,
query
}
router.push(routerObj)
const { name = 'index', params = {}, query = {} } = newPage
let routerObj = { name, params, query }
await router.push(routerObj)
}
},
/**
@@ -233,12 +228,20 @@ export default {
})
if (currentIndex > 0) {
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name))
for (let i = state.opened.length - 1; i >= 0; i--) {
if (state.opened[i].name === 'index' || i >= currentIndex) {
continue
}
commit('keepAliveRemove', state.opened[i].name)
state.opened.splice(i, 1)
}
}
state.current = pageAim
if (router.app.$route.fullPath !== pageAim) router.push(pageAim)
// 持久化
await dispatch('opened2db')
// 设置当前的页面
state.current = pageAim
if (router.app.$route.fullPath !== pageAim) await router.push(pageAim)
},
/**
* @class opened
@@ -253,12 +256,19 @@ export default {
if (page.fullPath === pageAim) currentIndex = index
})
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name))
// 设置当前的页面
state.current = pageAim
if (router.app.$route.fullPath !== pageAim) router.push(pageAim)
for (let i = state.opened.length - 1; i >= 0; i--) {
if (state.opened[i].name === 'index' || currentIndex >= i) {
continue
}
commit('keepAliveRemove', state.opened[i].name)
state.opened.splice(i, 1)
}
// 持久化
await dispatch('opened2db')
// 设置当前的页面
state.current = pageAim
if (router.app.$route.fullPath !== pageAim) await router.push(pageAim)
},
/**
* @class opened
@@ -273,17 +283,19 @@ export default {
if (page.fullPath === pageAim) currentIndex = index
})
// 删除打开的页面数据 并更新缓存设置
if (currentIndex === 0) {
state.opened.splice(1).forEach(({ name }) => commit('keepAliveRemove', name))
} else {
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name))
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name))
for (let i = state.opened.length - 1; i >= 0; i--) {
if (state.opened[i].name === 'index' || currentIndex === i) {
continue
}
commit('keepAliveRemove', state.opened[i].name)
state.opened.splice(i, 1)
}
// 设置新的页面
state.current = pageAim
if (router.app.$route.fullPath !== pageAim) router.push(pageAim)
// 持久化
await dispatch('opened2db')
// 设置新的页面
state.current = pageAim
if (router.app.$route.fullPath !== pageAim) await router.push(pageAim)
},
/**
* @class opened
@@ -292,12 +304,19 @@ export default {
*/
async closeAll ({ state, commit, dispatch }) {
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(1).forEach(({ name }) => commit('keepAliveRemove', name))
for (let i = state.opened.length - 1; i >= 0; i--) {
if (state.opened[i].name === 'index') {
continue
}
commit('keepAliveRemove', state.opened[i].name)
state.opened.splice(i, 1)
}
// 持久化
await dispatch('opened2db')
// 关闭所有的标签页后需要判断一次现在是不是在首页
if (router.app.$route.name !== 'index') {
router.push({ name: 'index' })
await router.push({ name: 'index' })
}
}
},