Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e7f626f015 | ||
|
b53d0945ab | ||
|
ca75f7bcbc | ||
|
b7939165d1 | ||
|
ebc2ac08b7 | ||
|
a9d2978c31 | ||
|
a4597887ac | ||
|
44b180a7b3 | ||
|
acebaeae0c | ||
|
d09923ff4f | ||
|
fc1a13d10b |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vue-element-admin",
|
"name": "vue-element-admin",
|
||||||
"version": "3.0.0",
|
"version": "3.2.0",
|
||||||
"description": "A Vue.js admin",
|
"description": "A Vue.js admin",
|
||||||
"author": "Pan <panfree23@gmail.com>",
|
"author": "Pan <panfree23@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@@ -10,6 +10,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { generateTitle } from '@/utils/i18n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
created() {
|
created() {
|
||||||
this.getBreadcrumb()
|
this.getBreadcrumb()
|
||||||
@@ -25,6 +27,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
generateTitle,
|
||||||
getBreadcrumb() {
|
getBreadcrumb() {
|
||||||
let matched = this.$route.matched.filter(item => item.name)
|
let matched = this.$route.matched.filter(item => item.name)
|
||||||
const first = matched[0]
|
const first = matched[0]
|
||||||
@@ -32,9 +35,6 @@ export default {
|
|||||||
matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
|
matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
|
||||||
}
|
}
|
||||||
this.levelList = matched
|
this.levelList = matched
|
||||||
},
|
|
||||||
generateTitle(title) {
|
|
||||||
return this.$t('route.' + title)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,9 +6,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getVersion } from '@/utils/index.js'
|
|
||||||
|
|
||||||
const version = getVersion('element-ui') // element-ui version from package.json
|
const version = require('element-ui/package.json').version // element-ui version from node_modules
|
||||||
const ORIGINAL_THEME = '#409EFF' // default color
|
const ORIGINAL_THEME = '#409EFF' // default color
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@@ -26,7 +26,7 @@ router.beforeEach((to, from, next) => {
|
|||||||
const roles = res.data.role
|
const roles = res.data.role
|
||||||
store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
|
store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
|
||||||
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
|
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
|
||||||
next({ ...to }) // hack方法 确保addRoutes已完成
|
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,replace: true so the navigation will not leave a history record
|
||||||
})
|
})
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
store.dispatch('FedLogOut').then(() => {
|
store.dispatch('FedLogOut').then(() => {
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
const getters = {
|
const getters = {
|
||||||
sidebar: state => state.app.sidebar,
|
sidebar: state => state.app.sidebar,
|
||||||
language: state => state.app.language,
|
language: state => state.app.language,
|
||||||
visitedViews: state => state.app.visitedViews,
|
visitedViews: state => state.tagsView.visitedViews,
|
||||||
cachedViews: state => state.app.cachedViews,
|
cachedViews: state => state.tagsView.cachedViews,
|
||||||
token: state => state.user.token,
|
token: state => state.user.token,
|
||||||
avatar: state => state.user.avatar,
|
avatar: state => state.user.avatar,
|
||||||
name: state => state.user.name,
|
name: state => state.user.name,
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import app from './modules/app'
|
import app from './modules/app'
|
||||||
import user from './modules/user'
|
|
||||||
import permission from './modules/permission'
|
import permission from './modules/permission'
|
||||||
|
import tagsView from './modules/tagsView'
|
||||||
|
import user from './modules/user'
|
||||||
import getters from './getters'
|
import getters from './getters'
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
@@ -10,8 +11,9 @@ Vue.use(Vuex)
|
|||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
modules: {
|
modules: {
|
||||||
app,
|
app,
|
||||||
user,
|
permission,
|
||||||
permission
|
tagsView,
|
||||||
|
user
|
||||||
},
|
},
|
||||||
getters
|
getters
|
||||||
})
|
})
|
||||||
|
@@ -5,9 +5,7 @@ const app = {
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
opened: !+Cookies.get('sidebarStatus')
|
opened: !+Cookies.get('sidebarStatus')
|
||||||
},
|
},
|
||||||
language: Cookies.get('language') || 'zh',
|
language: Cookies.get('language') || 'zh'
|
||||||
visitedViews: [],
|
|
||||||
cachedViews: []
|
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
TOGGLE_SIDEBAR: state => {
|
TOGGLE_SIDEBAR: state => {
|
||||||
@@ -21,32 +19,6 @@ const app = {
|
|||||||
SET_LANGUAGE: (state, language) => {
|
SET_LANGUAGE: (state, language) => {
|
||||||
state.language = language
|
state.language = language
|
||||||
Cookies.set('language', language)
|
Cookies.set('language', language)
|
||||||
},
|
|
||||||
ADD_VISITED_VIEWS: (state, view) => {
|
|
||||||
if (state.visitedViews.some(v => v.path === view.path)) return
|
|
||||||
state.visitedViews.push({
|
|
||||||
name: view.name,
|
|
||||||
path: view.path,
|
|
||||||
title: view.meta.title || 'no-name'
|
|
||||||
})
|
|
||||||
if (!view.meta.noCache) {
|
|
||||||
state.cachedViews.push(view.name)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DEL_VISITED_VIEWS: (state, view) => {
|
|
||||||
for (const [i, v] of state.visitedViews.entries()) {
|
|
||||||
if (v.path === view.path) {
|
|
||||||
state.visitedViews.splice(i, 1)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const i of state.cachedViews) {
|
|
||||||
if (i === view.name) {
|
|
||||||
const index = state.cachedViews.indexOf(i)
|
|
||||||
state.cachedViews.splice(index, 1)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@@ -55,15 +27,6 @@ const app = {
|
|||||||
},
|
},
|
||||||
setLanguage({ commit }, language) {
|
setLanguage({ commit }, language) {
|
||||||
commit('SET_LANGUAGE', language)
|
commit('SET_LANGUAGE', language)
|
||||||
},
|
|
||||||
addVisitedViews({ commit }, view) {
|
|
||||||
commit('ADD_VISITED_VIEWS', view)
|
|
||||||
},
|
|
||||||
delVisitedViews({ commit, state }, view) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
commit('DEL_VISITED_VIEWS', view)
|
|
||||||
resolve([...state.visitedViews])
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
47
src/store/modules/tagsView.js
Normal file
47
src/store/modules/tagsView.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
const tagsView = {
|
||||||
|
state: {
|
||||||
|
visitedViews: [],
|
||||||
|
cachedViews: []
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
ADD_VISITED_VIEWS: (state, view) => {
|
||||||
|
if (state.visitedViews.some(v => v.path === view.path)) return
|
||||||
|
state.visitedViews.push({
|
||||||
|
name: view.name,
|
||||||
|
path: view.path,
|
||||||
|
title: view.meta.title || 'no-name'
|
||||||
|
})
|
||||||
|
if (!view.meta.noCache) {
|
||||||
|
state.cachedViews.push(view.name)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DEL_VISITED_VIEWS: (state, view) => {
|
||||||
|
for (const [i, v] of state.visitedViews.entries()) {
|
||||||
|
if (v.path === view.path) {
|
||||||
|
state.visitedViews.splice(i, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const i of state.cachedViews) {
|
||||||
|
if (i === view.name) {
|
||||||
|
const index = state.cachedViews.indexOf(i)
|
||||||
|
state.cachedViews.splice(index, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
addVisitedViews({ commit }, view) {
|
||||||
|
commit('ADD_VISITED_VIEWS', view)
|
||||||
|
},
|
||||||
|
delVisitedViews({ commit, state }, view) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
commit('DEL_VISITED_VIEWS', view)
|
||||||
|
resolve([...state.visitedViews])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default tagsView
|
@@ -98,10 +98,11 @@ div:focus{
|
|||||||
|
|
||||||
code {
|
code {
|
||||||
background: #eef1f6;
|
background: #eef1f6;
|
||||||
padding: 15px 10px;
|
padding: 15px 16px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 36px;
|
line-height: 36px;
|
||||||
|
font-size: 14px;
|
||||||
a {
|
a {
|
||||||
color: #337ab7;
|
color: #337ab7;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
3
src/utils/i18n.js
Normal file
3
src/utils/i18n.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function generateTitle(title) {
|
||||||
|
return this.$t('route.' + title) // $t :this method from vue-i18n ,inject in @/lang/index.js
|
||||||
|
}
|
@@ -265,9 +265,3 @@ export function deepClone(source) {
|
|||||||
}
|
}
|
||||||
return targetObj
|
return targetObj
|
||||||
}
|
}
|
||||||
|
|
||||||
// get dependencies verison from package.json
|
|
||||||
export function getVersion(name) {
|
|
||||||
const p = require('../../package')
|
|
||||||
return p.dependencies[name]
|
|
||||||
}
|
|
||||||
|
@@ -14,7 +14,7 @@ import DndList from '@/components/DndList'
|
|||||||
import { fetchList } from '@/api/article'
|
import { fetchList } from '@/api/article'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'dnd-list-demo',
|
name: 'dndList-demo',
|
||||||
components: { DndList },
|
components: { DndList },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@@ -11,7 +11,7 @@ export default {
|
|||||||
name: 'TableMain',
|
name: 'TableMain',
|
||||||
computed: {
|
computed: {
|
||||||
cachedViews() {
|
cachedViews() {
|
||||||
return this.$store.state.app.cachedViews
|
return this.$store.state.tagsView.cachedViews
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -35,14 +35,18 @@
|
|||||||
|
|
||||||
<el-table-column min-width="300px" label="标题">
|
<el-table-column min-width="300px" label="标题">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input v-show="scope.row.edit" size="small" v-model="scope.row.title"></el-input>
|
<template v-if="scope.row.edit">
|
||||||
<span v-show="!scope.row.edit">{{ scope.row.title }}</span>
|
<el-input class="edit-input" size="small" v-model="scope.row.title"></el-input>
|
||||||
|
<el-button class='cancel-btn' size="small" icon="el-icon-refresh" type="warning" @click="cancelEdit(scope.row)">cancel</el-button>
|
||||||
|
</template>
|
||||||
|
<span v-else>{{ scope.row.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column align="center" label="编辑" width="120">
|
<el-table-column align="center" label="编辑" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button :type="scope.row.edit?'success':'primary'" @click='scope.row.edit=!scope.row.edit' size="small" icon="edit">{{scope.row.edit?'完成':'编辑'}}</el-button>
|
<el-button v-if="scope.row.edit" type="success" @click="confirmEdit(scope.row)" size="small" icon="el-icon-circle-check-outline">完成</el-button>
|
||||||
|
<el-button v-else type="primary" @click='scope.row.edit=!scope.row.edit' size="small" icon="el-icon-edit">编辑</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
@@ -84,12 +88,40 @@ export default {
|
|||||||
fetchList(this.listQuery).then(response => {
|
fetchList(this.listQuery).then(response => {
|
||||||
const items = response.data.items
|
const items = response.data.items
|
||||||
this.list = items.map(v => {
|
this.list = items.map(v => {
|
||||||
this.$set(v, 'edit', false)
|
this.$set(v, 'edit', false) // https://vuejs.org/v2/guide/reactivity.html
|
||||||
|
v.originalTitle = v.title // will be used when user click the cancel botton
|
||||||
return v
|
return v
|
||||||
})
|
})
|
||||||
this.listLoading = false
|
this.listLoading = false
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
cancelEdit(row) {
|
||||||
|
row.title = row.originalTitle
|
||||||
|
row.edit = false
|
||||||
|
this.$message({
|
||||||
|
message: 'The title has been restored to the original value',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
confirmEdit(row) {
|
||||||
|
row.edit = false
|
||||||
|
row.originalTitle = row.title
|
||||||
|
this.$message({
|
||||||
|
message: 'The title has been edited',
|
||||||
|
type: 'success'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.edit-input {
|
||||||
|
padding-right: 100px;
|
||||||
|
}
|
||||||
|
.cancel-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 15px;
|
||||||
|
top: 13px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@@ -13,7 +13,8 @@ export default {
|
|||||||
name: 'AppMain',
|
name: 'AppMain',
|
||||||
computed: {
|
computed: {
|
||||||
cachedViews() {
|
cachedViews() {
|
||||||
return this.$store.state.app.cachedViews
|
// console.log(this.$store.state.tagsView.cachedViews)
|
||||||
|
return this.$store.state.tagsView.cachedViews
|
||||||
}
|
}
|
||||||
// key() {
|
// key() {
|
||||||
// return this.$route.name !== undefined ? this.$route.name + +new Date() : this.$route + +new Date()
|
// return this.$route.name !== undefined ? this.$route.name + +new Date() : this.$route + +new Date()
|
||||||
|
@@ -1,21 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="menu-wrapper">
|
<div class="menu-wrapper">
|
||||||
<template v-for="item in routes">
|
<template v-for="item in routes" v-if="!item.hidden&&item.children">
|
||||||
|
|
||||||
<router-link v-if="!item.hidden&&item.children&&item.children.length===1" :to="item.path+'/'+item.children[0].path" :key="item.children[0].name">
|
<router-link v-if="item.children.length===1 && !item.children[0].children" :to="item.path+'/'+item.children[0].path" :key="item.children[0].name">
|
||||||
<el-menu-item :index="item.path+'/'+item.children[0].path" class='submenu-title-noDropdown'>
|
<el-menu-item :index="item.path+'/'+item.children[0].path" class='submenu-title-noDropdown'>
|
||||||
<svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon>
|
<svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon>
|
||||||
<span v-if="item.children[0].meta&&item.children[0].meta.title">{{generateTitle(item.children[0].meta.title)}}</span>
|
<span v-if="item.children[0].meta&&item.children[0].meta.title">{{generateTitle(item.children[0].meta.title)}}</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<el-submenu v-if="!item.hidden&&item.children&&item.children.length>1" :index="item.name||item.path" :key="item.name">
|
<el-submenu v-else :index="item.name||item.path" :key="item.name">
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
<svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
|
<svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
|
||||||
<span v-if="item.meta&&item.meta.title">{{generateTitle(item.meta.title)}}</span>
|
<span v-if="item.meta&&item.meta.title">{{generateTitle(item.meta.title)}}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="!child.hidden" v-for="child in item.children">
|
<template v-for="child in item.children" v-if="!child.hidden">
|
||||||
<sidebar-item class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :key="child.path"></sidebar-item>
|
<sidebar-item class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :key="child.path"></sidebar-item>
|
||||||
|
|
||||||
<router-link v-else :to="item.path+'/'+child.path" :key="child.name">
|
<router-link v-else :to="item.path+'/'+child.path" :key="child.name">
|
||||||
@@ -32,6 +32,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { generateTitle } from '@/utils/i18n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SidebarItem',
|
name: 'SidebarItem',
|
||||||
props: {
|
props: {
|
||||||
@@ -40,9 +42,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
generateTitle(title) {
|
generateTitle
|
||||||
return this.$t('route.' + title)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<scroll-pane class='tags-view-container' ref='scrollPane'>
|
<scroll-pane class='tags-view-container' ref='scrollPane'>
|
||||||
<router-link ref='tag' class="tags-view-item" :class="isActive(tag)?'active':''" v-for="tag in Array.from(visitedViews)" :to="tag.path":key="tag.path">
|
<router-link ref='tag' class="tags-view-item" :class="isActive(tag)?'active':''" v-for="tag in Array.from(visitedViews)" :to="tag.path":key="tag.path">
|
||||||
{{$t('route.'+tag.title)}}
|
{{generateTitle(tag.title)}}
|
||||||
<span class='el-icon-close' @click='closeViewTags(tag,$event)'></span>
|
<span class='el-icon-close' @click='closeViewTags(tag,$event)'></span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</scroll-pane>
|
</scroll-pane>
|
||||||
@@ -9,18 +9,20 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ScrollPane from '@/components/ScrollPane'
|
import ScrollPane from '@/components/ScrollPane'
|
||||||
|
import { generateTitle } from '@/utils/i18n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { ScrollPane },
|
components: { ScrollPane },
|
||||||
computed: {
|
computed: {
|
||||||
visitedViews() {
|
visitedViews() {
|
||||||
return this.$store.state.app.visitedViews
|
return this.$store.state.tagsView.visitedViews
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.addViewTags()
|
this.addViewTags()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
generateTitle,
|
||||||
closeViewTags(view, $event) {
|
closeViewTags(view, $event) {
|
||||||
this.$store.dispatch('delVisitedViews', view).then((views) => {
|
this.$store.dispatch('delVisitedViews', view).then((views) => {
|
||||||
if (this.isActive(view)) {
|
if (this.isActive(view)) {
|
||||||
@@ -61,7 +63,6 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route() {
|
$route() {
|
||||||
|
Reference in New Issue
Block a user