Compare commits

...

11 Commits

Author SHA1 Message Date
Pan
e7f626f015 [release] 3.2.0 2017-12-08 18:20:15 +08:00
Pan
b53d0945ab fix(dndList): fixed the name same as router 2017-12-08 18:09:15 +08:00
Pan
ca75f7bcbc perf(tagsView):split to single modules 2017-12-08 16:17:40 +08:00
lvsmart
b7939165d1 get real version from node_modules 2017-12-08 11:49:34 +08:00
Pan
ebc2ac08b7 add(inlineEditable): add the calcel btn to restore the title 2017-12-08 11:07:20 +08:00
Pan
a9d2978c31 perf[permission]: set replace: true so the navigation will not leave a history record 2017-12-07 17:33:30 +08:00
Pan
a4597887ac style:refine css 2017-12-07 16:03:07 +08:00
Pan
44b180a7b3 [release] 3.1.1 2017-12-06 14:19:06 +08:00
Pan
acebaeae0c perf(i18n): add generateTitle to utils 2017-12-06 14:18:28 +08:00
Pan
d09923ff4f fix[sidebar]:fixed when sidebar item only has one children but nested #327 2017-12-05 18:42:15 +08:00
Pan
fc1a13d10b [release] 3.1.0 2017-12-05 11:41:57 +08:00
17 changed files with 117 additions and 74 deletions

View File

@@ -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",

View File

@@ -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)
} }
} }
} }

View File

@@ -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 {

View File

@@ -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(() => {

View File

@@ -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,

View File

@@ -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
}) })

View File

@@ -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])
})
} }
} }
} }

View 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

View File

@@ -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
View 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
}

View File

@@ -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]
}

View File

@@ -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 {

View File

@@ -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
} }
} }
} }

View File

@@ -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>

View File

@@ -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()

View File

@@ -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>

View File

@@ -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() {