Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5cd245ac15 | ||
|
0c3063f46c | ||
|
91cb0ac5ca | ||
|
7549eb8044 | ||
|
1072572ac6 | ||
|
046d1369d2 | ||
|
657937c7a5 | ||
|
6de521d671 | ||
|
dbf9638922 | ||
|
aaa64a8ccf | ||
|
ff8d7ada73 | ||
|
bf480ca6b4 | ||
|
803201af3a | ||
|
e97dbf6115 | ||
|
cf1fb6cd4d |
5
.babelrc
5
.babelrc
@@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
"presets": ["es2015", "stage-2"],
|
"presets": [
|
||||||
|
["env", { "modules": false }],
|
||||||
|
"stage-2"
|
||||||
|
],
|
||||||
"plugins": ["transform-runtime"],
|
"plugins": ["transform-runtime"],
|
||||||
"comments": false
|
"comments": false
|
||||||
}
|
}
|
||||||
|
@@ -55,6 +55,7 @@ Join the group on QQ 591724180.
|
|||||||
- cache tabs example
|
- cache tabs example
|
||||||
- screenfull
|
- screenfull
|
||||||
- markdown2html
|
- markdown2html
|
||||||
|
- views-tab
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
@@ -57,6 +57,7 @@
|
|||||||
- cache tabs example
|
- cache tabs example
|
||||||
- screenfull
|
- screenfull
|
||||||
- markdown2html
|
- markdown2html
|
||||||
|
- views-tab
|
||||||
|
|
||||||
|
|
||||||
## 开发
|
## 开发
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "juicy",
|
"name": "juicy",
|
||||||
"version": "1.0.2",
|
"version": "1.0.3",
|
||||||
"description": "A Vue.js admin",
|
"description": "A Vue.js admin",
|
||||||
"author": "Pan <panfree23@gmail.com>",
|
"author": "Pan <panfree23@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
"babel-eslint": "7.2.3",
|
"babel-eslint": "7.2.3",
|
||||||
"babel-loader": "7.0.0",
|
"babel-loader": "7.0.0",
|
||||||
"babel-plugin-transform-runtime": "6.23.0",
|
"babel-plugin-transform-runtime": "6.23.0",
|
||||||
"babel-preset-es2015": "6.24.1",
|
"babel-preset-env": "1.5.2",
|
||||||
"babel-preset-stage-2": "6.24.1",
|
"babel-preset-stage-2": "6.24.1",
|
||||||
"babel-register": "6.24.1",
|
"babel-register": "6.24.1",
|
||||||
"chalk": "1.1.3",
|
"chalk": "1.1.3",
|
||||||
|
@@ -1,99 +1,91 @@
|
|||||||
(function() {
|
const vueSticky = {};
|
||||||
const vueSticky = {};
|
let listenAction;
|
||||||
let listenAction;
|
vueSticky.install = Vue => {
|
||||||
vueSticky.install = Vue => {
|
Vue.directive('sticky', {
|
||||||
Vue.directive('sticky', {
|
inserted(el, binding) {
|
||||||
inserted(el, binding) {
|
const params = binding.value || {},
|
||||||
const params = binding.value || {},
|
stickyTop = params.stickyTop || 0,
|
||||||
stickyTop = params.stickyTop || 0,
|
zIndex = params.zIndex || 1000,
|
||||||
zIndex = params.zIndex || 1000,
|
elStyle = el.style;
|
||||||
elStyle = el.style;
|
|
||||||
|
|
||||||
elStyle.position = '-webkit-sticky';
|
elStyle.position = '-webkit-sticky';
|
||||||
elStyle.position = 'sticky';
|
elStyle.position = 'sticky';
|
||||||
// if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
|
// if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
|
||||||
// if (~elStyle.position.indexOf('sticky')) {
|
// if (~elStyle.position.indexOf('sticky')) {
|
||||||
// elStyle.top = `${stickyTop}px`;
|
// elStyle.top = `${stickyTop}px`;
|
||||||
// elStyle.zIndex = zIndex;
|
// elStyle.zIndex = zIndex;
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
const elHeight = el.getBoundingClientRect().height;
|
const elHeight = el.getBoundingClientRect().height;
|
||||||
const elWidth = el.getBoundingClientRect().width;
|
const elWidth = el.getBoundingClientRect().width;
|
||||||
elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`;
|
elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`;
|
||||||
|
|
||||||
const parentElm = el.parentNode || document.documentElement;
|
const parentElm = el.parentNode || document.documentElement;
|
||||||
const placeholder = document.createElement('div');
|
const placeholder = document.createElement('div');
|
||||||
|
placeholder.style.display = 'none';
|
||||||
|
placeholder.style.width = `${elWidth}px`;
|
||||||
|
placeholder.style.height = `${elHeight}px`;
|
||||||
|
parentElm.insertBefore(placeholder, el)
|
||||||
|
|
||||||
|
let active = false;
|
||||||
|
|
||||||
|
const getScroll = (target, top) => {
|
||||||
|
const prop = top ? 'pageYOffset' : 'pageXOffset';
|
||||||
|
const method = top ? 'scrollTop' : 'scrollLeft';
|
||||||
|
let ret = target[prop];
|
||||||
|
if (typeof ret !== 'number') {
|
||||||
|
ret = window.document.documentElement[method];
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sticky = () => {
|
||||||
|
if (active) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!elStyle.height) {
|
||||||
|
elStyle.height = `${el.offsetHeight}px`
|
||||||
|
}
|
||||||
|
|
||||||
|
elStyle.position = 'fixed';
|
||||||
|
elStyle.width = `${elWidth}px`;
|
||||||
|
placeholder.style.display = 'inline-block';
|
||||||
|
active = true
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
if (!active) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
elStyle.position = '';
|
||||||
placeholder.style.display = 'none';
|
placeholder.style.display = 'none';
|
||||||
placeholder.style.width = `${elWidth}px`;
|
active = false;
|
||||||
placeholder.style.height = `${elHeight}px`;
|
};
|
||||||
parentElm.insertBefore(placeholder, el)
|
|
||||||
|
|
||||||
let active = false;
|
const check = () => {
|
||||||
|
const scrollTop = getScroll(window, true);
|
||||||
const getScroll = (target, top) => {
|
const offsetTop = el.getBoundingClientRect().top;
|
||||||
const prop = top ? 'pageYOffset' : 'pageXOffset';
|
if (offsetTop < stickyTop) {
|
||||||
const method = top ? 'scrollTop' : 'scrollLeft';
|
sticky();
|
||||||
let ret = target[prop];
|
} else {
|
||||||
if (typeof ret !== 'number') {
|
if (scrollTop < elHeight + stickyTop) {
|
||||||
ret = window.document.documentElement[method];
|
reset()
|
||||||
}
|
}
|
||||||
return ret;
|
}
|
||||||
};
|
};
|
||||||
|
listenAction = () => {
|
||||||
|
check()
|
||||||
|
};
|
||||||
|
|
||||||
const sticky = () => {
|
window.addEventListener('scroll', listenAction)
|
||||||
if (active) {
|
},
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!elStyle.height) {
|
|
||||||
elStyle.height = `${el.offsetHeight}px`
|
|
||||||
}
|
|
||||||
|
|
||||||
elStyle.position = 'fixed';
|
unbind() {
|
||||||
elStyle.width = `${elWidth}px`;
|
window.removeEventListener('scroll', listenAction)
|
||||||
placeholder.style.display = 'inline-block';
|
}
|
||||||
active = true
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
const reset = () => {
|
export default vueSticky
|
||||||
if (!active) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
elStyle.position = '';
|
|
||||||
placeholder.style.display = 'none';
|
|
||||||
active = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const check = () => {
|
|
||||||
const scrollTop = getScroll(window, true);
|
|
||||||
const offsetTop = el.getBoundingClientRect().top;
|
|
||||||
if (offsetTop < stickyTop) {
|
|
||||||
sticky();
|
|
||||||
} else {
|
|
||||||
if (scrollTop < elHeight + stickyTop) {
|
|
||||||
reset()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
listenAction = () => {
|
|
||||||
check()
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('scroll', listenAction)
|
|
||||||
},
|
|
||||||
|
|
||||||
unbind() {
|
|
||||||
window.removeEventListener('scroll', listenAction)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
if (typeof exports == 'object') {
|
|
||||||
module.exports = vueSticky
|
|
||||||
} else if (typeof define == 'function' && define.amd) {
|
|
||||||
define([], () => vueSticky)
|
|
||||||
} else if (window.Vue) {
|
|
||||||
window.vueSticky = vueSticky;
|
|
||||||
Vue.use(vueSticky)
|
|
||||||
}
|
|
||||||
}());
|
|
||||||
|
|
||||||
|
@@ -1,54 +1,47 @@
|
|||||||
import './waves.css';
|
import './waves.css';
|
||||||
(function() {
|
|
||||||
const vueWaves = {};
|
const vueWaves = {};
|
||||||
vueWaves.install = (Vue, options = {}) => {
|
vueWaves.install = (Vue, options = {}) => {
|
||||||
Vue.directive('waves', {
|
Vue.directive('waves', {
|
||||||
bind(el, binding) {
|
bind(el, binding) {
|
||||||
el.addEventListener('click', e => {
|
el.addEventListener('click', e => {
|
||||||
const customOpts = Object.assign(options, binding.value);
|
const customOpts = Object.assign(options, binding.value);
|
||||||
const opts = Object.assign({
|
const opts = Object.assign({
|
||||||
ele: el, // 波纹作用元素
|
ele: el, // 波纹作用元素
|
||||||
type: 'hit', // hit点击位置扩散center中心点扩展
|
type: 'hit', // hit点击位置扩散center中心点扩展
|
||||||
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
|
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
|
||||||
}, customOpts),
|
}, customOpts),
|
||||||
target = opts.ele;
|
target = opts.ele;
|
||||||
if (target) {
|
if (target) {
|
||||||
target.style.position = 'relative';
|
target.style.position = 'relative';
|
||||||
target.style.overflow = 'hidden';
|
target.style.overflow = 'hidden';
|
||||||
const rect = target.getBoundingClientRect();
|
const rect = target.getBoundingClientRect();
|
||||||
let ripple = target.querySelector('.waves-ripple');
|
let ripple = target.querySelector('.waves-ripple');
|
||||||
if (!ripple) {
|
if (!ripple) {
|
||||||
ripple = document.createElement('span');
|
ripple = document.createElement('span');
|
||||||
ripple.className = 'waves-ripple';
|
ripple.className = 'waves-ripple';
|
||||||
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
|
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
|
||||||
target.appendChild(ripple);
|
target.appendChild(ripple);
|
||||||
} else {
|
} else {
|
||||||
ripple.className = 'waves-ripple';
|
ripple.className = 'waves-ripple';
|
||||||
}
|
}
|
||||||
switch (opts.type) {
|
switch (opts.type) {
|
||||||
case 'center':
|
case 'center':
|
||||||
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
|
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
|
||||||
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px';
|
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px';
|
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px';
|
||||||
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px';
|
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px';
|
||||||
}
|
}
|
||||||
ripple.style.backgroundColor = opts.color;
|
ripple.style.backgroundColor = opts.color;
|
||||||
ripple.className = 'waves-ripple z-active';
|
ripple.className = 'waves-ripple z-active';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
if (typeof exports == 'object') {
|
|
||||||
module.exports = vueWaves
|
export default vueWaves;
|
||||||
} else if (typeof define == 'function' && define.amd) {
|
|
||||||
define([], () => vueWaves)
|
|
||||||
} else if (window.Vue) {
|
|
||||||
window.vueWaves = vueWaves;
|
|
||||||
Vue.use(vueWaves)
|
|
||||||
}
|
|
||||||
}());
|
|
||||||
|
|
||||||
|
@@ -104,5 +104,5 @@ export function html2Text(val) {
|
|||||||
|
|
||||||
|
|
||||||
export function toThousandslsFilter(num) {
|
export function toThousandslsFilter(num) {
|
||||||
return (+num || 0).toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
|
return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','));
|
||||||
}
|
}
|
||||||
|
1
src/router/_import_development.js
Normal file
1
src/router/_import_development.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
module.exports = file => require('../views/' + file + '.vue')
|
1
src/router/_import_production.js
Normal file
1
src/router/_import_production.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
module.exports = file => () => import('../views/' + file + '.vue')
|
@@ -1,67 +1,70 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Router from 'vue-router';
|
import Router from 'vue-router';
|
||||||
|
const _import = require('./_import_' + process.env.NODE_ENV);
|
||||||
|
// in development env not use Lazy Loading,because Lazy Loading large page will cause webpack hot update too slow
|
||||||
|
// so only in production use Lazy Loading
|
||||||
|
|
||||||
/* layout */
|
/* layout */
|
||||||
import Layout from '../views/layout/Layout';
|
import Layout from '../views/layout/Layout';
|
||||||
|
|
||||||
/* login */
|
/* login */
|
||||||
import Login from '../views/login/';
|
const Login = _import('login/index');
|
||||||
const authRedirect = () => import('../views/login/authredirect');
|
const authRedirect = _import('login/authredirect');
|
||||||
const sendPWD = () => import('../views/login/sendpwd');
|
const sendPWD = _import('login/sendpwd');
|
||||||
const reset = () => import('../views/login/reset');
|
const reset = _import('login/reset');
|
||||||
|
|
||||||
/* dashboard */
|
/* dashboard */
|
||||||
const dashboard = () => import('../views/dashboard/index');
|
const dashboard = _import('dashboard/index');
|
||||||
|
|
||||||
/* Introduction */
|
/* Introduction */
|
||||||
const Introduction = () => import('../views/introduction/index');
|
const Introduction = _import('introduction/index');
|
||||||
|
|
||||||
/* components */
|
/* components */
|
||||||
const componentsIndex = () => import('../views/components/index');
|
const componentsIndex = _import('components/index');
|
||||||
const Tinymce = () => import('../views/components/tinymce');
|
const Tinymce = _import('components/tinymce');
|
||||||
const Markdown = () => import('../views/components/markdown');
|
const Markdown = _import('components/markdown');
|
||||||
const JsonEditor = () => import('../views/components/jsoneditor');
|
const JsonEditor = _import('components/jsoneditor');
|
||||||
const DndList = () => import('../views/components/dndlist');
|
const DndList = _import('components/dndlist');
|
||||||
const AvatarUpload = () => import('../views/components/avatarUpload');
|
const AvatarUpload = _import('components/avatarUpload');
|
||||||
const Dropzone = () => import('../views/components/dropzone');
|
const Dropzone = _import('components/dropzone');
|
||||||
const Sticky = () => import('../views/components/sticky');
|
const Sticky = _import('components/sticky');
|
||||||
const SplitPane = () => import('../views/components/splitpane');
|
const SplitPane = _import('components/splitpane');
|
||||||
const CountTo = () => import('../views/components/countTo');
|
const CountTo = _import('components/countTo');
|
||||||
const Mixin = () => import('../views/components/mixin');
|
const Mixin = _import('components/mixin');
|
||||||
|
|
||||||
|
|
||||||
/* charts */
|
/* charts */
|
||||||
const chartIndex = () => import('../views/charts/index');
|
const chartIndex = _import('charts/index');
|
||||||
const KeyboardChart = () => import('../views/charts/keyboard');
|
const KeyboardChart = _import('charts/keyboard');
|
||||||
const KeyboardChart2 = () => import('../views/charts/keyboard2');
|
const KeyboardChart2 = _import('charts/keyboard2');
|
||||||
const LineMarker = () => import('../views/charts/line');
|
const LineMarker = _import('charts/line');
|
||||||
const MixChart = () => import('../views/charts/mixchart');
|
const MixChart = _import('charts/mixchart');
|
||||||
|
|
||||||
/* error page */
|
/* error page */
|
||||||
const Err404 = () => import('../views/error/404');
|
const Err404 = _import('error/404');
|
||||||
const Err401 = () => import('../views/error/401');
|
const Err401 = _import('error/401');
|
||||||
|
|
||||||
/* error log */
|
/* error log */
|
||||||
const ErrorLog = () => import('../views/errlog/index');
|
const ErrorLog = _import('errlog/index');
|
||||||
|
|
||||||
/* excel */
|
/* excel */
|
||||||
const ExcelDownload = () => import('../views/excel/index');
|
const ExcelDownload = _import('excel/index');
|
||||||
|
|
||||||
/* theme */
|
/* theme */
|
||||||
const Theme = () => import('../views/theme/index');
|
const Theme = _import('theme/index');
|
||||||
|
|
||||||
/* example*/
|
/* example*/
|
||||||
const TableLayout = () => import('../views/example/table/index');
|
const TableLayout = _import('example/table/index');
|
||||||
const DynamicTable = () => import('../views/example/table/dynamictable');
|
const DynamicTable = _import('example/table/dynamictable');
|
||||||
const Table = () => import('../views/example/table/table');
|
const Table = _import('example/table/table');
|
||||||
const DragTable = () => import('../views/example/table/dragTable');
|
const DragTable = _import('example/table/dragTable');
|
||||||
const InlineEditTable = () => import('../views/example/table/inlineEditTable');
|
const InlineEditTable = _import('example/table/inlineEditTable');
|
||||||
|
|
||||||
const Form = () => import('../views/example/form');
|
const Form = _import('example/form');
|
||||||
const Tab = () => import('../views/example/tab/index');
|
const Tab = _import('example/tab/index');
|
||||||
|
|
||||||
/* permission */
|
/* permission */
|
||||||
const Permission = () => import('../views/permission/index');
|
const Permission = _import('permission/index');
|
||||||
|
|
||||||
|
|
||||||
Vue.use(Router);
|
Vue.use(Router);
|
||||||
@@ -196,9 +199,9 @@ export const asyncRouterMap = [
|
|||||||
icon: 'zonghe',
|
icon: 'zonghe',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/table',
|
path: '/example/table',
|
||||||
component: TableLayout,
|
component: TableLayout,
|
||||||
redirect: '/table/table',
|
redirect: '/example/table/table',
|
||||||
name: 'Table',
|
name: 'Table',
|
||||||
children: [
|
children: [
|
||||||
{ path: 'dynamictable', component: DynamicTable, name: '动态table' },
|
{ path: 'dynamictable', component: DynamicTable, name: '动态table' },
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
const getters = {
|
const getters = {
|
||||||
sidebar: state => state.app.sidebar,
|
sidebar: state => state.app.sidebar,
|
||||||
|
visitedViews: state => state.app.visitedViews,
|
||||||
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,
|
||||||
|
@@ -6,7 +6,8 @@ const app = {
|
|||||||
opened: !+Cookies.get('sidebarStatus')
|
opened: !+Cookies.get('sidebarStatus')
|
||||||
},
|
},
|
||||||
theme: 'default',
|
theme: 'default',
|
||||||
livenewsChannels: Cookies.get('livenewsChannels') || '[]'
|
livenewsChannels: Cookies.get('livenewsChannels') || '[]',
|
||||||
|
visitedViews: []
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
TOGGLE_SIDEBAR: state => {
|
TOGGLE_SIDEBAR: state => {
|
||||||
@@ -16,11 +17,25 @@ const app = {
|
|||||||
Cookies.set('sidebarStatus', 0);
|
Cookies.set('sidebarStatus', 0);
|
||||||
}
|
}
|
||||||
state.sidebar.opened = !state.sidebar.opened;
|
state.sidebar.opened = !state.sidebar.opened;
|
||||||
|
},
|
||||||
|
ADD_VISITED_VIEWS: (state, view) => {
|
||||||
|
if (state.visitedViews.includes(view)) return
|
||||||
|
state.visitedViews.push(view)
|
||||||
|
},
|
||||||
|
DEL_VISITED_VIEWS: (state, view) => {
|
||||||
|
const index = state.visitedViews.indexOf(view)
|
||||||
|
state.visitedViews.splice(index, 1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
ToggleSideBar: ({ commit }) => {
|
ToggleSideBar: ({ commit }) => {
|
||||||
commit('TOGGLE_SIDEBAR')
|
commit('TOGGLE_SIDEBAR')
|
||||||
|
},
|
||||||
|
addVisitedViews: ({ commit }, view) => {
|
||||||
|
commit('ADD_VISITED_VIEWS', view)
|
||||||
|
},
|
||||||
|
delVisitedViews: ({ commit }, view) => {
|
||||||
|
commit('DEL_VISITED_VIEWS', view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
import { asyncRouterMap, constantRouterMap } from 'src/router';
|
import { asyncRouterMap, constantRouterMap } from 'src/router';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过meta.role判断是否与当前用户权限匹配
|
||||||
|
* @param roles
|
||||||
|
* @param route
|
||||||
|
*/
|
||||||
function hasPermission(roles, route) {
|
function hasPermission(roles, route) {
|
||||||
if (route.meta && route.meta.role) {
|
if (route.meta && route.meta.role) {
|
||||||
return roles.some(role => route.meta.role.indexOf(role) >= 0)
|
return roles.some(role => route.meta.role.indexOf(role) >= 0)
|
||||||
@@ -8,40 +13,45 @@ function hasPermission(roles, route) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归过滤异步路由表,返回符合用户角色权限的路由表
|
||||||
|
* @param asyncRouterMap
|
||||||
|
* @param roles
|
||||||
|
*/
|
||||||
|
function filterAsyncRouter(asyncRouterMap, roles) {
|
||||||
|
const accessedRouters = asyncRouterMap.filter(route => {
|
||||||
|
if (hasPermission(roles, route)) {
|
||||||
|
if (route.children && route.children.length) {
|
||||||
|
route.children = filterAsyncRouter(route.children, roles)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
return accessedRouters
|
||||||
|
}
|
||||||
|
|
||||||
const permission = {
|
const permission = {
|
||||||
state: {
|
state: {
|
||||||
routers: constantRouterMap,
|
routers: constantRouterMap,
|
||||||
addRouters: []
|
addRouters: []
|
||||||
},
|
},
|
||||||
|
|
||||||
mutations: {
|
mutations: {
|
||||||
SET_ROUTERS: (state, routers) => {
|
SET_ROUTERS: (state, routers) => {
|
||||||
state.addRouters = routers;
|
state.addRouters = routers;
|
||||||
state.routers = constantRouterMap.concat(routers);
|
state.routers = constantRouterMap.concat(routers);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
GenerateRoutes({ commit }, data) {
|
GenerateRoutes({ commit }, data) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const { roles } = data;
|
const { roles } = data
|
||||||
const accessedRouters = asyncRouterMap.filter(v => {
|
let accessedRouters
|
||||||
if (roles.indexOf('admin') >= 0) return true;
|
if (roles.indexOf('admin') >= 0) {
|
||||||
if (hasPermission(roles, v)) {
|
accessedRouters = asyncRouterMap
|
||||||
if (v.children && v.children.length > 0) {
|
} else {
|
||||||
v.children = v.children.filter(child => {
|
accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
|
||||||
if (hasPermission(roles, child)) {
|
}
|
||||||
return child
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
return v
|
|
||||||
} else {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
commit('SET_ROUTERS', accessedRouters);
|
commit('SET_ROUTERS', accessedRouters);
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
@@ -49,5 +59,4 @@ const permission = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default permission;
|
export default permission;
|
||||||
|
@@ -24,27 +24,34 @@ service.interceptors.request.use(config => {
|
|||||||
|
|
||||||
// respone拦截器
|
// respone拦截器
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
response => response
|
response => response,
|
||||||
/**
|
/**
|
||||||
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
|
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
|
||||||
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
|
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
|
||||||
*/
|
*/
|
||||||
// const code = response.data.code;
|
// const res = response.data;
|
||||||
// // 50014:Token 过期了 50012:其他客户端登录了 50008:非法的token
|
// if (res.code !== 20000) {
|
||||||
// if (code === 50008 || code === 50014 || code === 50012) {
|
// Message({
|
||||||
// Message({
|
// message: res.message,
|
||||||
// message: res.message,
|
// type: 'error',
|
||||||
// type: 'error',
|
// duration: 5 * 1000
|
||||||
// duration: 5 * 1000
|
// });
|
||||||
// });
|
// // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
|
||||||
// // 登出
|
// if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
|
||||||
// store.dispatch('FedLogOut').then(() => {
|
// MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
|
||||||
// router.push({ path: '/login' })
|
// confirmButtonText: '重新登录',
|
||||||
// });
|
// cancelButtonText: '取消',
|
||||||
// } else {
|
// type: 'warning'
|
||||||
// return response
|
// }).then(() => {
|
||||||
// }
|
// store.dispatch('FedLogOut').then(() => {
|
||||||
,
|
// location.reload();// 为了重新实例化vue-router对象 避免bug
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// return Promise.reject(error);
|
||||||
|
// } else {
|
||||||
|
// return response.data;
|
||||||
|
// }
|
||||||
error => {
|
error => {
|
||||||
console.log('err' + error);// for debug
|
console.log('err' + error);// for debug
|
||||||
Message({
|
Message({
|
||||||
|
@@ -40,8 +40,8 @@
|
|||||||
<router-link class="pan-btn light-blue-btn" to="/charts/index">图表</router-link>
|
<router-link class="pan-btn light-blue-btn" to="/charts/index">图表</router-link>
|
||||||
<router-link class="pan-btn red-btn" to="/errorpage/404">错误页面</router-link>
|
<router-link class="pan-btn red-btn" to="/errorpage/404">错误页面</router-link>
|
||||||
<router-link class="pan-btn pink-btn" to="/excel/download">导出excel</router-link>
|
<router-link class="pan-btn pink-btn" to="/excel/download">导出excel</router-link>
|
||||||
<router-link class="pan-btn green-btn" to="/example/table">table</router-link>
|
<router-link class="pan-btn green-btn" to="/example/table/table">Table</router-link>
|
||||||
<router-link class="pan-btn tiffany-btn" to="/example/form1">form</router-link>
|
<router-link class="pan-btn tiffany-btn" to="/example/form/edit">Form</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="clearfix main-dashboard-container">
|
<div class="clearfix main-dashboard-container">
|
||||||
|
@@ -1,38 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<div class="filter-container">
|
<div style='margin:0 0 5px 20px'>固定表头 按照表头顺序排序</div>
|
||||||
<el-checkbox-group v-model="formThead">
|
<fixed-thead/>
|
||||||
<el-checkbox label="apple">apple</el-checkbox>
|
|
||||||
<el-checkbox label="banana">banana</el-checkbox>
|
<div style='margin:30px 0 5px 20px'>不固定表头 按照点击顺序排序</div>
|
||||||
<el-checkbox label="orange">orange</el-checkbox>
|
<unfixed-thead/>
|
||||||
</el-checkbox-group>
|
|
||||||
</div>
|
|
||||||
<el-table :data="tableData" style="width: 100%">
|
|
||||||
<el-table-column prop="name" label="名称" width="180">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column :key='fruit' v-for='(fruit,index) in formThead' :label="fruit">
|
|
||||||
<template scope="scope">
|
|
||||||
{{scope.row.list[index].value}}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import fixedThead from './dynamictable/fixedThead'
|
||||||
|
import unfixedThead from './dynamictable/unfixedThead'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
components: { fixedThead, unfixedThead }
|
||||||
return {
|
|
||||||
tableData: [{
|
|
||||||
name: '水果',
|
|
||||||
list: [{ name: 'apple', value: 10 }, { name: 'banana', value: 20 }, { name: 'orange', value: 20 }]
|
|
||||||
}, {
|
|
||||||
name: '水果2',
|
|
||||||
list: [{ name: 'apple2', value: 12 }, { name: 'banana2', value: 22 }, { name: 'orange', value: 20 }]
|
|
||||||
}],
|
|
||||||
formThead: ['apple', 'banana']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
61
src/views/example/table/dynamictable/fixedThead.vue
Normal file
61
src/views/example/table/dynamictable/fixedThead.vue
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
|
||||||
|
<div class="filter-container">
|
||||||
|
<el-checkbox-group v-model="checkboxVal" >
|
||||||
|
<el-checkbox label="apple">apple</el-checkbox>
|
||||||
|
<el-checkbox label="banana">banana</el-checkbox>
|
||||||
|
<el-checkbox label="orange">orange</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table :data="tableData" :key='key' style="width: 100%">
|
||||||
|
<el-table-column prop="name" label="fruitName" width="180"></el-table-column>
|
||||||
|
<el-table-column :key='fruit' v-for='(fruit,index) in formThead' :label="fruit">
|
||||||
|
<template scope="scope">
|
||||||
|
{{scope.row.list[index].value}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const defaultFormThead = ['apple', 'banana']; // 默认选中项
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tableData: [
|
||||||
|
{
|
||||||
|
name: 'fruit1',
|
||||||
|
list: [
|
||||||
|
{ name: 'apple1', value: 10 },
|
||||||
|
{ name: 'banana1', value: 20 },
|
||||||
|
{ name: 'orange1', value: 20 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'fruit2',
|
||||||
|
list: [
|
||||||
|
{ name: 'apple2', value: 12 },
|
||||||
|
{ name: 'banana2', value: 22 },
|
||||||
|
{ name: 'orange2', value: 20 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
key: 1, // table key
|
||||||
|
formTheadOptions: ['apple', 'banana', 'orange'], // 可选择表头
|
||||||
|
checkboxVal: defaultFormThead, // checkboxVal
|
||||||
|
formThead: defaultFormThead // 默认表头
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
checkboxVal(valArr) {
|
||||||
|
this.formThead = this.formTheadOptions.filter(i => valArr.indexOf(i) >= 0);
|
||||||
|
this.key = this.key + 1;// 为了保证table 每次都会重渲 (牺牲性能保证效果,当然也可以不用)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
51
src/views/example/table/dynamictable/unfixedThead.vue
Normal file
51
src/views/example/table/dynamictable/unfixedThead.vue
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
|
||||||
|
<div class="filter-container">
|
||||||
|
<el-checkbox-group v-model="formThead">
|
||||||
|
<el-checkbox label="apple">apple</el-checkbox>
|
||||||
|
<el-checkbox label="banana">banana</el-checkbox>
|
||||||
|
<el-checkbox label="orange">orange</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table :data="tableData" style="width: 100%">
|
||||||
|
<el-table-column prop="name" label="fruitName" width="180">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :key='fruit' v-for='(fruit,index) in formThead' :label="fruit">
|
||||||
|
<template scope="scope">
|
||||||
|
{{scope.row.list[index].value}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tableData: [
|
||||||
|
{
|
||||||
|
name: 'fruit1',
|
||||||
|
list: [
|
||||||
|
{ name: 'apple1', value: 10 },
|
||||||
|
{ name: 'banana1', value: 20 },
|
||||||
|
{ name: 'orange1', value: 20 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'fruit2',
|
||||||
|
list: [
|
||||||
|
{ name: 'apple2', value: 12 },
|
||||||
|
{ name: 'banana2', value: 22 },
|
||||||
|
{ name: 'orange2', value: 20 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
formThead: ['apple', 'banana']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@@ -2,12 +2,13 @@
|
|||||||
<el-menu class="navbar" mode="horizontal">
|
<el-menu class="navbar" mode="horizontal">
|
||||||
<hamburger class="hamburger-container" :toggleClick="toggleSideBar" :isActive="sidebar.opened"></hamburger>
|
<hamburger class="hamburger-container" :toggleClick="toggleSideBar" :isActive="sidebar.opened"></hamburger>
|
||||||
<levelbar></levelbar>
|
<levelbar></levelbar>
|
||||||
|
<tabs-view></tabs-view>
|
||||||
<error-log v-if="log.length>0" class="errLog-container" :logsList="log"></error-log>
|
<error-log v-if="log.length>0" class="errLog-container" :logsList="log"></error-log>
|
||||||
<screenfull class='screenfull'></screenfull>
|
<screenfull class='screenfull'></screenfull>
|
||||||
<el-dropdown class="avatar-container" trigger="click">
|
<el-dropdown class="avatar-container" trigger="click">
|
||||||
<div class="avatar-wrapper">
|
<div class="avatar-wrapper">
|
||||||
<img class="user-avatar" :src="avatar+'?imageView2/1/w/80/h/80'">
|
<img class="user-avatar" :src="avatar+'?imageView2/1/w/80/h/80'">
|
||||||
<i class="el-icon-caret-bottom" />
|
<i class="el-icon-caret-bottom"></i>
|
||||||
</div>
|
</div>
|
||||||
<el-dropdown-menu class="user-dropdown" slot="dropdown">
|
<el-dropdown-menu class="user-dropdown" slot="dropdown">
|
||||||
<router-link class='inlineBlock' to="/">
|
<router-link class='inlineBlock' to="/">
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import Levelbar from './Levelbar';
|
import Levelbar from './Levelbar';
|
||||||
|
import TabsView from './TabsView';
|
||||||
import Hamburger from 'components/Hamburger';
|
import Hamburger from 'components/Hamburger';
|
||||||
import Screenfull from 'components/Screenfull';
|
import Screenfull from 'components/Screenfull';
|
||||||
import ErrorLog from 'components/ErrLog';
|
import ErrorLog from 'components/ErrLog';
|
||||||
@@ -37,6 +39,7 @@
|
|||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Levelbar,
|
Levelbar,
|
||||||
|
TabsView,
|
||||||
Hamburger,
|
Hamburger,
|
||||||
ErrorLog,
|
ErrorLog,
|
||||||
Screenfull
|
Screenfull
|
||||||
|
45
src/views/layout/TabsView.vue
Normal file
45
src/views/layout/TabsView.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<div class='tabs-view-container'>
|
||||||
|
<router-link class="tabs-view" v-for="tag in Array.from(visitedViews)" :to="tag.path" :key="tag.path">
|
||||||
|
<el-tag :closable="true" @close='closeViewTabs(tag,$event)'>
|
||||||
|
{{tag.name}}
|
||||||
|
</el-tag>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
computed: {
|
||||||
|
visitedViews() {
|
||||||
|
return this.$store.state.app.visitedViews.slice(-6)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeViewTabs(view, $event) {
|
||||||
|
this.$store.dispatch('delVisitedViews', view)
|
||||||
|
$event.preventDefault()
|
||||||
|
},
|
||||||
|
addViewTabs() {
|
||||||
|
this.$store.dispatch('addVisitedViews', this.$route.matched[this.$route.matched.length - 1])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route() {
|
||||||
|
this.addViewTabs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
|
.tabs-view-container{
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
margin-left: 10px;
|
||||||
|
.tabs-view{
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
Reference in New Issue
Block a user