Merge branch 'hotfix/12-16'
Former-commit-id: a24414bc5eb7e16004e918424d8c2fcf434779c1
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# No Mock 构建
|
||||
|
||||
# 指定构建模式
|
||||
NODE_ENV=production
|
||||
|
||||
# 标记当前是 No Mock 构建
|
||||
VUE_APP_BUILD_MODE=nomock
|
||||
Generated
+4589
-6055
File diff suppressed because it is too large
Load Diff
+6
-3
@@ -1,17 +1,19 @@
|
||||
{
|
||||
"name": "d2-admin",
|
||||
"version": "1.5.9",
|
||||
"version": "1.6.9",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve --open",
|
||||
"start": "npm run serve",
|
||||
"dev": "npm run serve",
|
||||
"build": "vue-cli-service build",
|
||||
"build:nomock": "vue-cli-service build --mode nomock",
|
||||
"build:travis": "vue-cli-service build --mode travis",
|
||||
"lint": "vue-cli-service lint --fix",
|
||||
"test:unit": "vue-cli-service test:unit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@d2-projects/vue-filters-date": "^1.0.2",
|
||||
"axios": "^0.17.1",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"better-scroll": "^1.12.1",
|
||||
@@ -21,11 +23,11 @@
|
||||
"fuse.js": "^3.2.1",
|
||||
"hotkeys-js": "^3.3.6",
|
||||
"js-cookie": "^2.2.0",
|
||||
"lodash": "^4.17.11",
|
||||
"lodash": "^4.17.10",
|
||||
"lowdb": "^1.0.0",
|
||||
"mockjs": "^1.0.1-beta3",
|
||||
"nprogress": "^0.2.0",
|
||||
"particles.js": "^2.0.0",
|
||||
"qs": "^6.6.0",
|
||||
"screenfull": "^3.3.2",
|
||||
"ua-parser-js": "^0.7.18",
|
||||
"vue": "^2.5.17",
|
||||
@@ -48,6 +50,7 @@
|
||||
"sass-loader": "^7.0.1",
|
||||
"svg-sprite-loader": "^3.8.0",
|
||||
"text-loader": "0.0.1",
|
||||
"uglifyjs-webpack-plugin": "^2.0.1",
|
||||
"vue-template-compiler": "^2.5.17"
|
||||
},
|
||||
"lint-staged": {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// 优化显示
|
||||
|
||||
html, body {
|
||||
margin: 0px;
|
||||
height: 100%;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// element 样式补丁
|
||||
|
||||
.el-card {
|
||||
&.is-always-shadow {
|
||||
box-shadow: 0 0 8px 0 rgba(232,237,250,.6), 0 2px 4px 0 rgba(232,237,250,.5);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
@import '~@/assets/style/public.scss';
|
||||
@import '~@/assets/style/theme/theme-base.scss';
|
||||
|
||||
@import '~@/assets/style/theme/d2/index.scss';
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div v-if="$slots.header" class="d2-container-card__header" ref="header">
|
||||
<slot name="header"/>
|
||||
</div>
|
||||
<div class="d2-container-card__body">
|
||||
<div class="d2-container-card__body" ref="body">
|
||||
<div class="d2-container-card__body-card">
|
||||
<slot/>
|
||||
</div>
|
||||
@@ -15,7 +15,19 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import scroll from './mixins/normal'
|
||||
export default {
|
||||
name: 'd2-container-card'
|
||||
name: 'd2-container-card',
|
||||
mixins: [
|
||||
scroll
|
||||
],
|
||||
mounted () {
|
||||
// 增加滚动事件监听
|
||||
this.addScrollListener()
|
||||
},
|
||||
beforeDestroy () {
|
||||
// 移除滚动事件监听
|
||||
this.removeScrollListener()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div v-if="$slots.header" class="d2-container-full__header" ref="header">
|
||||
<slot name="header"/>
|
||||
</div>
|
||||
<div class="d2-container-full__body">
|
||||
<div class="d2-container-full__body" ref="body">
|
||||
<slot/>
|
||||
</div>
|
||||
<div v-if="$slots.footer" class="d2-container-full__footer" ref="footer">
|
||||
@@ -13,7 +13,19 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import scroll from './mixins/normal'
|
||||
export default {
|
||||
name: 'd2-container-full'
|
||||
name: 'd2-container-full',
|
||||
mixins: [
|
||||
scroll
|
||||
],
|
||||
mounted () {
|
||||
// 增加滚动事件监听
|
||||
this.addScrollListener()
|
||||
},
|
||||
beforeDestroy () {
|
||||
// 移除滚动事件监听
|
||||
this.removeScrollListener()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div v-if="$slots.header" class="d2-container-ghost__header" ref="header">
|
||||
<slot name="header"/>
|
||||
</div>
|
||||
<div class="d2-container-ghost__body">
|
||||
<div class="d2-container-ghost__body" ref="body">
|
||||
<slot/>
|
||||
</div>
|
||||
<div v-if="$slots.footer" class="d2-container-ghost__footer" ref="footer">
|
||||
@@ -11,3 +11,21 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import scroll from './mixins/normal'
|
||||
export default {
|
||||
name: 'd2-container-ghost',
|
||||
mixins: [
|
||||
scroll
|
||||
],
|
||||
mounted () {
|
||||
// 增加滚动事件监听
|
||||
this.addScrollListener()
|
||||
},
|
||||
beforeDestroy () {
|
||||
// 移除滚动事件监听
|
||||
this.removeScrollListener()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div
|
||||
class="d2-source"
|
||||
:class="{ 'd2-source--active': isActive }"
|
||||
@click="handleClick">
|
||||
<d2-icon name="code"/> SourceCode
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
// 文件路径
|
||||
filename: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isActive: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// 一秒后显示按钮
|
||||
setTimeout(() => {
|
||||
this.isActive = true
|
||||
}, 500)
|
||||
},
|
||||
methods: {
|
||||
// 点击按钮的时候跳转到源代码
|
||||
handleClick () {
|
||||
const file = this.filename.split('?')[0]
|
||||
const url = file
|
||||
? `https://github.com/d2-projects/d2-admin-start-kit/blob/master/${file}`
|
||||
: 'https://github.com/d2-projects/d2-admin-start-kit'
|
||||
this.$open(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.d2-source {
|
||||
$borderRadius: 4px;
|
||||
$paddingLR: 15px;
|
||||
$paddingTB: 7px;
|
||||
$fontSize: 12px;
|
||||
$rightOuter: $paddingLR / 2;
|
||||
opacity: 0;
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
right: - $borderRadius - $rightOuter;
|
||||
bottom: 20px;
|
||||
font-size: $fontSize;
|
||||
line-height: $fontSize;
|
||||
font-weight: bold;
|
||||
border-radius: $borderRadius;
|
||||
padding: $paddingTB $paddingLR;
|
||||
padding-right: $borderRadius + $paddingLR;
|
||||
background-color: rgba(#000, .7);
|
||||
border: 1px solid #000;
|
||||
color: #FFF;
|
||||
transition: all .3s;
|
||||
@extend %unable-select;
|
||||
&.d2-source--active {
|
||||
opacity: 1;
|
||||
}
|
||||
&:hover {
|
||||
right: - $borderRadius;
|
||||
background-color: rgba(#000, .9);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,7 @@
|
||||
import BScroll from 'better-scroll'
|
||||
export default {
|
||||
props: {
|
||||
// 滚动优化的选项
|
||||
betterScrollOptions: {
|
||||
type: Object,
|
||||
required: false,
|
||||
@@ -20,6 +21,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
scrollInit () {
|
||||
// 初始化 bs
|
||||
this.BS = new BScroll(this.$refs.wrapper, Object.assign({
|
||||
mouseWheel: true,
|
||||
scrollbar: {
|
||||
@@ -27,6 +29,11 @@ export default {
|
||||
interactive: false
|
||||
}
|
||||
}, this.betterScrollOptions))
|
||||
// 滚动时发出事件 并且统一返回的数据格式
|
||||
this.BS.on('scroll', ({ x, y }) => this.$emit('scroll', {
|
||||
x: -x,
|
||||
y: -y
|
||||
}))
|
||||
},
|
||||
scrollDestroy () {
|
||||
// https://github.com/d2-projects/d2-admin/issues/75
|
||||
@@ -36,6 +43,19 @@ export default {
|
||||
delete this.BS
|
||||
this.BS = null
|
||||
}
|
||||
},
|
||||
// 外部调用的方法 返回顶部
|
||||
scrollToTop () {
|
||||
if (this.BS) this.BS.scrollTo(0, 0, 300)
|
||||
},
|
||||
// 手动发出滚动事件
|
||||
scroll () {
|
||||
if (this.BS) {
|
||||
this.$emit('scroll', {
|
||||
x: -this.BS.x,
|
||||
y: -this.BS.y
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// 提供滚动方面的功能
|
||||
// 非滚动优化模式通用
|
||||
|
||||
import { throttle } from 'lodash'
|
||||
|
||||
// 生成滚动事件的 handler
|
||||
function handleMaker (wait) {
|
||||
return throttle(e => {
|
||||
this.$emit('scroll', {
|
||||
x: e.target.scrollLeft,
|
||||
y: e.target.scrollTop
|
||||
})
|
||||
}, wait)
|
||||
}
|
||||
|
||||
export default {
|
||||
props: {
|
||||
// 滚动事件节流间隔
|
||||
scrollDelay: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 10
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
handleScroll: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
scrollDelay (val) {
|
||||
// 移除旧的监听
|
||||
this.removeScrollListener()
|
||||
// 生成新的 handle 方法
|
||||
this.handleScroll = handleMaker.call(this, val)
|
||||
// 添加新的监听
|
||||
this.addScrollListener()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 增加滚动事件监听
|
||||
addScrollListener () {
|
||||
if (typeof this.handleScroll !== 'function') {
|
||||
// mounted 生命周期内调用这个方法的时候会进入这里的判断
|
||||
this.handleScroll = handleMaker.call(this, this.scrollDelay)
|
||||
}
|
||||
// 添加监听
|
||||
this.$refs.body.addEventListener('scroll', this.handleScroll)
|
||||
},
|
||||
// 移除滚动事件监听
|
||||
removeScrollListener () {
|
||||
this.$refs.body.removeEventListener('scroll', this.handleScroll)
|
||||
},
|
||||
// 外部调用的方法 返回顶部
|
||||
scrollToTop () {
|
||||
const smoothscroll = () => {
|
||||
const body = this.$refs.body
|
||||
const currentScroll = body.scrollTop
|
||||
if (currentScroll > 0) {
|
||||
window.requestAnimationFrame(smoothscroll)
|
||||
body.scrollTo(0, currentScroll - (currentScroll / 5))
|
||||
}
|
||||
}
|
||||
smoothscroll()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// 组件
|
||||
import d2ContainerFull from './components/d2-container-full.vue'
|
||||
import d2ContainerFullBs from './components/d2-container-full-bs.vue'
|
||||
import d2ContainerGhost from './components/d2-container-ghost.vue'
|
||||
import d2ContainerGhostBs from './components/d2-container-ghost-bs.vue'
|
||||
import d2ContainerCard from './components/d2-container-card.vue'
|
||||
import d2ContainerCardBs from './components/d2-container-card-bs.vue'
|
||||
import d2Source from './components/d2-source.vue'
|
||||
|
||||
export default {
|
||||
name: 'd2-container',
|
||||
props: {
|
||||
// 容器样式
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'full'
|
||||
},
|
||||
// 滚动优化
|
||||
betterScroll: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 始终返回渲染组件
|
||||
component () {
|
||||
if (this.type === 'card' && !this.betterScroll) return d2ContainerCard
|
||||
if (this.type === 'card' && this.betterScroll) return d2ContainerCardBs
|
||||
if (this.type === 'ghost' && !this.betterScroll) return d2ContainerGhost
|
||||
if (this.type === 'ghost' && this.betterScroll) return d2ContainerGhostBs
|
||||
if (this.type === 'full' && !this.betterScroll) return d2ContainerFull
|
||||
if (this.type === 'full' && this.betterScroll) return d2ContainerFullBs
|
||||
else {
|
||||
return 'div'
|
||||
}
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
const slots = [
|
||||
h('div', this.$slots.default)
|
||||
]
|
||||
if (this.$slots.header) slots.push(h('div', { slot: 'header' }, [ this.$slots.header ]))
|
||||
if (this.$slots.footer) slots.push(h('div', { slot: 'footer' }, [ this.$slots.footer ]))
|
||||
return h('div', {
|
||||
ref: 'container',
|
||||
class: 'container-component'
|
||||
}, [
|
||||
h(this.component, {
|
||||
ref: 'component',
|
||||
props: this.$attrs,
|
||||
on: {
|
||||
scroll: e => this.$emit('scroll', e)
|
||||
}
|
||||
}, slots),
|
||||
// 只在预览和开发模式下显示源码按钮
|
||||
process.env.VUE_APP_BUILD_MODE === 'TRAVIS' || process.env.NODE_ENV === 'development' ? h(d2Source, {
|
||||
props: this.$attrs
|
||||
}) : undefined
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
// 返回顶部
|
||||
scrollToTop () {
|
||||
this.$refs.component.scrollToTop()
|
||||
// 如果开启了 better scroll 还需要手动触发一遍 scroll 事件
|
||||
const bs = this.$refs.component.BS
|
||||
if (bs) this.$refs.component.scroll()
|
||||
},
|
||||
// 用法同原生方法 scrollBy
|
||||
scrollBy (x = 0, y = 0, time = 300) {
|
||||
if (this.betterScroll) {
|
||||
const bs = this.$refs.component.BS
|
||||
if (bs) {
|
||||
bs.scrollBy(-x, -y, time)
|
||||
// 手动触发一遍 scroll 事件
|
||||
this.$refs.component.scroll()
|
||||
}
|
||||
} else {
|
||||
this.$refs.component.$refs.body.scrollBy(x, y)
|
||||
}
|
||||
},
|
||||
// 用法同原生方法 scrollTo
|
||||
scrollTo (x = 0, y = 0, time = 300) {
|
||||
if (this.betterScroll) {
|
||||
const bs = this.$refs.component.BS
|
||||
if (bs) {
|
||||
bs.scrollTo(-x, -y, time)
|
||||
// 手动触发一遍 scroll 事件
|
||||
this.$refs.component.scroll()
|
||||
}
|
||||
} else {
|
||||
this.$refs.component.$refs.body.scrollTo(x, y)
|
||||
}
|
||||
},
|
||||
// 用法同原生方法 scrollTop
|
||||
scrollTop (top = 0, time = 300) {
|
||||
if (this.betterScroll) {
|
||||
const bs = this.$refs.component.BS
|
||||
if (bs) {
|
||||
bs.scrollTo(bs.x, -top, time)
|
||||
// 手动触发一遍 scroll 事件
|
||||
this.$refs.component.scroll()
|
||||
}
|
||||
} else {
|
||||
this.$refs.component.$refs.body.scrollTop = top
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<template>
|
||||
<div class="container-component" ref="container">
|
||||
<!-- [card] 卡片容器 -->
|
||||
<d2-container-card v-if="type === 'card' && !betterScroll">
|
||||
<slot v-if="$slots.header" name="header" slot="header"/>
|
||||
<slot/>
|
||||
<slot v-if="$slots.footer" name="footer" slot="footer"/>
|
||||
</d2-container-card>
|
||||
<!-- [card] 卡片容器 滚动优化 -->
|
||||
<d2-container-card-bs v-bind="$attrs" v-if="type === 'card' && betterScroll">
|
||||
<slot v-if="$slots.header" name="header" slot="header"/>
|
||||
<slot/>
|
||||
<slot v-if="$slots.footer" name="footer" slot="footer"/>
|
||||
</d2-container-card-bs>
|
||||
<!-- [ghost] 隐形容器 -->
|
||||
<d2-container-ghost v-if="type === 'ghost' && !betterScroll">
|
||||
<slot v-if="$slots.header" name="header" slot="header"/>
|
||||
<slot/>
|
||||
<slot v-if="$slots.footer" name="footer" slot="footer"/>
|
||||
</d2-container-ghost>
|
||||
<!-- [ghost] 隐形容器 滚动优化 -->
|
||||
<d2-container-ghost-bs v-bind="$attrs" v-if="type === 'ghost' && betterScroll">
|
||||
<slot v-if="$slots.header" name="header" slot="header"/>
|
||||
<slot/>
|
||||
<slot v-if="$slots.footer" name="footer" slot="footer"/>
|
||||
</d2-container-ghost-bs>
|
||||
<!-- [container-full] 填充 -->
|
||||
<d2-container-full v-if="type === 'full' && !betterScroll">
|
||||
<slot v-if="$slots.header" name="header" slot="header"/>
|
||||
<slot/>
|
||||
<slot v-if="$slots.footer" name="footer" slot="footer"/>
|
||||
</d2-container-full>
|
||||
<!-- [container-full-bs] 填充 滚动优化 -->
|
||||
<d2-container-full-bs v-bind="$attrs" v-if="type === 'full' && betterScroll">
|
||||
<slot v-if="$slots.header" name="header" slot="header"/>
|
||||
<slot/>
|
||||
<slot v-if="$slots.footer" name="footer" slot="footer"/>
|
||||
</d2-container-full-bs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 组件
|
||||
import d2ContainerFull from './components/d2-container-full.vue'
|
||||
import d2ContainerFullBs from './components/d2-container-full-bs.vue'
|
||||
import d2ContainerGhost from './components/d2-container-ghost.vue'
|
||||
import d2ContainerGhostBs from './components/d2-container-ghost-bs.vue'
|
||||
import d2ContainerCard from './components/d2-container-card.vue'
|
||||
import d2ContainerCardBs from './components/d2-container-card-bs.vue'
|
||||
export default {
|
||||
name: 'd2-container',
|
||||
components: {
|
||||
'd2-container-full': d2ContainerFull,
|
||||
'd2-container-full-bs': d2ContainerFullBs,
|
||||
'd2-container-ghost': d2ContainerGhost,
|
||||
'd2-container-ghost-bs': d2ContainerGhostBs,
|
||||
'd2-container-card': d2ContainerCard,
|
||||
'd2-container-card-bs': d2ContainerCardBs
|
||||
},
|
||||
props: {
|
||||
// 容器样式
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'full'
|
||||
},
|
||||
// 滚动优化
|
||||
betterScroll: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -3,8 +3,9 @@
|
||||
<div class="d2-page-cover__logo">
|
||||
<slot/>
|
||||
</div>
|
||||
<p class="d2-page-cover__title">{{title}}</p>
|
||||
<p class="d2-page-cover__sub-title d2-mt-0">{{subTitle}}</p>
|
||||
<p class="d2-page-cover__title">D2 Admin {{$version}}</p>
|
||||
<p class="d2-page-cover__sub-title">优雅的中后台集成方案</p>
|
||||
<p class="d2-page-cover__build-time">FINAL BUILD TIME {{$buildTime}}</p>
|
||||
<slot name="footer"/>
|
||||
<a target="blank" href="https://github.com/d2-projects/d2-admin">
|
||||
<img
|
||||
@@ -15,25 +16,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'Title'
|
||||
},
|
||||
subTitle: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'subTitle'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/style/public.scss';
|
||||
.d2-page-cover {
|
||||
@extend %full;
|
||||
@extend %unable-select;
|
||||
@@ -47,10 +30,21 @@ export default {
|
||||
}
|
||||
}
|
||||
.d2-page-cover__title {
|
||||
margin: 0px;
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
color: $color-text-main;
|
||||
}
|
||||
.d2-page-cover__sub-title {
|
||||
color: $color-text-sub;
|
||||
margin: 0px;
|
||||
margin-bottom: 5px;
|
||||
color: $color-text-normal;
|
||||
}
|
||||
.d2-page-cover__build-time {
|
||||
margin: 0px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 12px;
|
||||
color: $color-text-placehoder;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<el-menu-item :index="menu.path || uniqueId">
|
||||
<i v-if="menu.icon" :class="`fa fa-${menu.icon}`"></i>
|
||||
<d2-icon-svg v-else-if="menu.iconSvg" :name="menu.iconSvg"/>
|
||||
<i v-else class="fa fa-file-o"></i>
|
||||
<i v-if="menu.icon === undefined & !menu.iconSvg" class="fa fa-file-o"></i>
|
||||
<d2-icon-svg v-if="menu.iconSvg" :name="menu.iconSvg"/>
|
||||
<span slot="title">{{menu.title || '未命名菜单'}}</span>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<el-submenu :index="menu.path || uniqueId">
|
||||
<template slot="title">
|
||||
<i v-if="menu.icon" :class="`fa fa-${menu.icon}`"></i>
|
||||
<d2-icon-svg v-else-if="menu.iconSvg" :name="menu.iconSvg"/>
|
||||
<i v-else class="fa fa-folder-o"></i>
|
||||
<i v-if="menu.icon === undefined & !menu.iconSvg" class="fa fa-folder-o"></i>
|
||||
<d2-icon-svg v-if="menu.iconSvg" :name="menu.iconSvg"/>
|
||||
<span slot="title">{{menu.title}}</span>
|
||||
</template>
|
||||
<template v-for="(child, childIndex) in menu.children">
|
||||
|
||||
@@ -165,7 +165,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~@/assets/style/public.scss';
|
||||
.d2-error-log-list__expand-group {
|
||||
.d2-error-log-list__expand {
|
||||
padding-left: 20px;
|
||||
|
||||
@@ -69,7 +69,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/style/public.scss';
|
||||
.theme-preview {
|
||||
height: 50px;
|
||||
width: 100px;
|
||||
|
||||
@@ -55,12 +55,12 @@ export default {
|
||||
}, 500)
|
||||
},
|
||||
// 监听路由 控制侧边栏激活状态
|
||||
'$route.matched': {
|
||||
handler (val) {
|
||||
this.active = val[val.length - 1].path
|
||||
'$route': {
|
||||
handler ({ fullPath }) {
|
||||
this.active = fullPath
|
||||
this.$nextTick(() => {
|
||||
if (this.aside.length > 0 && this.$refs.menu) {
|
||||
this.$refs.menu.activeIndex = this.active
|
||||
this.$refs.menu.activeIndex = fullPath
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -35,7 +35,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/style/public.scss';
|
||||
.d2-panel-search-item {
|
||||
height: 64px;
|
||||
margin: 0px -20px;
|
||||
|
||||
@@ -183,7 +183,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/style/public.scss';
|
||||
.panel-search {
|
||||
margin: 20px;
|
||||
.panel-search__input-group {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
:x="contentmenuX"
|
||||
:y="contentmenuY">
|
||||
<d2-contextmenu-list
|
||||
:menulist="tagName === 'index' ? contextmenuListIndex : contextmenuList"
|
||||
:menulist="tagName === '/index' ? contextmenuListIndex : contextmenuList"
|
||||
@rowClick="contextmenuClick"/>
|
||||
</d2-contextmenu>
|
||||
<el-tabs
|
||||
@@ -19,10 +19,10 @@
|
||||
@edit="handleTabsEdit"
|
||||
@contextmenu.native="handleContextmenu">
|
||||
<el-tab-pane
|
||||
v-for="(page, index) in opened"
|
||||
:key="index"
|
||||
v-for="page in opened"
|
||||
:key="page.fullPath"
|
||||
:label="page.meta.title || '未命名'"
|
||||
:name="page.name"/>
|
||||
:name="page.fullPath"/>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
@@ -79,7 +79,7 @@ export default {
|
||||
{ icon: 'times', title: '关闭其它', value: 'other' },
|
||||
{ icon: 'times-circle', title: '关闭全部', value: 'all' }
|
||||
],
|
||||
tagName: 'index'
|
||||
tagName: '/index'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -163,7 +163,7 @@ export default {
|
||||
*/
|
||||
handleClick (tab, event) {
|
||||
// 找到点击的页面在 tag 列表里是哪个
|
||||
const page = this.opened.find(page => page.name === tab.name)
|
||||
const page = this.opened.find(page => page.fullPath === tab.name)
|
||||
const { name, params, query } = page
|
||||
if (page) {
|
||||
this.$router.push({ name, params, query })
|
||||
|
||||
@@ -81,6 +81,15 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import d2MenuSide from './components/menu-side'
|
||||
import d2MenuHeader from './components/menu-header'
|
||||
import d2Tabs from './components/tabs'
|
||||
import d2HeaderFullscreen from './components/header-fullscreen'
|
||||
import d2HeaderSearch from './components/header-search'
|
||||
import d2HeaderSize from './components/header-size'
|
||||
import d2HeaderTheme from './components/header-theme'
|
||||
import d2HeaderUser from './components/header-user'
|
||||
import d2HeaderErrorLog from './components/header-error-log'
|
||||
import { mapState, mapGetters, mapActions } from 'vuex'
|
||||
import mixinSearch from './mixins/search'
|
||||
export default {
|
||||
@@ -89,15 +98,15 @@ export default {
|
||||
mixinSearch
|
||||
],
|
||||
components: {
|
||||
'd2-menu-side': () => import('./components/menu-side'),
|
||||
'd2-menu-header': () => import('./components/menu-header'),
|
||||
'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')
|
||||
d2MenuSide,
|
||||
d2MenuHeader,
|
||||
d2Tabs,
|
||||
d2HeaderFullscreen,
|
||||
d2HeaderSearch,
|
||||
d2HeaderSize,
|
||||
d2HeaderTheme,
|
||||
d2HeaderUser,
|
||||
d2HeaderErrorLog
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Cookies from 'js-cookie'
|
||||
import setting from '@/setting.js'
|
||||
|
||||
const cookies = {}
|
||||
|
||||
@@ -14,7 +13,7 @@ cookies.set = function (name = 'default', value = '', cookieSetting = {}) {
|
||||
expires: 1
|
||||
}
|
||||
Object.assign(currentCookieSetting, cookieSetting)
|
||||
Cookies.set(`d2admin-${setting.releases.version}-${name}`, value, currentCookieSetting)
|
||||
Cookies.set(`d2admin-${process.env.VUE_APP_VERSION}-${name}`, value, currentCookieSetting)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,7 +21,7 @@ cookies.set = function (name = 'default', value = '', cookieSetting = {}) {
|
||||
* @param {String} name cookie name
|
||||
*/
|
||||
cookies.get = function (name = 'default') {
|
||||
return Cookies.get(`d2admin-${setting.releases.version}-${name}`)
|
||||
return Cookies.get(`d2admin-${process.env.VUE_APP_VERSION}-${name}`)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,7 +36,7 @@ cookies.getAll = function () {
|
||||
* @param {String} name cookie name
|
||||
*/
|
||||
cookies.remove = function (name = 'default') {
|
||||
return Cookies.remove(`d2admin-${setting.releases.version}-${name}`)
|
||||
return Cookies.remove(`d2admin-${process.env.VUE_APP_VERSION}-${name}`)
|
||||
}
|
||||
|
||||
export default cookies
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import low from 'lowdb'
|
||||
import LocalStorage from 'lowdb/adapters/LocalStorage'
|
||||
import setting from '@/setting.js'
|
||||
|
||||
const adapter = new LocalStorage(`d2admin-${setting.releases.version}`)
|
||||
const adapter = new LocalStorage(`d2admin-${process.env.VUE_APP_VERSION}`)
|
||||
const db = low(adapter)
|
||||
|
||||
db
|
||||
+7
-5
@@ -1,8 +1,10 @@
|
||||
import log from './util.log.js'
|
||||
import cookies from './util.cookies.js'
|
||||
import cookies from './util.cookies'
|
||||
import db from './util.db'
|
||||
import log from './util.log'
|
||||
|
||||
let util = {
|
||||
const util = {
|
||||
cookies,
|
||||
db,
|
||||
log
|
||||
}
|
||||
|
||||
@@ -23,10 +25,10 @@ util.open = function (url) {
|
||||
var a = document.createElement('a')
|
||||
a.setAttribute('href', url)
|
||||
a.setAttribute('target', '_blank')
|
||||
a.setAttribute('id', 'd2admin-menu-link')
|
||||
a.setAttribute('id', 'd2admin-link-temp')
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(document.getElementById('d2admin-menu-link'))
|
||||
document.body.removeChild(document.getElementById('d2admin-link-temp'))
|
||||
}
|
||||
|
||||
export default util
|
||||
|
||||
@@ -5,8 +5,6 @@ import Vue from 'vue'
|
||||
import App from './App'
|
||||
// store
|
||||
import store from '@/store/index'
|
||||
// 模拟数据
|
||||
import '@/mock'
|
||||
// 多国语
|
||||
import i18n from './i18n'
|
||||
// 核心插件
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
const userDB = [
|
||||
{ username: 'admin', password: 'admin', uuid: 'admin-uuid', name: '管理员' },
|
||||
{ username: 'editor', password: 'editor', uuid: 'editor-uuid', name: '编辑' },
|
||||
{ username: 'user1', password: 'user1', uuid: 'user1-uuid', name: '用户1' }
|
||||
]
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/api/login',
|
||||
method: 'post',
|
||||
handle ({ body }) {
|
||||
const user = userDB.find(e => e.username === body.username && e.password === body.password)
|
||||
if (user) {
|
||||
return {
|
||||
code: 0,
|
||||
msg: '登录成功',
|
||||
data: {
|
||||
...user,
|
||||
token: '8dfhassad0asdjwoeiruty'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
code: 401,
|
||||
msg: '用户名或密码错误',
|
||||
data: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1,43 +0,0 @@
|
||||
import Mock from 'mockjs'
|
||||
|
||||
const userDB = [
|
||||
{
|
||||
username: 'admin',
|
||||
password: 'admin',
|
||||
uuid: 'admin-uuid',
|
||||
name: '管理员'
|
||||
},
|
||||
{
|
||||
username: 'editor',
|
||||
password: 'editor',
|
||||
uuid: 'editor-uuid',
|
||||
name: '编辑'
|
||||
},
|
||||
{
|
||||
username: 'user1',
|
||||
password: 'user1',
|
||||
uuid: 'user1-uuid',
|
||||
name: '用户1'
|
||||
}
|
||||
]
|
||||
|
||||
Mock.mock('/api/login', 'post', ({ url, type, body }) => {
|
||||
const bodyObj = JSON.parse(body)
|
||||
const user = userDB.find(e => e.username === bodyObj.username && e.password === bodyObj.password)
|
||||
if (user) {
|
||||
return {
|
||||
code: 0,
|
||||
msg: '登录成功',
|
||||
data: {
|
||||
...user,
|
||||
token: 'd787syv8dys8cas80d9s0a0d8f79ads56f7s4d56f879a8as89fd980s7dg'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
code: 401,
|
||||
msg: '用户名或密码错误',
|
||||
data: {}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,73 @@
|
||||
import Mock from 'mockjs'
|
||||
import qs from 'qs'
|
||||
import withCredentials from './patch/withCredentials'
|
||||
|
||||
/* 补丁 */
|
||||
withCredentials(Mock)
|
||||
|
||||
/* Mock 默认配置 */
|
||||
Mock.setup({ timeout: '200-300' })
|
||||
|
||||
/* 扩展 [生成器] */
|
||||
const Generator = (prop, template) => {
|
||||
const obj = {}
|
||||
obj[prop] = [template]
|
||||
return Mock.mock(obj)
|
||||
}
|
||||
|
||||
/* 扩展 [循环] */
|
||||
const Repeat = (num, itemTemplate) => Generator(`data|${num}`, itemTemplate).data
|
||||
|
||||
const CustomExtends = {
|
||||
Generator,
|
||||
Repeat,
|
||||
Mock,
|
||||
Random: Mock.Random
|
||||
}
|
||||
|
||||
const extend = (prop, value) => {
|
||||
CustomExtends[prop] = value
|
||||
}
|
||||
|
||||
/* 装配配置组 */
|
||||
const wired = ({ url, type, body }) => ({
|
||||
method: type,
|
||||
params: qs.parse(url.split('?').length > 1 ? url.split('?')[1] : ''),
|
||||
body: JSON.parse(body),
|
||||
url: qs.parse(url.split('?')[0]),
|
||||
...CustomExtends
|
||||
})
|
||||
|
||||
const setup = (path, method, handle) => {
|
||||
Mock.mock(
|
||||
RegExp(path),
|
||||
method,
|
||||
typeof handle === 'function' ? o => handle(wired(o)) : handle
|
||||
)
|
||||
}
|
||||
|
||||
const load = (collection) => {
|
||||
collection.map(({ path, method, handle }) => {
|
||||
if (method === '*') {
|
||||
method = [
|
||||
'get',
|
||||
'head',
|
||||
'post',
|
||||
'put',
|
||||
'delete',
|
||||
'connect',
|
||||
'options',
|
||||
'trace',
|
||||
'patch'
|
||||
]
|
||||
}
|
||||
if (typeof method === 'string' && method.indexOf('|') > -1) method = method.split('|')
|
||||
if (method instanceof Array) {
|
||||
method.map(item => setup(path, item, handle))
|
||||
} else {
|
||||
setup(path, method, handle)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default { setup, load, extend }
|
||||
@@ -0,0 +1,8 @@
|
||||
export default function (Mock) {
|
||||
// http://cnine.me/note/FrontEnd/mock-lose-cookies-dbg.html
|
||||
Mock.XHR.prototype.__send = Mock.XHR.prototype.send
|
||||
Mock.XHR.prototype.send = function () {
|
||||
if (this.custom.xhr) this.custom.xhr.withCredentials = this.withCredentials || false
|
||||
this.__send.apply(this, arguments)
|
||||
}
|
||||
}
|
||||
+6
-11
@@ -1,15 +1,10 @@
|
||||
import Mock from 'mockjs'
|
||||
import d2Mock from './d2-mock'
|
||||
|
||||
// 补丁 解决 mock.js 影响 Cookie 携带
|
||||
import PatchCookie from './patch/cookie'
|
||||
|
||||
PatchCookie(Mock)
|
||||
|
||||
// 导入所有的接口
|
||||
const req = context => context.keys().map(context)
|
||||
req(require.context('./api/', true, /\.js$/))
|
||||
const options = req(require.context('./api/', true, /\.js$/))
|
||||
.filter(e => e.default)
|
||||
.map(e => e.default)
|
||||
|
||||
// 设置全局延时 没有延时的话有时候会检测不到数据变化 建议保留
|
||||
Mock.setup({
|
||||
timeout: '300-600'
|
||||
options.forEach(option => {
|
||||
d2Mock.load(option)
|
||||
})
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
export default function (Mock) {
|
||||
// 解决 Mock 情况下,携带 withCredentials = true,且未被拦截的跨域请求丢失 Cookies 的问题
|
||||
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
|
||||
Mock.XHR.prototype.send = function () {
|
||||
if (this.custom.xhr) {
|
||||
this.custom.xhr.withCredentials = this.withCredentials || false
|
||||
}
|
||||
this.proxy_send(...arguments)
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
<template>
|
||||
<d2-container>
|
||||
<d2-container :filename="filename">
|
||||
<template slot="header">Page 1 header</template>
|
||||
Hello World
|
||||
<template slot="footer">footer</template>
|
||||
</d2-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'page1'
|
||||
name: 'page1',
|
||||
data () {
|
||||
return {
|
||||
filename: __filename
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
<template>
|
||||
<d2-container>
|
||||
<d2-container :filename="filename">
|
||||
<template slot="header">Page 2 header</template>
|
||||
Hello World
|
||||
<template slot="footer">footer</template>
|
||||
</d2-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'page2'
|
||||
name: 'page2',
|
||||
data () {
|
||||
return {
|
||||
filename: __filename
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
<template>
|
||||
<d2-container>
|
||||
<d2-container :filename="filename">
|
||||
<template slot="header">Page 3 header</template>
|
||||
Hello World
|
||||
<template slot="footer">footer</template>
|
||||
</d2-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'page3'
|
||||
name: 'page3',
|
||||
data () {
|
||||
return {
|
||||
filename: __filename
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/style/public.scss';
|
||||
.page {
|
||||
background: #303133;
|
||||
background-blend-mode: multiply,multiply;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<template>
|
||||
<d2-container class="page">
|
||||
<d2-page-cover
|
||||
:title="`D2 Admin ${version}`"
|
||||
sub-title="优雅的中后台集成方案">
|
||||
<d2-container :filename="filename" class="page">
|
||||
<d2-page-cover>
|
||||
<d2-icon-svg
|
||||
class="page__logo"
|
||||
name="d2-admin"/>
|
||||
@@ -35,7 +33,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import D2HelpBtn from './components/d2-help-btn'
|
||||
import D2Badge from './components/d2-badge'
|
||||
export default {
|
||||
@@ -43,16 +40,15 @@ export default {
|
||||
D2HelpBtn,
|
||||
D2Badge
|
||||
},
|
||||
computed: {
|
||||
...mapState('d2admin/releases', [
|
||||
'version'
|
||||
])
|
||||
data () {
|
||||
return {
|
||||
filename: __filename
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/style/public.scss';
|
||||
.page {
|
||||
.page__logo {
|
||||
width: 120px;
|
||||
@@ -60,7 +56,7 @@ export default {
|
||||
.page__btn-group {
|
||||
color: $color-text-placehoder;
|
||||
font-size: 12px;
|
||||
margin-top: -10px;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 20px;
|
||||
span {
|
||||
color: $color-text-sub;
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
// 例子插件配置地址
|
||||
// https://vincentgarreau.com/particles.js/#default
|
||||
@@ -1,112 +0,0 @@
|
||||
/* eslint-disable */
|
||||
|
||||
export default {
|
||||
"particles": {
|
||||
"number": {
|
||||
"value": 6,
|
||||
"density": {
|
||||
"enable": true,
|
||||
"value_area": 800
|
||||
}
|
||||
},
|
||||
"color": {
|
||||
"value": "#444"
|
||||
},
|
||||
"shape": {
|
||||
"type": "polygon",
|
||||
"stroke": {
|
||||
"width": 0,
|
||||
"color": "#000"
|
||||
},
|
||||
"polygon": {
|
||||
"nb_sides": 6
|
||||
},
|
||||
"image": {
|
||||
"src": "img/github.svg",
|
||||
"width": 100,
|
||||
"height": 100
|
||||
}
|
||||
},
|
||||
"opacity": {
|
||||
"value": 0.3,
|
||||
"random": true,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 1,
|
||||
"opacity_min": 0.1,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"value": 160,
|
||||
"random": false,
|
||||
"anim": {
|
||||
"enable": true,
|
||||
"speed": 10,
|
||||
"size_min": 40,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"line_linked": {
|
||||
"enable": false,
|
||||
"distance": 200,
|
||||
"color": "#ffffff",
|
||||
"opacity": 1,
|
||||
"width": 2
|
||||
},
|
||||
"move": {
|
||||
"enable": true,
|
||||
"speed": 8,
|
||||
"direction": "none",
|
||||
"random": false,
|
||||
"straight": false,
|
||||
"out_mode": "out",
|
||||
"bounce": false,
|
||||
"attract": {
|
||||
"enable": false,
|
||||
"rotateX": 600,
|
||||
"rotateY": 1200
|
||||
}
|
||||
}
|
||||
},
|
||||
"interactivity": {
|
||||
"detect_on": "canvas",
|
||||
"events": {
|
||||
"onhover": {
|
||||
"enable": false,
|
||||
"mode": "grab"
|
||||
},
|
||||
"onclick": {
|
||||
"enable": false,
|
||||
"mode": "push"
|
||||
},
|
||||
"resize": true
|
||||
},
|
||||
"modes": {
|
||||
"grab": {
|
||||
"distance": 400,
|
||||
"line_linked": {
|
||||
"opacity": 1
|
||||
}
|
||||
},
|
||||
"bubble": {
|
||||
"distance": 400,
|
||||
"size": 40,
|
||||
"duration": 2,
|
||||
"opacity": 8,
|
||||
"speed": 3
|
||||
},
|
||||
"repulse": {
|
||||
"distance": 200,
|
||||
"duration": 0.4
|
||||
},
|
||||
"push": {
|
||||
"particles_nb": 4
|
||||
},
|
||||
"remove": {
|
||||
"particles_nb": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"retina_detect": true
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/* eslint-disable */
|
||||
|
||||
export default {
|
||||
"particles": {
|
||||
"number": {
|
||||
"value": 80,
|
||||
"density": {
|
||||
"enable": true,
|
||||
"value_area": 800
|
||||
}
|
||||
},
|
||||
"color": {
|
||||
"value": "#DCDFE6"
|
||||
},
|
||||
"shape": {
|
||||
"type": "circle",
|
||||
"stroke": {
|
||||
"width": 0,
|
||||
"color": "#000000"
|
||||
},
|
||||
"polygon": {
|
||||
"nb_sides": 5
|
||||
},
|
||||
"image": {
|
||||
"src": "img/github.svg",
|
||||
"width": 100,
|
||||
"height": 100
|
||||
}
|
||||
},
|
||||
"opacity": {
|
||||
"value": 1,
|
||||
"random": false,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 1,
|
||||
"opacity_min": 0.1,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"value": 4,
|
||||
"random": true,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 40,
|
||||
"size_min": 0.1,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"line_linked": {
|
||||
"enable": true,
|
||||
"distance": 150,
|
||||
"color": "#DCDFE6",
|
||||
"opacity": 0.4,
|
||||
"width": 2
|
||||
},
|
||||
"move": {
|
||||
"enable": true,
|
||||
"speed": 6,
|
||||
"direction": "none",
|
||||
"random": false,
|
||||
"straight": false,
|
||||
"out_mode": "out",
|
||||
"bounce": false,
|
||||
"attract": {
|
||||
"enable": false,
|
||||
"rotateX": 600,
|
||||
"rotateY": 1200
|
||||
}
|
||||
}
|
||||
},
|
||||
"interactivity": {
|
||||
"detect_on": "canvas",
|
||||
"events": {
|
||||
"onhover": {
|
||||
"enable": true,
|
||||
"mode": "repulse"
|
||||
},
|
||||
"onclick": {
|
||||
"enable": true,
|
||||
"mode": "push"
|
||||
},
|
||||
"resize": true
|
||||
},
|
||||
"modes": {
|
||||
"grab": {
|
||||
"distance": 400,
|
||||
"line_linked": {
|
||||
"opacity": 1
|
||||
}
|
||||
},
|
||||
"bubble": {
|
||||
"distance": 400,
|
||||
"size": 40,
|
||||
"duration": 2,
|
||||
"opacity": 8,
|
||||
"speed": 3
|
||||
},
|
||||
"repulse": {
|
||||
"distance": 200,
|
||||
"duration": 0.4
|
||||
},
|
||||
"push": {
|
||||
"particles_nb": 4
|
||||
},
|
||||
"remove": {
|
||||
"particles_nb": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"retina_detect": true
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/* eslint-disable */
|
||||
|
||||
export default {
|
||||
"particles": {
|
||||
"number": {
|
||||
"value": 160,
|
||||
"density": {
|
||||
"enable": true,
|
||||
"value_area": 800
|
||||
}
|
||||
},
|
||||
"color": {
|
||||
"value": "#ffffff"
|
||||
},
|
||||
"shape": {
|
||||
"type": "circle",
|
||||
"stroke": {
|
||||
"width": 0,
|
||||
"color": "#000000"
|
||||
},
|
||||
"polygon": {
|
||||
"nb_sides": 5
|
||||
},
|
||||
"image": {
|
||||
"src": "img/github.svg",
|
||||
"width": 100,
|
||||
"height": 100
|
||||
}
|
||||
},
|
||||
"opacity": {
|
||||
"value": 1,
|
||||
"random": true,
|
||||
"anim": {
|
||||
"enable": true,
|
||||
"speed": 1,
|
||||
"opacity_min": 0,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"value": 3,
|
||||
"random": true,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 4,
|
||||
"size_min": 0.3,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"line_linked": {
|
||||
"enable": false,
|
||||
"distance": 150,
|
||||
"color": "#ffffff",
|
||||
"opacity": 0.4,
|
||||
"width": 1
|
||||
},
|
||||
"move": {
|
||||
"enable": true,
|
||||
"speed": 1,
|
||||
"direction": "none",
|
||||
"random": true,
|
||||
"straight": false,
|
||||
"out_mode": "out",
|
||||
"bounce": false,
|
||||
"attract": {
|
||||
"enable": false,
|
||||
"rotateX": 600,
|
||||
"rotateY": 600
|
||||
}
|
||||
}
|
||||
},
|
||||
"interactivity": {
|
||||
"detect_on": "canvas",
|
||||
"events": {
|
||||
"onhover": {
|
||||
"enable": true,
|
||||
"mode": "bubble"
|
||||
},
|
||||
"onclick": {
|
||||
"enable": true,
|
||||
"mode": "repulse"
|
||||
},
|
||||
"resize": true
|
||||
},
|
||||
"modes": {
|
||||
"grab": {
|
||||
"distance": 400,
|
||||
"line_linked": {
|
||||
"opacity": 1
|
||||
}
|
||||
},
|
||||
"bubble": {
|
||||
"distance": 250,
|
||||
"size": 0,
|
||||
"duration": 2,
|
||||
"opacity": 0,
|
||||
"speed": 3
|
||||
},
|
||||
"repulse": {
|
||||
"distance": 400,
|
||||
"duration": 0.4
|
||||
},
|
||||
"push": {
|
||||
"particles_nb": 4
|
||||
},
|
||||
"remove": {
|
||||
"particles_nb": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"retina_detect": true
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/* eslint-disable */
|
||||
|
||||
export default {
|
||||
"particles": {
|
||||
"number": {
|
||||
"value": 400,
|
||||
"density": {
|
||||
"enable": true,
|
||||
"value_area": 800
|
||||
}
|
||||
},
|
||||
"color": {
|
||||
"value": "#fff"
|
||||
},
|
||||
"shape": {
|
||||
"type": "circle",
|
||||
"stroke": {
|
||||
"width": 0,
|
||||
"color": "#000000"
|
||||
},
|
||||
"polygon": {
|
||||
"nb_sides": 5
|
||||
},
|
||||
"image": {
|
||||
"src": "img/github.svg",
|
||||
"width": 100,
|
||||
"height": 100
|
||||
}
|
||||
},
|
||||
"opacity": {
|
||||
"value": 0.5,
|
||||
"random": true,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 1,
|
||||
"opacity_min": 0.1,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"value": 10,
|
||||
"random": true,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 40,
|
||||
"size_min": 0.1,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"line_linked": {
|
||||
"enable": false,
|
||||
"distance": 500,
|
||||
"color": "#ffffff",
|
||||
"opacity": 0.4,
|
||||
"width": 2
|
||||
},
|
||||
"move": {
|
||||
"enable": true,
|
||||
"speed": 6,
|
||||
"direction": "bottom",
|
||||
"random": false,
|
||||
"straight": false,
|
||||
"out_mode": "out",
|
||||
"bounce": false,
|
||||
"attract": {
|
||||
"enable": false,
|
||||
"rotateX": 600,
|
||||
"rotateY": 1200
|
||||
}
|
||||
}
|
||||
},
|
||||
"interactivity": {
|
||||
"detect_on": "canvas",
|
||||
"events": {
|
||||
"onhover": {
|
||||
"enable": true,
|
||||
"mode": "bubble"
|
||||
},
|
||||
"onclick": {
|
||||
"enable": true,
|
||||
"mode": "repulse"
|
||||
},
|
||||
"resize": true
|
||||
},
|
||||
"modes": {
|
||||
"grab": {
|
||||
"distance": 400,
|
||||
"line_linked": {
|
||||
"opacity": 0.5
|
||||
}
|
||||
},
|
||||
"bubble": {
|
||||
"distance": 400,
|
||||
"size": 4,
|
||||
"duration": 0.3,
|
||||
"opacity": 1,
|
||||
"speed": 3
|
||||
},
|
||||
"repulse": {
|
||||
"distance": 200,
|
||||
"duration": 0.4
|
||||
},
|
||||
"push": {
|
||||
"particles_nb": 4
|
||||
},
|
||||
"remove": {
|
||||
"particles_nb": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"retina_detect": true
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
+314
-50
@@ -1,41 +1,77 @@
|
||||
<template>
|
||||
<div class="login-page">
|
||||
<div class="layer bg" id="login"></div>
|
||||
<div class="layer flex-center">
|
||||
<!-- logo部分 -->
|
||||
<div class="logo-group">
|
||||
<img src="./image/logo.png" alt="logo">
|
||||
<div class="page-login">
|
||||
<div class="page-login--layer page-login--layer-area">
|
||||
<ul class="circles">
|
||||
<li v-for="n in 10" :key="n"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
class="page-login--layer page-login--layer-time"
|
||||
flex="main:center cross:center">
|
||||
{{time}}
|
||||
</div>
|
||||
<div class="page-login--layer">
|
||||
<div
|
||||
class="page-login--content"
|
||||
flex="dir:top main:justify cross:center box:justify">
|
||||
<div class="page-login--content-header">
|
||||
<p class="page-login--content-header-motto">
|
||||
时间是一切财富中最宝贵的财富。 <span>—— 德奥弗拉斯多</span>
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="page-login--content-main"
|
||||
flex="dir:top main:center cross:center">
|
||||
<!-- logo -->
|
||||
<img class="page-login--logo" src="./image/logo@2x.png">
|
||||
<!-- 表单 -->
|
||||
<div class="page-login--form">
|
||||
<el-card shadow="never">
|
||||
<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>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input type="password" v-model="formLogin.password" placeholder="密码">
|
||||
<i slot="prepend" class="fa fa-keyboard-o"></i>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code">
|
||||
<el-input type="text" v-model="formLogin.code" placeholder="- - - -">
|
||||
<template slot="prepend">验证码</template>
|
||||
<template slot="append">
|
||||
<img class="login-code" src="./image/login-code.png">
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-button size="default" @click="submit" type="primary" class="button-login">登录</el-button>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<p
|
||||
class="page-login--options"
|
||||
flex="main:justify cross:center">
|
||||
<span><d2-icon name="question-circle"/> 忘记密码</span>
|
||||
<span>注册用户</span>
|
||||
</p>
|
||||
<!-- 快速登录按钮 -->
|
||||
<el-button class="page-login--quick" size="default" type="info" @click="dialogVisible = true">
|
||||
快速选择用户(测试功能)
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-login--content-footer">
|
||||
<p class="page-login--content-footer-options">
|
||||
<a href="#">帮助</a>
|
||||
<a href="#">隐私</a>
|
||||
<a href="#">条款</a>
|
||||
</p>
|
||||
<p class="page-login--content-footer-copyright">
|
||||
Copyright <d2-icon name="copyright"/> 2018 D2 Projects 开源组织出品 <a href="https://github.com/FairyEver">@FairyEver</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 表单部分 -->
|
||||
<div class="form-group">
|
||||
<el-card>
|
||||
<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>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input type="password" v-model="formLogin.password" placeholder="密码">
|
||||
<i slot="prepend" class="fa fa-keyboard-o"></i>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code">
|
||||
<el-input type="text" v-model="formLogin.code" placeholder="- - - -">
|
||||
<template slot="prepend">验证码</template>
|
||||
<template slot="append">
|
||||
<img class="login-code" src="./image/login-code.png">
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-button size="default" @click="submit" type="primary" class="button-login">登录</el-button>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 快速登录按钮 -->
|
||||
<el-button size="default" type="info" class="button-help" @click="dialogVisible = true">
|
||||
快速选择用户(测试功能)
|
||||
</el-button>
|
||||
</div>
|
||||
<el-dialog
|
||||
title="快速选择用户"
|
||||
@@ -43,7 +79,7 @@
|
||||
width="400px">
|
||||
<el-row :gutter="10" style="margin: -20px 0px -10px 0px;">
|
||||
<el-col v-for="(user, index) in users" :key="index" :span="8">
|
||||
<div class="user-btn" @click="handleUserBtnClick(user)">
|
||||
<div class="page-login--quick-user" @click="handleUserBtnClick(user)">
|
||||
<d2-icon name="user-circle-o"/>
|
||||
<span>{{user.name}}</span>
|
||||
</div>
|
||||
@@ -54,13 +90,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* eslint-disable */
|
||||
require('particles.js')
|
||||
import config from './config/default'
|
||||
import dayjs from 'dayjs'
|
||||
import { mapActions } from 'vuex'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
timeInterval: null,
|
||||
time: dayjs().format('HH:mm:ss'),
|
||||
// 快速选择用户
|
||||
dialogVisible: false,
|
||||
users: [
|
||||
@@ -101,22 +137,20 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// 初始化例子插件
|
||||
particlesJS('login', config)
|
||||
this.timeInterval = setInterval(() => {
|
||||
this.refreshTime()
|
||||
}, 1000)
|
||||
},
|
||||
beforeDestroy () {
|
||||
// 销毁 particlesJS
|
||||
// thanks https://github.com/d2-projects/d2-admin/issues/65
|
||||
// ref https://github.com/VincentGarreau/particles.js/issues/63
|
||||
if (pJSDom && pJSDom.length > 0) {
|
||||
pJSDom[0].pJS.fn.vendors.destroypJS()
|
||||
pJSDom = []
|
||||
}
|
||||
clearInterval(this.timeInterval)
|
||||
},
|
||||
methods: {
|
||||
...mapActions('d2admin/account', [
|
||||
'login'
|
||||
]),
|
||||
refreshTime () {
|
||||
this.time = dayjs().format('HH:mm:ss')
|
||||
},
|
||||
/**
|
||||
* @description 接收选择一个用户快速登录的事件
|
||||
* @param {Object} user 用户信息
|
||||
@@ -141,6 +175,10 @@ export default {
|
||||
username: this.formLogin.username,
|
||||
password: this.formLogin.password
|
||||
})
|
||||
.then(() => {
|
||||
// 重定向对象不存在则返回顶层路径
|
||||
this.$router.replace(this.$route.query.redirect || '/')
|
||||
})
|
||||
} else {
|
||||
// 登录表单校验失败
|
||||
this.$message.error('表单校验失败')
|
||||
@@ -152,5 +190,231 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './style.scss';
|
||||
.page-login {
|
||||
@extend %unable-select;
|
||||
$backgroundColor: #F0F2F5;
|
||||
// ---
|
||||
background-color: $backgroundColor;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
// 层
|
||||
.page-login--layer {
|
||||
@extend %full;
|
||||
overflow: auto;
|
||||
}
|
||||
.page-login--layer-area {
|
||||
overflow: hidden;
|
||||
}
|
||||
// 时间
|
||||
.page-login--layer-time {
|
||||
font-size: 24em;
|
||||
font-weight: bold;
|
||||
color: rgba(0, 0, 0, 0.03);
|
||||
overflow: hidden;
|
||||
}
|
||||
// 登陆页面控件的容器
|
||||
.page-login--content {
|
||||
height: 100%;
|
||||
min-height: 500px;
|
||||
}
|
||||
// header
|
||||
.page-login--content-header {
|
||||
padding: 1em 0;
|
||||
.page-login--content-header-motto {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
color: $color-text-normal;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
span {
|
||||
color: $color-text-sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
// main
|
||||
.page-login--logo {
|
||||
width: 240px;
|
||||
margin-bottom: 2em;
|
||||
margin-top: -2em;
|
||||
}
|
||||
// 登录表单
|
||||
.page-login--form {
|
||||
width: 280px;
|
||||
// 卡片
|
||||
.el-card {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
// 登录按钮
|
||||
.button-login {
|
||||
width: 100%;
|
||||
}
|
||||
// 输入框左边的图表区域缩窄
|
||||
.el-input-group__prepend {
|
||||
padding: 0px 14px;
|
||||
}
|
||||
.login-code {
|
||||
height: 40px - 2px;
|
||||
display: block;
|
||||
margin: 0px -20px;
|
||||
border-top-right-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
// 登陆选项
|
||||
.page-login--options {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
font-size: 14px;
|
||||
color: $color-primary;
|
||||
margin-bottom: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.page-login--quick {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
// 快速选择用户面板
|
||||
.page-login--quick-user {
|
||||
@extend %flex-center-col;
|
||||
padding: 10px 0px;
|
||||
border-radius: 4px;
|
||||
&:hover {
|
||||
background-color: $color-bg;
|
||||
i {
|
||||
color: $color-text-normal;
|
||||
}
|
||||
span {
|
||||
color: $color-text-normal;
|
||||
}
|
||||
}
|
||||
i {
|
||||
font-size: 36px;
|
||||
color: $color-text-sub;
|
||||
}
|
||||
span {
|
||||
font-size: 12px;
|
||||
margin-top: 10px;
|
||||
color: $color-text-sub;
|
||||
}
|
||||
}
|
||||
// footer
|
||||
.page-login--content-footer {
|
||||
padding: 1em 0;
|
||||
.page-login--content-footer-options {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
a {
|
||||
color: $color-text-normal;
|
||||
margin: 0 1em;
|
||||
}
|
||||
}
|
||||
.page-login--content-footer-copyright {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
font-size: 12px;
|
||||
color: $color-text-normal;
|
||||
a {
|
||||
color: $color-text-normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 背景
|
||||
.circles {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
li {
|
||||
position: absolute;
|
||||
display: block;
|
||||
list-style: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #FFF;
|
||||
animation: animate 25s linear infinite;
|
||||
bottom: -200px;
|
||||
@keyframes animate {
|
||||
0%{
|
||||
transform: translateY(0) rotate(0deg);
|
||||
opacity: 1;
|
||||
border-radius: 0;
|
||||
}
|
||||
100%{
|
||||
transform: translateY(-1000px) rotate(720deg);
|
||||
opacity: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
&:nth-child(1) {
|
||||
left: 15%;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
left: 5%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation-delay: 2s;
|
||||
animation-duration: 12s;
|
||||
}
|
||||
&:nth-child(3) {
|
||||
left: 70%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation-delay: 4s;
|
||||
}
|
||||
&:nth-child(4) {
|
||||
left: 40%;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
animation-delay: 0s;
|
||||
animation-duration: 18s;
|
||||
}
|
||||
&:nth-child(5) {
|
||||
left: 65%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
&:nth-child(6) {
|
||||
left: 75%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
animation-delay: 3s;
|
||||
}
|
||||
&:nth-child(7) {
|
||||
left: 35%;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
animation-delay: 7s;
|
||||
}
|
||||
&:nth-child(8) {
|
||||
left: 50%;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
animation-delay: 15s;
|
||||
animation-duration: 45s;
|
||||
}
|
||||
&:nth-child(9) {
|
||||
left: 20%;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
animation-delay: 2s;
|
||||
animation-duration: 35s;
|
||||
}
|
||||
&:nth-child(10) {
|
||||
left: 85%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
animation-delay: 0s;
|
||||
animation-duration: 11s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
@import '~@/assets/style/public.scss';
|
||||
.login-page {
|
||||
background-color: #EDF4FA;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
// 层
|
||||
.layer {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
&.flex-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
// 背景
|
||||
.bg {
|
||||
canvas {
|
||||
display: block;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
// logo
|
||||
.logo-group {
|
||||
margin-top: -75px - 70px;
|
||||
position: relative;
|
||||
top: 75px;
|
||||
img {
|
||||
height: 140px;
|
||||
}
|
||||
}
|
||||
// 登录表单
|
||||
.form-group {
|
||||
width: 300px;
|
||||
// 重新设置卡片阴影
|
||||
.el-card {
|
||||
box-shadow: 0 0 8px 0 rgba(232,237,250,.6), 0 2px 4px 0 rgba(232,237,250,.5);
|
||||
.el-card__body {
|
||||
padding-top: 70px;
|
||||
}
|
||||
}
|
||||
// 登录按钮
|
||||
.button-login {
|
||||
width: 100%;
|
||||
}
|
||||
// 输入框左边的图表区域缩窄
|
||||
.el-input-group__prepend {
|
||||
padding: 0px 14px;
|
||||
}
|
||||
.login-code {
|
||||
height: 40px - 2px;
|
||||
display: block;
|
||||
margin: 0px -20px;
|
||||
border-top-right-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
}
|
||||
// 帮助按钮
|
||||
.button-help {
|
||||
width: 300px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.user-btn {
|
||||
@extend %flex-center-col;
|
||||
@extend %unable-select;
|
||||
padding: 10px 0px;
|
||||
border-radius: 4px;
|
||||
&:hover {
|
||||
background-color: $color-bg;
|
||||
i {
|
||||
color: $color-text-normal;
|
||||
}
|
||||
span {
|
||||
color: $color-text-normal;
|
||||
}
|
||||
}
|
||||
i {
|
||||
font-size: 36px;
|
||||
color: $color-text-sub;
|
||||
}
|
||||
span {
|
||||
font-size: 12px;
|
||||
margin-top: 10px;
|
||||
color: $color-text-sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,13 +41,9 @@ const service = axios.create({
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// 在请求发送之前做一些处理
|
||||
if (!(/^https:\/\/|http:\/\//.test(config.url))) {
|
||||
const token = util.cookies.get('token')
|
||||
if (token && token !== 'undefined') {
|
||||
// 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
|
||||
config.headers['X-Token'] = token
|
||||
}
|
||||
}
|
||||
const token = util.cookies.get('token')
|
||||
// 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
|
||||
config.headers['X-Token'] = token
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
|
||||
@@ -7,6 +7,8 @@ import 'flex.css'
|
||||
import '@/components'
|
||||
// svg 图标
|
||||
import '@/assets/svg-icons'
|
||||
// 过滤器
|
||||
import d2VueFiltersDate from '@d2-projects/vue-filters-date'
|
||||
// 功能插件
|
||||
import pluginError from '@/plugin/error'
|
||||
import pluginLog from '@/plugin/log'
|
||||
@@ -14,14 +16,21 @@ import pluginOpen from '@/plugin/open'
|
||||
|
||||
export default {
|
||||
async install (Vue, options) {
|
||||
// 设置为 false 以阻止 vue 在启动时生成生产提示。https://cn.vuejs.org/v2/api/#productionTip
|
||||
// 设置为 false 以阻止 vue 在启动时生成生产提示
|
||||
// https://cn.vuejs.org/v2/api/#productionTip
|
||||
Vue.config.productionTip = false
|
||||
// 当前环境
|
||||
Vue.prototype.$env = process.env.NODE_ENV
|
||||
// 当前的 baseUrl
|
||||
Vue.prototype.$baseUrl = process.env.BASE_URL
|
||||
// 当前版本
|
||||
Vue.prototype.$version = process.env.VUE_APP_VERSION
|
||||
// 构建时间
|
||||
Vue.prototype.$buildTime = process.env.VUE_APP_BUILD_TIME
|
||||
// Element
|
||||
Vue.use(ElementUI)
|
||||
// 过滤器 日期模块
|
||||
Vue.use(d2VueFiltersDate)
|
||||
// 插件
|
||||
Vue.use(pluginError)
|
||||
Vue.use(pluginLog)
|
||||
|
||||
+10
-8
@@ -29,21 +29,23 @@ router.beforeEach((to, from, next) => {
|
||||
// 关闭搜索面板
|
||||
store.commit('d2admin/search/set', false)
|
||||
// 验证当前路由所有的匹配中是否需要有登录验证的
|
||||
if (to.matched.some(r => r.meta.requiresAuth)) {
|
||||
if (to.matched.some(r => r.meta.auth)) {
|
||||
// 这里暂时将cookie里是否存有token作为验证是否登录的条件
|
||||
// 请根据自身业务需要修改
|
||||
const token = util.cookies.get('token')
|
||||
if (token && token !== 'undefined') {
|
||||
next()
|
||||
} else {
|
||||
// 将当前预计打开的页面完整地址临时存储 登录后继续跳转
|
||||
// 这个 cookie(redirect) 会在登录后自动删除
|
||||
util.cookies.set('redirect', to.fullPath)
|
||||
// 没有登录的时候跳转到登录界面
|
||||
// 携带上登陆成功之后需要跳转的页面完整路径
|
||||
next({
|
||||
name: 'login'
|
||||
name: 'login',
|
||||
query: {
|
||||
redirect: to.fullPath
|
||||
}
|
||||
})
|
||||
NProgress.done() // next(...)重定向不会触发router.afterEach钩子,需要手动hack一下
|
||||
// https://github.com/d2-projects/d2-admin/issues/138
|
||||
NProgress.done()
|
||||
}
|
||||
} else {
|
||||
// 不需要身份校验 直接通过
|
||||
@@ -56,9 +58,9 @@ router.afterEach(to => {
|
||||
NProgress.done()
|
||||
// 需要的信息
|
||||
const app = router.app
|
||||
const { name, params, query } = to
|
||||
const { name, params, query, fullPath } = to
|
||||
// 多页控制 打开新的页面
|
||||
app.$store.dispatch('d2admin/page/open', { name, params, query })
|
||||
app.$store.dispatch('d2admin/page/open', { name, params, query, fullPath })
|
||||
// 更改标题
|
||||
util.title(to.meta.title)
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ import demo from './modules/demo'
|
||||
|
||||
import layoutHeaderAside from '@/layout/header-aside'
|
||||
|
||||
const meta = { requiresAuth: true }
|
||||
const meta = { auth: true }
|
||||
|
||||
/**
|
||||
* 在主框架内显示
|
||||
|
||||
+2
-7
@@ -1,5 +1,3 @@
|
||||
import { version } from '../package'
|
||||
|
||||
export default {
|
||||
// 快捷键
|
||||
// 支持快捷键 例如 ctrl+shift+s
|
||||
@@ -18,17 +16,14 @@ export default {
|
||||
opened: [
|
||||
{
|
||||
name: 'index',
|
||||
fullPath: '/index',
|
||||
meta: {
|
||||
title: '首页',
|
||||
requiresAuth: false
|
||||
auth: false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// 版本
|
||||
releases: {
|
||||
version
|
||||
},
|
||||
// 菜单搜索
|
||||
search: {
|
||||
enable: true
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import util from '@/libs/util.js'
|
||||
import { AccountLogin } from '@/api/sys/login'
|
||||
import { AccountLogin } from '@api/sys.login'
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
@@ -10,45 +10,41 @@ export default {
|
||||
* @param {Object} param vm {Object} vue 实例
|
||||
* @param {Object} param username {String} 用户账号
|
||||
* @param {Object} param password {String} 密码
|
||||
* @param {Object} param route {Object} 登录成功后定向的路由对象
|
||||
* @param {Object} param route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式
|
||||
*/
|
||||
login ({ dispatch }, {
|
||||
vm,
|
||||
username,
|
||||
password,
|
||||
route = {
|
||||
name: 'index'
|
||||
}
|
||||
password
|
||||
}) {
|
||||
// 开始请求登录接口
|
||||
AccountLogin({
|
||||
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)
|
||||
})
|
||||
})
|
||||
.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')
|
||||
// 更新路由 尝试去获取 cookie 里保存的需要重定向的页面完整地址
|
||||
const path = util.cookies.get('redirect')
|
||||
// 根据是否存有重定向页面判断如何重定向
|
||||
vm.$router.replace(path ? { path } : route)
|
||||
// 删除 cookie 中保存的重定向页面
|
||||
util.cookies.remove('redirect')
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('err: ', err)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 注销用户并返回登录页面
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import db from '@/libs/db.js'
|
||||
import util from '@/libs/util.js'
|
||||
import util from '@/libs/util'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
/**
|
||||
* @description 检查路径是否存在 不存在的话初始化
|
||||
@@ -19,9 +19,16 @@ function pathInit ({
|
||||
}) {
|
||||
const uuid = util.cookies.get('uuid') || 'ghost-uuid'
|
||||
const currentPath = `${dbName}.${user ? `user.${uuid}` : 'public'}${path ? `.${path}` : ''}`
|
||||
const value = db.get(currentPath).value()
|
||||
const value = util.db.get(currentPath).value()
|
||||
// console.group('pathInit')
|
||||
// console.log('dbName', dbName)
|
||||
// console.log('path', path)
|
||||
// console.log('user', user)
|
||||
// console.log('defaultValue', defaultValue)
|
||||
// console.log('value', value)
|
||||
// console.groupEnd()
|
||||
if (!(value !== undefined && validator(value))) {
|
||||
db
|
||||
util.db
|
||||
.set(currentPath, defaultValue)
|
||||
.write()
|
||||
}
|
||||
@@ -45,7 +52,7 @@ export default {
|
||||
value = '',
|
||||
user = false
|
||||
}) {
|
||||
db.set(pathInit({
|
||||
util.db.set(pathInit({
|
||||
dbName,
|
||||
path,
|
||||
user
|
||||
@@ -66,12 +73,12 @@ export default {
|
||||
user = false
|
||||
}) {
|
||||
return new Promise(resolve => {
|
||||
resolve(db.get(pathInit({
|
||||
resolve(cloneDeep(util.db.get(pathInit({
|
||||
dbName,
|
||||
path,
|
||||
user,
|
||||
defaultValue
|
||||
})).value())
|
||||
})).value()))
|
||||
})
|
||||
},
|
||||
/**
|
||||
@@ -83,7 +90,7 @@ export default {
|
||||
user = false
|
||||
} = {}) {
|
||||
return new Promise(resolve => {
|
||||
resolve(db.get(pathInit({
|
||||
resolve(util.db.get(pathInit({
|
||||
dbName: 'database',
|
||||
path: '',
|
||||
user,
|
||||
@@ -100,7 +107,7 @@ export default {
|
||||
user = false
|
||||
} = {}) {
|
||||
return new Promise(resolve => {
|
||||
resolve(db.get(pathInit({
|
||||
resolve(util.db.get(pathInit({
|
||||
dbName: 'database',
|
||||
path: '',
|
||||
user,
|
||||
@@ -118,11 +125,11 @@ export default {
|
||||
*/
|
||||
databasePage (context, {
|
||||
vm,
|
||||
basis = 'name',
|
||||
basis = 'fullPath',
|
||||
user = false
|
||||
} = {}) {
|
||||
return new Promise(resolve => {
|
||||
resolve(db.get(pathInit({
|
||||
resolve(util.db.get(pathInit({
|
||||
dbName: 'database',
|
||||
path: `$page.${vm.$route[basis]}`,
|
||||
user,
|
||||
@@ -139,11 +146,11 @@ export default {
|
||||
*/
|
||||
databasePageClear (context, {
|
||||
vm,
|
||||
basis = 'name',
|
||||
basis = 'fullPath',
|
||||
user = false
|
||||
} = {}) {
|
||||
return new Promise(resolve => {
|
||||
resolve(db.get(pathInit({
|
||||
resolve(util.db.get(pathInit({
|
||||
dbName: 'database',
|
||||
path: `$page.${vm.$route[basis]}`,
|
||||
user,
|
||||
@@ -161,16 +168,16 @@ export default {
|
||||
*/
|
||||
pageSet (context, {
|
||||
vm,
|
||||
basis = 'name',
|
||||
basis = 'fullPath',
|
||||
user = false
|
||||
}) {
|
||||
return new Promise(resolve => {
|
||||
resolve(db.get(pathInit({
|
||||
resolve(util.db.get(pathInit({
|
||||
dbName: 'database',
|
||||
path: `$page.${vm.$route[basis]}.$data`,
|
||||
user,
|
||||
validator: () => false,
|
||||
defaultValue: vm.$data
|
||||
defaultValue: cloneDeep(vm.$data)
|
||||
})))
|
||||
})
|
||||
},
|
||||
@@ -183,16 +190,16 @@ export default {
|
||||
*/
|
||||
pageGet (context, {
|
||||
vm,
|
||||
basis = 'name',
|
||||
basis = 'fullPath',
|
||||
user = false
|
||||
}) {
|
||||
return new Promise(resolve => {
|
||||
resolve(db.get(pathInit({
|
||||
resolve(cloneDeep(util.db.get(pathInit({
|
||||
dbName: 'database',
|
||||
path: `$page.${vm.$route[basis]}.$data`,
|
||||
user,
|
||||
defaultValue: vm.$data
|
||||
})).value())
|
||||
defaultValue: cloneDeep(vm.$data)
|
||||
})).value()))
|
||||
})
|
||||
},
|
||||
/**
|
||||
@@ -204,11 +211,11 @@ export default {
|
||||
*/
|
||||
pageClear (context, {
|
||||
vm,
|
||||
basis = 'name',
|
||||
basis = 'fullPath',
|
||||
user = false
|
||||
}) {
|
||||
return new Promise(resolve => {
|
||||
resolve(db.get(pathInit({
|
||||
resolve(util.db.get(pathInit({
|
||||
dbName: 'database',
|
||||
path: `$page.${vm.$route[basis]}.$data`,
|
||||
user,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { remove, get } from 'lodash'
|
||||
import { get } from 'lodash'
|
||||
|
||||
// 设置文件
|
||||
import setting from '@/setting.js'
|
||||
@@ -34,14 +34,14 @@ export default {
|
||||
user: true
|
||||
}, { root: true })
|
||||
// 在处理函数中进行数据优化 过滤掉现在已经失效的页签或者已经改变了信息的页签
|
||||
// 以 name 字段为准
|
||||
// 以 fullPath 字段为准
|
||||
// 如果页面过多的话可能需要优化算法
|
||||
// valid 有效列表 1, 1, 0, 1 => 有效, 有效, 失效, 有效
|
||||
const valid = []
|
||||
// 处理数据
|
||||
state.opened = value.map(opened => {
|
||||
// 忽略首页
|
||||
if (opened.name === 'index') {
|
||||
if (opened.fullPath === '/index') {
|
||||
valid.push(1)
|
||||
return opened
|
||||
}
|
||||
@@ -80,19 +80,16 @@ export default {
|
||||
* @class opened
|
||||
* @description 更新页面列表上的某一项
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param { index, params, query } 路由信息
|
||||
* @param {Object} param { index, params, query, fullPath } 路由信息
|
||||
*/
|
||||
openedUpdate ({ state, commit, dispatch }, { index, params, query }) {
|
||||
openedUpdate ({ state, commit, dispatch }, { index, params, query, fullPath }) {
|
||||
return new Promise(async resolve => {
|
||||
// 更新页面列表某一项
|
||||
let page = state.opened[index]
|
||||
page.params = params || page.params
|
||||
page.query = query || page.query
|
||||
page.fullPath = fullPath || page.fullPath
|
||||
state.opened.splice(index, 1, page)
|
||||
// 增加缓存设置
|
||||
if (isKeepAlive(page)) {
|
||||
commit('keepAlivePush', page.name)
|
||||
}
|
||||
// 持久化
|
||||
await dispatch('opend2db')
|
||||
// end
|
||||
@@ -105,12 +102,13 @@ export default {
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param new tag info
|
||||
*/
|
||||
add ({ state, commit, dispatch }, { tag, params, query }) {
|
||||
add ({ state, commit, dispatch }, { tag, params, query, fullPath }) {
|
||||
return new Promise(async resolve => {
|
||||
// 设置新的 tag 在新打开一个以前没打开过的页面时使用
|
||||
let newTag = tag
|
||||
newTag.params = params || newTag.params
|
||||
newTag.query = query || newTag.query
|
||||
newTag.fullPath = fullPath || newTag.fullPath
|
||||
// 添加进当前显示的页面数组
|
||||
state.opened.push(newTag)
|
||||
// 如果这个页面需要缓存 将其添加到缓存设置
|
||||
@@ -127,25 +125,26 @@ export default {
|
||||
* @class current
|
||||
* @description 打开一个新的页面
|
||||
* @param {Object} state vuex state
|
||||
* @param {Object} param { name, params, query } 路由信息
|
||||
* @param {Object} param { name, params, query, fullPath } 路由信息
|
||||
*/
|
||||
open ({ state, commit, dispatch }, { name, params, query }) {
|
||||
open ({ state, commit, dispatch }, { name, params, query, fullPath }) {
|
||||
return new Promise(async resolve => {
|
||||
// 已经打开的页面
|
||||
let opened = state.opened
|
||||
// 判断此页面是否已经打开 并且记录位置
|
||||
let pageOpendIndex = 0
|
||||
const pageOpend = opened.find((page, index) => {
|
||||
const same = page.name === name
|
||||
const same = page.fullPath === fullPath
|
||||
pageOpendIndex = same ? index : pageOpendIndex
|
||||
return same
|
||||
})
|
||||
if (pageOpend) {
|
||||
// 页面以前打开过 但是新的页面可能 name 一样,参数不一样
|
||||
// 页面以前打开过
|
||||
await dispatch('openedUpdate', {
|
||||
index: pageOpendIndex,
|
||||
params,
|
||||
query
|
||||
query,
|
||||
fullPath
|
||||
})
|
||||
} else {
|
||||
// 页面以前没有打开过
|
||||
@@ -153,13 +152,14 @@ export default {
|
||||
// 如果这里没有找到 page 代表这个路由虽然在框架内 但是不参与标签页显示
|
||||
if (page) {
|
||||
await dispatch('add', {
|
||||
tag: page,
|
||||
tag: Object.assign({}, page),
|
||||
params,
|
||||
query
|
||||
query,
|
||||
fullPath
|
||||
})
|
||||
}
|
||||
}
|
||||
commit('currentSet', name)
|
||||
commit('currentSet', fullPath)
|
||||
// end
|
||||
resolve()
|
||||
})
|
||||
@@ -180,7 +180,7 @@ export default {
|
||||
// 去找一个新的页面
|
||||
let len = state.opened.length
|
||||
for (let i = 1; i < len; i++) {
|
||||
if (state.opened[i].name === tagName) {
|
||||
if (state.opened[i].fullPath === tagName) {
|
||||
if (i < len - 1) {
|
||||
newPage = state.opened[i + 1]
|
||||
} else {
|
||||
@@ -191,12 +191,12 @@ export default {
|
||||
}
|
||||
}
|
||||
// 找到这个页面在已经打开的数据里是第几个
|
||||
const index = state.opened.findIndex(page => page.name === tagName)
|
||||
const index = state.opened.findIndex(page => page.fullPath === tagName)
|
||||
if (index >= 0) {
|
||||
// 如果这个页面是缓存的页面 将其在缓存设置中删除
|
||||
commit('keepAliveRemove', state.opened[index].name)
|
||||
// 更新数据 删除关闭的页面
|
||||
state.opened.splice(index, 1)
|
||||
// 如果这个页面是缓存的页面 将其在缓存设置中删除
|
||||
commit('keepAliveRemove', tagName)
|
||||
}
|
||||
// 持久化
|
||||
await dispatch('opend2db')
|
||||
@@ -225,7 +225,7 @@ export default {
|
||||
const pageAim = pageSelect || state.current
|
||||
let currentIndex = 0
|
||||
state.opened.forEach((page, index) => {
|
||||
if (page.name === pageAim) {
|
||||
if (page.fullPath === pageAim) {
|
||||
currentIndex = index
|
||||
}
|
||||
})
|
||||
@@ -234,10 +234,8 @@ export default {
|
||||
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name))
|
||||
}
|
||||
state.current = pageAim
|
||||
if (vm && vm.$route.name !== pageAim) {
|
||||
vm.$router.push({
|
||||
name: pageAim
|
||||
})
|
||||
if (vm && vm.$route.fullPath !== pageAim) {
|
||||
vm.$router.push(pageAim)
|
||||
}
|
||||
// 持久化
|
||||
await dispatch('opend2db')
|
||||
@@ -256,7 +254,7 @@ export default {
|
||||
const pageAim = pageSelect || state.current
|
||||
let currentIndex = 0
|
||||
state.opened.forEach((page, index) => {
|
||||
if (page.name === pageAim) {
|
||||
if (page.fullPath === pageAim) {
|
||||
currentIndex = index
|
||||
}
|
||||
})
|
||||
@@ -264,10 +262,8 @@ export default {
|
||||
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name))
|
||||
// 设置当前的页面
|
||||
state.current = pageAim
|
||||
if (vm && vm.$route.name !== pageAim) {
|
||||
vm.$router.push({
|
||||
name: pageAim
|
||||
})
|
||||
if (vm && vm.$route.fullPath !== pageAim) {
|
||||
vm.$router.push(pageAim)
|
||||
}
|
||||
// 持久化
|
||||
await dispatch('opend2db')
|
||||
@@ -286,7 +282,7 @@ export default {
|
||||
const pageAim = pageSelect || state.current
|
||||
let currentIndex = 0
|
||||
state.opened.forEach((page, index) => {
|
||||
if (page.name === pageAim) {
|
||||
if (page.fullPath === pageAim) {
|
||||
currentIndex = index
|
||||
}
|
||||
})
|
||||
@@ -299,10 +295,8 @@ export default {
|
||||
}
|
||||
// 设置新的页面
|
||||
state.current = pageAim
|
||||
if (vm && vm.$route.name !== pageAim) {
|
||||
vm.$router.push({
|
||||
name: pageAim
|
||||
})
|
||||
if (vm && vm.$route.fullPath !== pageAim) {
|
||||
vm.$router.push(pageAim)
|
||||
}
|
||||
// 持久化
|
||||
await dispatch('opend2db')
|
||||
@@ -349,8 +343,12 @@ export default {
|
||||
*/
|
||||
keepAliveRemove (state, name) {
|
||||
const list = [ ...state.keepAlive ]
|
||||
remove(list, item => item === name)
|
||||
state.keepAlive = list
|
||||
const index = list.findIndex(item => item === name)
|
||||
|
||||
if (index !== -1) {
|
||||
list.splice(index, 1)
|
||||
state.keepAlive = list
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description 增加一个页面的缓存设置
|
||||
@@ -360,7 +358,7 @@ export default {
|
||||
keepAlivePush (state, name) {
|
||||
const keep = [ ...state.keepAlive ]
|
||||
keep.push(name)
|
||||
state.keepAlive = Array.from(new Set(keep))
|
||||
state.keepAlive = keep
|
||||
},
|
||||
/**
|
||||
* @description 清空页面缓存设置
|
||||
@@ -371,12 +369,12 @@ export default {
|
||||
},
|
||||
/**
|
||||
* @class current
|
||||
* @description 设置当前激活的页面 name
|
||||
* @description 设置当前激活的页面 fullPath
|
||||
* @param {Object} state vuex state
|
||||
* @param {String} name new name
|
||||
* @param {String} fullPath new fullPath
|
||||
*/
|
||||
currentSet (state, name) {
|
||||
state.current = name
|
||||
currentSet (state, fullPath) {
|
||||
state.current = fullPath
|
||||
},
|
||||
/**
|
||||
* @class pool
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
import util from '@/libs/util.js'
|
||||
import setting from '@/setting.js'
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
// D2Admin 版本
|
||||
version: setting.releases.version
|
||||
},
|
||||
mutations: {
|
||||
/**
|
||||
* @description 显示版本信息
|
||||
* @param {Object} state vuex state
|
||||
*/
|
||||
versionShow (state) {
|
||||
util.log.capsule('D2Admin', `v${state.version}`)
|
||||
versionShow () {
|
||||
util.log.capsule('D2Admin', `v${process.env.VUE_APP_VERSION}`)
|
||||
console.log('Github https://github.com/d2-projects/d2-admin')
|
||||
console.log('Doc https://doc.d2admin.fairyever.com/zh/')
|
||||
console.log('请不要吝啬您的 star,谢谢 ~')
|
||||
|
||||
@@ -48,12 +48,25 @@ export default {
|
||||
load ({ state, commit, dispatch }) {
|
||||
return new Promise(async resolve => {
|
||||
// store 赋值
|
||||
state.activeName = await dispatch('d2admin/db/get', {
|
||||
let activeName = await dispatch('d2admin/db/get', {
|
||||
dbName: 'sys',
|
||||
path: 'theme.activeName',
|
||||
defaultValue: state.list[0].name,
|
||||
user: true
|
||||
}, { root: true })
|
||||
// 检查这个主题在主题列表里是否存在
|
||||
if (state.list.find(e => e.name === activeName)) {
|
||||
state.activeName = activeName
|
||||
} else {
|
||||
state.activeName = state.list[0].name
|
||||
// 持久化
|
||||
await dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'theme.activeName',
|
||||
value: state.activeName,
|
||||
user: true
|
||||
}, { root: true })
|
||||
}
|
||||
// 将 vuex 中的主题应用到 dom
|
||||
commit('dom')
|
||||
// end
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
||||
|
||||
// 拼接路径
|
||||
const resolve = dir => require('path').join(__dirname, dir)
|
||||
|
||||
// 增加环境变量
|
||||
process.env.VUE_APP_VERSION = require('./package.json').version
|
||||
process.env.VUE_APP_BUILD_TIME = require('dayjs')().format('YYYY-M-D HH:mm:ss')
|
||||
|
||||
// 基础路径 注意发布之前要先修改这里
|
||||
let baseUrl = '/'
|
||||
|
||||
@@ -10,11 +16,52 @@ module.exports = {
|
||||
devServer: {
|
||||
publicPath: baseUrl // 和 baseUrl 保持一致
|
||||
},
|
||||
css: {
|
||||
loaderOptions: {
|
||||
// 设置 scss 公用变量文件
|
||||
sass: {
|
||||
data: `@import '~@/assets/style/public.scss';`
|
||||
}
|
||||
}
|
||||
},
|
||||
// 默认设置: https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-service/lib/config/base.js
|
||||
chainWebpack: config => {
|
||||
/**
|
||||
* 删除懒加载模块的 prefetch preload,降低带宽压力
|
||||
* https://cli.vuejs.org/zh/guide/html-and-static-assets.html#prefetch
|
||||
* https://cli.vuejs.org/zh/guide/html-and-static-assets.html#preload
|
||||
* 而且预渲染时生成的 prefetch 标签是 modern 版本的,低版本浏览器是不需要的
|
||||
*/
|
||||
config.plugins
|
||||
.delete('prefetch')
|
||||
.delete('preload')
|
||||
// 解决 cli3 热更新失效 https://github.com/vuejs/vue-cli/issues/1559
|
||||
config.resolve
|
||||
.symlinks(true)
|
||||
config
|
||||
// 开发环境
|
||||
.when(process.env.NODE_ENV === 'development',
|
||||
// sourcemap不包含列信息
|
||||
config => config.devtool('cheap-source-map')
|
||||
)
|
||||
// 非开发环境
|
||||
.when(process.env.NODE_ENV !== 'development', config => {
|
||||
config.optimization
|
||||
.minimizer([
|
||||
new UglifyJsPlugin({
|
||||
uglifyOptions: {
|
||||
// 移除 console
|
||||
// 其它优化选项 https://segmentfault.com/a/1190000010874406
|
||||
compress: {
|
||||
warnings: false,
|
||||
drop_console: true,
|
||||
drop_debugger: true,
|
||||
pure_funcs: ['console.log']
|
||||
}
|
||||
}
|
||||
})
|
||||
])
|
||||
})
|
||||
// markdown
|
||||
config.module
|
||||
.rule('md')
|
||||
@@ -52,10 +99,21 @@ module.exports = {
|
||||
// 重新设置 alias
|
||||
config.resolve.alias
|
||||
.set('@', resolve('src'))
|
||||
.set('@api', resolve('src/api'))
|
||||
// node
|
||||
config.node
|
||||
.set('__dirname', true)
|
||||
.set('__filename', true)
|
||||
// babel-polyfill 加入 entry
|
||||
const entry = config.entry('app')
|
||||
entry
|
||||
.add('babel-polyfill')
|
||||
.end()
|
||||
// 判断环境加入模拟数据
|
||||
if (process.env.VUE_APP_BUILD_MODE !== 'nomock') {
|
||||
entry
|
||||
.add('@/mock')
|
||||
.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user