Commit 2786b410 authored by Junling Bu's avatar Junling Bu
Browse files

feat[litemall-admin]: 更新vue-element-admin到4.3.0

parent 92cfea63
{ {
"name": "litemall-admin", "name": "litemall-admin",
"version": "1.0.0", "version": "1.0.0",
"description": "litemall-admin basing on vue-element-admin 4.2.1", "description": "litemall-admin basing on vue-element-admin 4.3.0",
"author": "linlinjava <linlinjava@163.com>", "author": "linlinjava <linlinjava@163.com>",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
...@@ -50,13 +50,14 @@ ...@@ -50,13 +50,14 @@
"clipboard": "2.0.4", "clipboard": "2.0.4",
"connect": "3.6.6", "connect": "3.6.6",
"echarts": "4.2.1", "echarts": "4.2.1",
"element-ui": "2.12.0", "element-ui": "2.13.2",
"file-saver": "1.3.8", "file-saver": "1.3.8",
"js-cookie": "2.2.0", "js-cookie": "2.2.0",
"normalize.css": "7.0.0", "normalize.css": "7.0.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"path-to-regexp": "2.4.0", "path-to-regexp": "2.4.0",
"screenfull": "4.2.0", "screenfull": "4.2.0",
"script-loader": "0.7.2",
"vue": "2.6.10", "vue": "2.6.10",
"vue-count-to": "1.0.13", "vue-count-to": "1.0.13",
"vue-router": "3.0.2", "vue-router": "3.0.2",
...@@ -83,11 +84,10 @@ ...@@ -83,11 +84,10 @@
"html-webpack-plugin": "3.2.0", "html-webpack-plugin": "3.2.0",
"husky": "1.3.1", "husky": "1.3.1",
"lint-staged": "8.1.5", "lint-staged": "8.1.5",
"node-sass": "^4.9.0", "sass": "^1.26.2",
"runjs": "^4.3.2", "runjs": "^4.3.2",
"sass-loader": "^7.1.0", "sass-loader": "^7.1.0",
"script-ext-html-webpack-plugin": "2.1.3", "script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",
"serve-static": "^1.13.2", "serve-static": "^1.13.2",
"svg-sprite-loader": "4.1.3", "svg-sprite-loader": "4.1.3",
"svgo": "1.2.0", "svgo": "1.2.0",
......
...@@ -42,7 +42,7 @@ export default { ...@@ -42,7 +42,7 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/deep/ .el-badge__content.is-fixed.is-dot { ::v-deep .el-badge__content.is-fixed.is-dot {
right: 5px; right: 5px;
top: 10px; top: 10px;
} }
......
<template> <template>
<el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll"> <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
<slot/> <slot />
</el-scrollbar> </el-scrollbar>
</template> </template>
...@@ -80,7 +80,7 @@ export default { ...@@ -80,7 +80,7 @@ export default {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
/deep/ { ::v-deep {
.el-scrollbar__bar { .el-scrollbar__bar {
bottom: 0px; bottom: 0px;
} }
......
...@@ -28,7 +28,7 @@ router.beforeEach((to, from, next) => { ...@@ -28,7 +28,7 @@ router.beforeEach((to, from, next) => {
store.dispatch('GetUserInfo').then(res => { // 拉取user_info store.dispatch('GetUserInfo').then(res => { // 拉取user_info
const perms = res.data.data.perms // note: perms must be a array! such as: ['GET /aaa','POST /bbb'] const perms = res.data.data.perms // note: perms must be a array! such as: ['GET /aaa','POST /bbb']
store.dispatch('GenerateRoutes', { perms }).then(() => { // 根据perms权限生成可访问的路由表 store.dispatch('GenerateRoutes', { perms }).then(() => { // 根据perms权限生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表 router.addRoutes(store.getters.addRoutes) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
}) })
}).catch((err) => { }).catch((err) => {
......
...@@ -24,14 +24,14 @@ import Layout from '@/views/layout/Layout' ...@@ -24,14 +24,14 @@ import Layout from '@/views/layout/Layout'
noCache: true if true ,the page will no be cached(default is false) noCache: true if true ,the page will no be cached(default is false)
} }
**/ **/
export const constantRouterMap = [ export const constantRoutes = [
{ {
path: '/redirect', path: '/redirect',
component: Layout, component: Layout,
hidden: true, hidden: true,
children: [ children: [
{ {
path: '/redirect/:path*', path: '/redirect/:path(.*)',
component: () => import('@/views/redirect/index') component: () => import('@/views/redirect/index')
} }
] ]
...@@ -71,13 +71,7 @@ export const constantRouterMap = [ ...@@ -71,13 +71,7 @@ export const constantRouterMap = [
} }
] ]
export default new Router({ export const asyncRoutes = [
// mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRouterMap
})
export const asyncRouterMap = [
{ {
path: '/user', path: '/user',
component: Layout, component: Layout,
...@@ -612,3 +606,19 @@ export const asyncRouterMap = [ ...@@ -612,3 +606,19 @@ export const asyncRouterMap = [
{ path: '*', redirect: '/404', hidden: true } { path: '*', redirect: '/404', hidden: true }
] ]
const createRouter = () => new Router({
// mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
const router = createRouter()
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router
...@@ -8,12 +8,9 @@ const getters = { ...@@ -8,12 +8,9 @@ const getters = {
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,
introduction: state => state.user.introduction,
status: state => state.user.status,
roles: state => state.user.roles, roles: state => state.user.roles,
perms: state => state.user.perms, perms: state => state.user.perms,
setting: state => state.user.setting, permission_routes: state => state.permission.routes,
permission_routers: state => state.permission.routers, addRoutes: state => state.permission.addRoutes
addRouters: state => state.permission.addRouters
} }
export default getters export default getters
import { asyncRouterMap, constantRouterMap } from '@/router' import { asyncRoutes, constantRoutes } from '@/router'
/** /**
* 通过meta.perms判断是否与当前用户权限匹配 * 通过meta.perms判断是否与当前用户权限匹配
...@@ -15,16 +15,16 @@ function hasPermission(perms, route) { ...@@ -15,16 +15,16 @@ function hasPermission(perms, route) {
/** /**
* 递归过滤异步路由表,返回符合用户角色权限的路由表 * 递归过滤异步路由表,返回符合用户角色权限的路由表
* @param routes asyncRouterMap * @param routes asyncRoutes
* @param perms * @param perms
*/ */
function filterAsyncRouter(routes, perms) { function filterAsyncRoutes(routes, perms) {
const res = [] const res = []
routes.forEach(route => { routes.forEach(route => {
const tmp = { ...route } const tmp = { ...route }
if (tmp.children) { if (tmp.children) {
tmp.children = filterAsyncRouter(tmp.children, perms) tmp.children = filterAsyncRoutes(tmp.children, perms)
if (tmp.children && tmp.children.length > 0) { if (tmp.children && tmp.children.length > 0) {
res.push(tmp) res.push(tmp)
} }
...@@ -40,26 +40,26 @@ function filterAsyncRouter(routes, perms) { ...@@ -40,26 +40,26 @@ function filterAsyncRouter(routes, perms) {
const permission = { const permission = {
state: { state: {
routers: constantRouterMap, routes: constantRoutes,
addRouters: [] addRoutes: []
}, },
mutations: { mutations: {
SET_ROUTERS: (state, routers) => { SET_ROUTES: (state, routes) => {
state.addRouters = routers state.addRoutes = routes
state.routers = constantRouterMap.concat(routers) state.routes = constantRoutes.concat(routes)
} }
}, },
actions: { actions: {
GenerateRoutes({ commit }, data) { GenerateRoutes({ commit }, data) {
return new Promise(resolve => { return new Promise(resolve => {
const { perms } = data const { perms } = data
let accessedRouters let accessedRoutes
if (perms.includes('*')) { if (perms.includes('*')) {
accessedRouters = asyncRouterMap accessedRoutes = asyncRoutes
} else { } else {
accessedRouters = filterAsyncRouter(asyncRouterMap, perms) accessedRoutes = filterAsyncRoutes(asyncRoutes, perms)
} }
commit('SET_ROUTERS', accessedRouters) commit('SET_ROUTES', accessedRoutes)
resolve() resolve()
}) })
} }
......
import { loginByUsername, logout, getUserInfo } from '@/api/login' import { loginByUsername, logout, getUserInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth' import { getToken, setToken, removeToken } from '@/utils/auth'
import router, { resetRouter } from '@/router'
const user = { const user = {
state: { state: {
user: '', user: '',
status: '',
code: '',
token: getToken(), token: getToken(),
name: '', name: '',
avatar: '', avatar: '',
introduction: '',
roles: [], roles: [],
perms: [], perms: []
setting: {
articlePlatform: []
}
}, },
mutations: { mutations: {
SET_CODE: (state, code) => {
state.code = code
},
SET_TOKEN: (state, token) => { SET_TOKEN: (state, token) => {
state.token = token state.token = token
}, },
SET_INTRODUCTION: (state, introduction) => {
state.introduction = introduction
},
SET_SETTING: (state, setting) => {
state.setting = setting
},
SET_STATUS: (state, status) => {
state.status = status
},
SET_NAME: (state, name) => { SET_NAME: (state, name) => {
state.name = name state.name = name
}, },
...@@ -78,7 +61,6 @@ const user = { ...@@ -78,7 +61,6 @@ const user = {
commit('SET_ROLES', data.roles) commit('SET_ROLES', data.roles)
commit('SET_NAME', data.name) commit('SET_NAME', data.name)
commit('SET_AVATAR', data.avatar) commit('SET_AVATAR', data.avatar)
commit('SET_INTRODUCTION', data.introduction)
resolve(response) resolve(response)
}).catch(error => { }).catch(error => {
reject(error) reject(error)
...@@ -86,28 +68,20 @@ const user = { ...@@ -86,28 +68,20 @@ const user = {
}) })
}, },
// 第三方验证登录
// LoginByThirdparty({ commit, state }, code) {
// return new Promise((resolve, reject) => {
// commit('SET_CODE', code)
// loginByThirdparty(state.status, state.email, state.code).then(response => {
// commit('SET_TOKEN', response.data.token)
// setToken(response.data.token)
// resolve()
// }).catch(error => {
// reject(error)
// })
// })
// },
// 登出 // 登出
LogOut({ commit, state }) { LogOut({ commit, state, dispatch }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logout(state.token).then(() => { logout(state.token).then(() => {
commit('SET_TOKEN', '') commit('SET_TOKEN', '')
commit('SET_ROLES', []) commit('SET_ROLES', [])
commit('SET_PERMS', []) commit('SET_PERMS', [])
removeToken() removeToken()
resetRouter()
// reset visited views and cached views
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
dispatch('tagsView/delAllViews', null, { root: true })
resolve() resolve()
}).catch(error => { }).catch(error => {
reject(error) reject(error)
...@@ -119,6 +93,7 @@ const user = { ...@@ -119,6 +93,7 @@ const user = {
FedLogOut({ commit }) { FedLogOut({ commit }) {
return new Promise(resolve => { return new Promise(resolve => {
commit('SET_TOKEN', '') commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken() removeToken()
resolve() resolve()
}) })
...@@ -126,19 +101,23 @@ const user = { ...@@ -126,19 +101,23 @@ const user = {
// 动态修改权限 // 动态修改权限
ChangeRoles({ commit, dispatch }, role) { ChangeRoles({ commit, dispatch }, role) {
return new Promise(resolve => { return new Promise(async resolve => {
commit('SET_TOKEN', role) commit('SET_TOKEN', role)
setToken(role) setToken(role)
getUserInfo(role).then(response => {
const data = response.data const { roles } = await dispatch('GetUserInfo')
commit('SET_ROLES', data.roles)
commit('SET_PERMS', data.perms) resetRouter()
commit('SET_NAME', data.name)
commit('SET_AVATAR', data.avatar) const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })
commit('SET_INTRODUCTION', data.introduction)
dispatch('GenerateRoutes', data) // 动态修改权限后 重绘侧边菜单 // dynamically add accessible routes
resolve() router.addRoutes(accessRoutes)
})
// reset visited views and cached views
dispatch('tagsView/delAllViews', null, { root: true })
resolve()
}) })
} }
} }
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
.fixed-width { .fixed-width {
.el-button--mini { .el-button--mini {
padding: 7px 10px; padding: 7px 10px;
width: 60px; min-width: 60px;
} }
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
/* theme color */ /* theme color */
$--color-primary: #1890ff; $--color-primary: #1890ff;
$--color-success: #13ce66; $--color-success: #13ce66;
$--color-warning: #FFBA00; $--color-warning: #ffba00;
$--color-danger: #ff4949; $--color-danger: #ff4949;
// $--color-info: #1E1E1E; // $--color-info: #1E1E1E;
...@@ -17,10 +17,10 @@ $--button-font-weight: 400; ...@@ -17,10 +17,10 @@ $--button-font-weight: 400;
$--border-color-light: #dfe4ed; $--border-color-light: #dfe4ed;
$--border-color-lighter: #e6ebf5; $--border-color-lighter: #e6ebf5;
$--table-border:1px solid#dfe6ec; $--table-border: 1px solid #dfe6ec;
/* icon font path, required */ /* icon font path, required */
$--font-path: '~element-ui/lib/theme-chalk/fonts'; $--font-path: "~element-ui/lib/theme-chalk/fonts";
@import "~element-ui/packages/theme-chalk/src/index"; @import "~element-ui/packages/theme-chalk/src/index";
......
...@@ -57,6 +57,11 @@ ...@@ -57,6 +57,11 @@
margin-right: 16px; margin-right: 16px;
} }
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
.el-menu { .el-menu {
border: none; border: none;
height: 100%; height: 100%;
...@@ -105,6 +110,11 @@ ...@@ -105,6 +110,11 @@
.svg-icon { .svg-icon {
margin-left: 20px; margin-left: 20px;
} }
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
} }
} }
...@@ -118,6 +128,11 @@ ...@@ -118,6 +128,11 @@
margin-left: 20px; margin-left: 20px;
} }
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
.el-submenu__icon-arrow { .el-submenu__icon-arrow {
display: none; display: none;
} }
...@@ -178,6 +193,10 @@ ...@@ -178,6 +193,10 @@
.svg-icon { .svg-icon {
margin-right: 16px; margin-right: 16px;
} }
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
} }
.nest-menu .el-submenu>.el-submenu__title, .nest-menu .el-submenu>.el-submenu__title,
......
/* eslint-disable */ /* eslint-disable */
require('script-loader!file-saver'); import { saveAs } from 'file-saver'
import XLSX from 'xlsx' import XLSX from 'xlsx'
function generateArray(table) { function generateArray(table) {
...@@ -145,20 +145,34 @@ export function export_table_to_excel(id) { ...@@ -145,20 +145,34 @@ export function export_table_to_excel(id) {
} }
export function export_json_to_excel({ export function export_json_to_excel({
multiHeader = [],
header, header,
data, data,
filename, filename,
merges = [],
autoWidth = true, autoWidth = true,
bookType= 'xlsx' bookType = 'xlsx'
} = {}) { } = {}) {
/* original data */ /* original data */
filename = filename || 'excel-list' filename = filename || 'excel-list'
data = [...data] data = [...data]
data.unshift(header); data.unshift(header);
for (let i = multiHeader.length - 1; i > -1; i--) {
data.unshift(multiHeader[i])
}
var ws_name = "SheetJS"; var ws_name = "SheetJS";
var wb = new Workbook(), var wb = new Workbook(),
ws = sheet_from_array_of_arrays(data); ws = sheet_from_array_of_arrays(data);
if (merges.length > 0) {
if (!ws['!merges']) ws['!merges'] = [];
merges.forEach(item => {
ws['!merges'].push(XLSX.utils.decode_range(item))
})
}
if (autoWidth) { if (autoWidth) {
/*设置worksheet每列的最大宽度*/ /*设置worksheet每列的最大宽度*/
const colWidth = data.map(row => row.map(val => { const colWidth = data.map(row => row.map(val => {
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
<!-- 查询和其他操作 --> <!-- 查询和其他操作 -->
<div class="filter-container"> <div class="filter-container">
<el-input v-model="listQuery.userId" clearable class="filter-item" style="width: 200px;" placeholder="请输入用户ID"/> <el-input v-model="listQuery.userId" clearable class="filter-item" style="width: 200px;" placeholder="请输入用户ID" />
<el-input v-model="listQuery.valueId" clearable class="filter-item" style="width: 200px;" placeholder="请输入商品ID"/> <el-input v-model="listQuery.valueId" clearable class="filter-item" style="width: 200px;" placeholder="请输入商品ID" />
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button> <el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
<el-button :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">导出</el-button> <el-button :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">导出</el-button>
</div> </div>
...@@ -12,21 +12,21 @@ ...@@ -12,21 +12,21 @@
<!-- 查询结果 --> <!-- 查询结果 -->
<el-table v-loading="listLoading" :data="list" element-loading-text="正在查询中。。。" border fit highlight-current-row> <el-table v-loading="listLoading" :data="list" element-loading-text="正在查询中。。。" border fit highlight-current-row>
<el-table-column align="center" label="用户ID" prop="userId"/> <el-table-column align="center" label="用户ID" prop="userId" />
<el-table-column align="center" label="商品ID" prop="valueId"/> <el-table-column align="center" label="商品ID" prop="valueId" />
<el-table-column align="center" label="打分" prop="star"/> <el-table-column align="center" label="打分" prop="star" />
<el-table-column align="center" label="评论内容" prop="content"/> <el-table-column align="center" label="评论内容" prop="content" />
<el-table-column align="center" label="评论图片" prop="picUrls"> <el-table-column align="center" label="评论图片" prop="picUrls">
<template slot-scope="scope"> <template slot-scope="scope">
<el-image v-for="item in scope.row.picUrls" :key="item" :src="item" :preview-src-list="scope.row.picUrls" :lazy="true" style="width: 40px; height: 40px; margin-right: 5px;"/> <el-image v-for="item in scope.row.picUrls" :key="item" :src="item" :preview-src-list="scope.row.picUrls" :lazy="true" style="width: 40px; height: 40px; margin-right: 5px;" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="时间" prop="addTime"/> <el-table-column align="center" label="时间" prop="addTime" />
<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width"> <el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
<template slot-scope="scope"> <template slot-scope="scope">
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
<el-dialog :visible.sync="replyFormVisible" title="回复"> <el-dialog :visible.sync="replyFormVisible" title="回复">
<el-form ref="replyForm" :model="replyForm" status-icon label-position="left" label-width="100px" style="width: 400px; margin-left:50px;"> <el-form ref="replyForm" :model="replyForm" status-icon label-position="left" label-width="100px" style="width: 400px; margin-left:50px;">
<el-form-item label="回复内容" prop="content"> <el-form-item label="回复内容" prop="content">
<el-input :autosize="{ minRows: 4, maxRows: 8}" v-model="replyForm.content" type="textarea"/> <el-input v-model="replyForm.content" :autosize="{ minRows: 4, maxRows: 8}" type="textarea" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
...@@ -129,8 +129,6 @@ export default { ...@@ -129,8 +129,6 @@ export default {
type: 'success', type: 'success',
duration: 2000 duration: 2000
}) })
const index = this.list.indexOf(row)
this.list.splice(index, 1)
}) })
}, },
handleDownload() { handleDownload() {
......
...@@ -46,8 +46,8 @@ ...@@ -46,8 +46,8 @@
密码修改 密码修改
</router-link> </router-link>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item divided> <el-dropdown-item divided @click.native="logout">
<span style="display:block;" @click="logout">退出</span> <span style="display:block;">退出</span>
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
......
...@@ -17,7 +17,11 @@ export default { ...@@ -17,7 +17,11 @@ export default {
const vnodes = [] const vnodes = []
if (icon) { if (icon) {
vnodes.push(<svg-icon icon-class={icon}/>) if (icon.includes('el-icon')) {
vnodes.push(<i class={[icon, 'sub-el-icon']} />)
} else {
vnodes.push(<svg-icon icon-class={icon}/>)
}
} }
if (title) { if (title) {
...@@ -27,3 +31,11 @@ export default { ...@@ -27,3 +31,11 @@ export default {
} }
} }
</script> </script>
<style scoped>
.sub-el-icon {
color: currentColor;
width: 1em;
height: 1em;
}
</style>
<template> <template>
<!-- eslint-disable vue/require-component-is--> <component :is="type" v-bind="linkProps(to)">
<component v-bind="linkProps(to)"> <slot />
<slot/>
</component> </component>
</template> </template>
<script> <script>
import { isExternal } from '@/utils' import { isExternal } from '@/utils/validate'
export default { export default {
props: { props: {
to: { to: {
...@@ -16,22 +13,28 @@ export default { ...@@ -16,22 +13,28 @@ export default {
required: true required: true
} }
}, },
methods: { computed: {
isExternalLink(routePath) { isExternal() {
return isExternal(routePath) return isExternal(this.to)
}, },
linkProps(url) { type() {
if (this.isExternalLink(url)) { if (this.isExternal) {
return 'a'
}
return 'router-link'
}
},
methods: {
linkProps(to) {
if (this.isExternal) {
return { return {
is: 'a', href: to,
href: url,
target: '_blank', target: '_blank',
rel: 'noopener' rel: 'noopener'
} }
} }
return { return {
is: 'router-link', to: to
to: url
} }
} }
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
text-color="#bfcbd9" text-color="#bfcbd9"
active-text-color="#409EFF" active-text-color="#409EFF"
> >
<sidebar-item v-for="route in permission_routers" :key="route.path" :item="route" :base-path="route.path"/> <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
</el-menu> </el-menu>
</el-scrollbar> </el-scrollbar>
</template> </template>
...@@ -22,7 +22,7 @@ export default { ...@@ -22,7 +22,7 @@ export default {
components: { SidebarItem }, components: { SidebarItem },
computed: { computed: {
...mapGetters([ ...mapGetters([
'permission_routers', 'permission_routes',
'sidebar' 'sidebar'
]), ]),
isCollapse() { isCollapse() {
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
<script> <script>
const tagAndTagSpacing = 4 // tagAndTagSpacing const tagAndTagSpacing = 4 // tagAndTagSpacing
export default { export default {
name: 'ScrollPane', name: 'ScrollPane',
data() { data() {
...@@ -19,27 +18,33 @@ export default { ...@@ -19,27 +18,33 @@ export default {
return this.$refs.scrollContainer.$refs.wrap return this.$refs.scrollContainer.$refs.wrap
} }
}, },
mounted() {
this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
},
beforeDestroy() {
this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
},
methods: { methods: {
handleScroll(e) { handleScroll(e) {
const eventDelta = e.wheelDelta || -e.deltaY * 40 const eventDelta = e.wheelDelta || -e.deltaY * 40
const $scrollWrapper = this.scrollWrapper const $scrollWrapper = this.scrollWrapper
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4 $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
}, },
emitScroll() {
this.$emit('scroll')
},
moveToTarget(currentTag) { moveToTarget(currentTag) {
const $container = this.$refs.scrollContainer.$el const $container = this.$refs.scrollContainer.$el
const $containerWidth = $container.offsetWidth const $containerWidth = $container.offsetWidth
const $scrollWrapper = this.scrollWrapper const $scrollWrapper = this.scrollWrapper
const tagList = this.$parent.$refs.tag const tagList = this.$parent.$refs.tag
let firstTag = null let firstTag = null
let lastTag = null let lastTag = null
// find first tag and last tag // find first tag and last tag
if (tagList.length > 0) { if (tagList.length > 0) {
firstTag = tagList[0] firstTag = tagList[0]
lastTag = tagList[tagList.length - 1] lastTag = tagList[tagList.length - 1]
} }
if (firstTag === currentTag) { if (firstTag === currentTag) {
$scrollWrapper.scrollLeft = 0 $scrollWrapper.scrollLeft = 0
} else if (lastTag === currentTag) { } else if (lastTag === currentTag) {
...@@ -49,13 +54,10 @@ export default { ...@@ -49,13 +54,10 @@ export default {
const currentIndex = tagList.findIndex(item => item === currentTag) const currentIndex = tagList.findIndex(item => item === currentTag)
const prevTag = tagList[currentIndex - 1] const prevTag = tagList[currentIndex - 1]
const nextTag = tagList[currentIndex + 1] const nextTag = tagList[currentIndex + 1]
// the tag's offsetLeft after of nextTag // the tag's offsetLeft after of nextTag
const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
// the tag's offsetLeft before of prevTag // the tag's offsetLeft before of prevTag
const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) { if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
$scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
} else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) { } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
...@@ -73,7 +75,7 @@ export default { ...@@ -73,7 +75,7 @@ export default {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
/deep/ { ::v-deep {
.el-scrollbar__bar { .el-scrollbar__bar {
bottom: 0px; bottom: 0px;
} }
......
<template> <template>
<div id="tags-view-container" class="tags-view-container"> <div id="tags-view-container" class="tags-view-container">
<scroll-pane ref="scrollPane" class="tags-view-wrapper"> <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
<router-link <router-link
v-for="tag in visitedViews" v-for="tag in visitedViews"
ref="tag" ref="tag"
...@@ -17,10 +17,10 @@ ...@@ -17,10 +17,10 @@
</router-link> </router-link>
</scroll-pane> </scroll-pane>
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu"> <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
<li @click="refreshSelectedTag(selectedTag)">刷新</li> <li @click="refreshSelectedTag(selectedTag)">Refresh</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭</li> <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">Close</li>
<li @click="closeOthersTags">关闭其他</li> <li @click="closeOthersTags">Close Others</li>
<li @click="closeAllTags(selectedTag)">关闭所有</li> <li @click="closeAllTags(selectedTag)">Close All</li>
</ul> </ul>
</div> </div>
</template> </template>
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
<script> <script>
import ScrollPane from './ScrollPane' import ScrollPane from './ScrollPane'
import path from 'path' import path from 'path'
export default { export default {
components: { ScrollPane }, components: { ScrollPane },
data() { data() {
...@@ -45,7 +44,7 @@ export default { ...@@ -45,7 +44,7 @@ export default {
return this.$store.state.tagsView.visitedViews return this.$store.state.tagsView.visitedViews
}, },
routes() { routes() {
return this.$store.state.permission.routers return this.$store.state.permission.routes
} }
}, },
watch: { watch: {
...@@ -176,19 +175,20 @@ export default { ...@@ -176,19 +175,20 @@ export default {
const offsetWidth = this.$el.offsetWidth // container width const offsetWidth = this.$el.offsetWidth // container width
const maxLeft = offsetWidth - menuMinWidth // left boundary const maxLeft = offsetWidth - menuMinWidth // left boundary
const left = e.clientX - offsetLeft + 15 // 15: margin right const left = e.clientX - offsetLeft + 15 // 15: margin right
if (left > maxLeft) { if (left > maxLeft) {
this.left = maxLeft this.left = maxLeft
} else { } else {
this.left = left this.left = left
} }
this.top = e.clientY this.top = e.clientY
this.visible = true this.visible = true
this.selectedTag = tag this.selectedTag = tag
}, },
closeMenu() { closeMenu() {
this.visible = false this.visible = false
},
handleScroll() {
this.closeMenu()
} }
} }
} }
......
export { default as AppMain } from './AppMain'
export { default as Navbar } from './Navbar' export { default as Navbar } from './Navbar'
export { default as Sidebar } from './Sidebar/index.vue' export { default as Sidebar } from './Sidebar/index.vue'
export { default as TagsView } from './TagsView' export { default as TagsView } from './TagsView/index.vue'
export { default as AppMain } from './AppMain'
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment