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"],
|
||||
"comments": false
|
||||
}
|
||||
|
@@ -55,6 +55,7 @@ Join the group on QQ 591724180.
|
||||
- cache tabs example
|
||||
- screenfull
|
||||
- markdown2html
|
||||
- views-tab
|
||||
|
||||
## Development
|
||||
|
||||
|
@@ -57,6 +57,7 @@
|
||||
- cache tabs example
|
||||
- screenfull
|
||||
- markdown2html
|
||||
- views-tab
|
||||
|
||||
|
||||
## 开发
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "juicy",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.3",
|
||||
"description": "A Vue.js admin",
|
||||
"author": "Pan <panfree23@gmail.com>",
|
||||
"license": "MIT",
|
||||
@@ -43,7 +43,7 @@
|
||||
"babel-eslint": "7.2.3",
|
||||
"babel-loader": "7.0.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-register": "6.24.1",
|
||||
"chalk": "1.1.3",
|
||||
|
@@ -1,99 +1,91 @@
|
||||
(function() {
|
||||
const vueSticky = {};
|
||||
let listenAction;
|
||||
vueSticky.install = Vue => {
|
||||
Vue.directive('sticky', {
|
||||
inserted(el, binding) {
|
||||
const params = binding.value || {},
|
||||
stickyTop = params.stickyTop || 0,
|
||||
zIndex = params.zIndex || 1000,
|
||||
elStyle = el.style;
|
||||
const vueSticky = {};
|
||||
let listenAction;
|
||||
vueSticky.install = Vue => {
|
||||
Vue.directive('sticky', {
|
||||
inserted(el, binding) {
|
||||
const params = binding.value || {},
|
||||
stickyTop = params.stickyTop || 0,
|
||||
zIndex = params.zIndex || 1000,
|
||||
elStyle = el.style;
|
||||
|
||||
elStyle.position = '-webkit-sticky';
|
||||
elStyle.position = 'sticky';
|
||||
elStyle.position = '-webkit-sticky';
|
||||
elStyle.position = 'sticky';
|
||||
// if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
|
||||
// if (~elStyle.position.indexOf('sticky')) {
|
||||
// elStyle.top = `${stickyTop}px`;
|
||||
// elStyle.zIndex = zIndex;
|
||||
// return
|
||||
// }
|
||||
const elHeight = el.getBoundingClientRect().height;
|
||||
const elWidth = el.getBoundingClientRect().width;
|
||||
elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`;
|
||||
const elHeight = el.getBoundingClientRect().height;
|
||||
const elWidth = el.getBoundingClientRect().width;
|
||||
elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`;
|
||||
|
||||
const parentElm = el.parentNode || document.documentElement;
|
||||
const placeholder = document.createElement('div');
|
||||
const parentElm = el.parentNode || document.documentElement;
|
||||
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.width = `${elWidth}px`;
|
||||
placeholder.style.height = `${elHeight}px`;
|
||||
parentElm.insertBefore(placeholder, el)
|
||||
active = false;
|
||||
};
|
||||
|
||||
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];
|
||||
const check = () => {
|
||||
const scrollTop = getScroll(window, true);
|
||||
const offsetTop = el.getBoundingClientRect().top;
|
||||
if (offsetTop < stickyTop) {
|
||||
sticky();
|
||||
} else {
|
||||
if (scrollTop < elHeight + stickyTop) {
|
||||
reset()
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
};
|
||||
listenAction = () => {
|
||||
check()
|
||||
};
|
||||
|
||||
const sticky = () => {
|
||||
if (active) {
|
||||
return
|
||||
}
|
||||
if (!elStyle.height) {
|
||||
elStyle.height = `${el.offsetHeight}px`
|
||||
}
|
||||
window.addEventListener('scroll', listenAction)
|
||||
},
|
||||
|
||||
elStyle.position = 'fixed';
|
||||
elStyle.width = `${elWidth}px`;
|
||||
placeholder.style.display = 'inline-block';
|
||||
active = true
|
||||
};
|
||||
unbind() {
|
||||
window.removeEventListener('scroll', listenAction)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
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)
|
||||
}
|
||||
}());
|
||||
export default vueSticky
|
||||
|
||||
|
@@ -1,54 +1,47 @@
|
||||
import './waves.css';
|
||||
(function() {
|
||||
const vueWaves = {};
|
||||
vueWaves.install = (Vue, options = {}) => {
|
||||
Vue.directive('waves', {
|
||||
bind(el, binding) {
|
||||
el.addEventListener('click', e => {
|
||||
const customOpts = Object.assign(options, binding.value);
|
||||
const opts = Object.assign({
|
||||
ele: el, // 波纹作用元素
|
||||
type: 'hit', // hit点击位置扩散center中心点扩展
|
||||
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
|
||||
}, customOpts),
|
||||
target = opts.ele;
|
||||
if (target) {
|
||||
target.style.position = 'relative';
|
||||
target.style.overflow = 'hidden';
|
||||
const rect = target.getBoundingClientRect();
|
||||
let ripple = target.querySelector('.waves-ripple');
|
||||
if (!ripple) {
|
||||
ripple = document.createElement('span');
|
||||
ripple.className = 'waves-ripple';
|
||||
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
|
||||
target.appendChild(ripple);
|
||||
} else {
|
||||
ripple.className = 'waves-ripple';
|
||||
}
|
||||
switch (opts.type) {
|
||||
case 'center':
|
||||
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
|
||||
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px';
|
||||
break;
|
||||
default:
|
||||
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.backgroundColor = opts.color;
|
||||
ripple.className = 'waves-ripple z-active';
|
||||
return false;
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
})
|
||||
};
|
||||
if (typeof exports == 'object') {
|
||||
module.exports = vueWaves
|
||||
} else if (typeof define == 'function' && define.amd) {
|
||||
define([], () => vueWaves)
|
||||
} else if (window.Vue) {
|
||||
window.vueWaves = vueWaves;
|
||||
Vue.use(vueWaves)
|
||||
}
|
||||
}());
|
||||
|
||||
const vueWaves = {};
|
||||
vueWaves.install = (Vue, options = {}) => {
|
||||
Vue.directive('waves', {
|
||||
bind(el, binding) {
|
||||
el.addEventListener('click', e => {
|
||||
const customOpts = Object.assign(options, binding.value);
|
||||
const opts = Object.assign({
|
||||
ele: el, // 波纹作用元素
|
||||
type: 'hit', // hit点击位置扩散center中心点扩展
|
||||
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
|
||||
}, customOpts),
|
||||
target = opts.ele;
|
||||
if (target) {
|
||||
target.style.position = 'relative';
|
||||
target.style.overflow = 'hidden';
|
||||
const rect = target.getBoundingClientRect();
|
||||
let ripple = target.querySelector('.waves-ripple');
|
||||
if (!ripple) {
|
||||
ripple = document.createElement('span');
|
||||
ripple.className = 'waves-ripple';
|
||||
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
|
||||
target.appendChild(ripple);
|
||||
} else {
|
||||
ripple.className = 'waves-ripple';
|
||||
}
|
||||
switch (opts.type) {
|
||||
case 'center':
|
||||
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
|
||||
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px';
|
||||
break;
|
||||
default:
|
||||
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.backgroundColor = opts.color;
|
||||
ripple.className = 'waves-ripple z-active';
|
||||
return false;
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
export default vueWaves;
|
||||
|
||||
|
@@ -104,5 +104,5 @@ export function html2Text(val) {
|
||||
|
||||
|
||||
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 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 */
|
||||
import Layout from '../views/layout/Layout';
|
||||
|
||||
/* login */
|
||||
import Login from '../views/login/';
|
||||
const authRedirect = () => import('../views/login/authredirect');
|
||||
const sendPWD = () => import('../views/login/sendpwd');
|
||||
const reset = () => import('../views/login/reset');
|
||||
const Login = _import('login/index');
|
||||
const authRedirect = _import('login/authredirect');
|
||||
const sendPWD = _import('login/sendpwd');
|
||||
const reset = _import('login/reset');
|
||||
|
||||
/* dashboard */
|
||||
const dashboard = () => import('../views/dashboard/index');
|
||||
const dashboard = _import('dashboard/index');
|
||||
|
||||
/* Introduction */
|
||||
const Introduction = () => import('../views/introduction/index');
|
||||
const Introduction = _import('introduction/index');
|
||||
|
||||
/* components */
|
||||
const componentsIndex = () => import('../views/components/index');
|
||||
const Tinymce = () => import('../views/components/tinymce');
|
||||
const Markdown = () => import('../views/components/markdown');
|
||||
const JsonEditor = () => import('../views/components/jsoneditor');
|
||||
const DndList = () => import('../views/components/dndlist');
|
||||
const AvatarUpload = () => import('../views/components/avatarUpload');
|
||||
const Dropzone = () => import('../views/components/dropzone');
|
||||
const Sticky = () => import('../views/components/sticky');
|
||||
const SplitPane = () => import('../views/components/splitpane');
|
||||
const CountTo = () => import('../views/components/countTo');
|
||||
const Mixin = () => import('../views/components/mixin');
|
||||
const componentsIndex = _import('components/index');
|
||||
const Tinymce = _import('components/tinymce');
|
||||
const Markdown = _import('components/markdown');
|
||||
const JsonEditor = _import('components/jsoneditor');
|
||||
const DndList = _import('components/dndlist');
|
||||
const AvatarUpload = _import('components/avatarUpload');
|
||||
const Dropzone = _import('components/dropzone');
|
||||
const Sticky = _import('components/sticky');
|
||||
const SplitPane = _import('components/splitpane');
|
||||
const CountTo = _import('components/countTo');
|
||||
const Mixin = _import('components/mixin');
|
||||
|
||||
|
||||
/* charts */
|
||||
const chartIndex = () => import('../views/charts/index');
|
||||
const KeyboardChart = () => import('../views/charts/keyboard');
|
||||
const KeyboardChart2 = () => import('../views/charts/keyboard2');
|
||||
const LineMarker = () => import('../views/charts/line');
|
||||
const MixChart = () => import('../views/charts/mixchart');
|
||||
const chartIndex = _import('charts/index');
|
||||
const KeyboardChart = _import('charts/keyboard');
|
||||
const KeyboardChart2 = _import('charts/keyboard2');
|
||||
const LineMarker = _import('charts/line');
|
||||
const MixChart = _import('charts/mixchart');
|
||||
|
||||
/* error page */
|
||||
const Err404 = () => import('../views/error/404');
|
||||
const Err401 = () => import('../views/error/401');
|
||||
const Err404 = _import('error/404');
|
||||
const Err401 = _import('error/401');
|
||||
|
||||
/* error log */
|
||||
const ErrorLog = () => import('../views/errlog/index');
|
||||
const ErrorLog = _import('errlog/index');
|
||||
|
||||
/* excel */
|
||||
const ExcelDownload = () => import('../views/excel/index');
|
||||
const ExcelDownload = _import('excel/index');
|
||||
|
||||
/* theme */
|
||||
const Theme = () => import('../views/theme/index');
|
||||
const Theme = _import('theme/index');
|
||||
|
||||
/* example*/
|
||||
const TableLayout = () => import('../views/example/table/index');
|
||||
const DynamicTable = () => import('../views/example/table/dynamictable');
|
||||
const Table = () => import('../views/example/table/table');
|
||||
const DragTable = () => import('../views/example/table/dragTable');
|
||||
const InlineEditTable = () => import('../views/example/table/inlineEditTable');
|
||||
const TableLayout = _import('example/table/index');
|
||||
const DynamicTable = _import('example/table/dynamictable');
|
||||
const Table = _import('example/table/table');
|
||||
const DragTable = _import('example/table/dragTable');
|
||||
const InlineEditTable = _import('example/table/inlineEditTable');
|
||||
|
||||
const Form = () => import('../views/example/form');
|
||||
const Tab = () => import('../views/example/tab/index');
|
||||
const Form = _import('example/form');
|
||||
const Tab = _import('example/tab/index');
|
||||
|
||||
/* permission */
|
||||
const Permission = () => import('../views/permission/index');
|
||||
const Permission = _import('permission/index');
|
||||
|
||||
|
||||
Vue.use(Router);
|
||||
@@ -196,9 +199,9 @@ export const asyncRouterMap = [
|
||||
icon: 'zonghe',
|
||||
children: [
|
||||
{
|
||||
path: '/table',
|
||||
path: '/example/table',
|
||||
component: TableLayout,
|
||||
redirect: '/table/table',
|
||||
redirect: '/example/table/table',
|
||||
name: 'Table',
|
||||
children: [
|
||||
{ path: 'dynamictable', component: DynamicTable, name: '动态table' },
|
||||
|
@@ -1,5 +1,6 @@
|
||||
const getters = {
|
||||
sidebar: state => state.app.sidebar,
|
||||
visitedViews: state => state.app.visitedViews,
|
||||
token: state => state.user.token,
|
||||
avatar: state => state.user.avatar,
|
||||
name: state => state.user.name,
|
||||
|
@@ -6,7 +6,8 @@ const app = {
|
||||
opened: !+Cookies.get('sidebarStatus')
|
||||
},
|
||||
theme: 'default',
|
||||
livenewsChannels: Cookies.get('livenewsChannels') || '[]'
|
||||
livenewsChannels: Cookies.get('livenewsChannels') || '[]',
|
||||
visitedViews: []
|
||||
},
|
||||
mutations: {
|
||||
TOGGLE_SIDEBAR: state => {
|
||||
@@ -16,11 +17,25 @@ const app = {
|
||||
Cookies.set('sidebarStatus', 0);
|
||||
}
|
||||
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: {
|
||||
ToggleSideBar: ({ commit }) => {
|
||||
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';
|
||||
|
||||
/**
|
||||
* 通过meta.role判断是否与当前用户权限匹配
|
||||
* @param roles
|
||||
* @param route
|
||||
*/
|
||||
function hasPermission(roles, route) {
|
||||
if (route.meta && route.meta.role) {
|
||||
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 = {
|
||||
state: {
|
||||
routers: constantRouterMap,
|
||||
addRouters: []
|
||||
},
|
||||
|
||||
mutations: {
|
||||
SET_ROUTERS: (state, routers) => {
|
||||
state.addRouters = routers;
|
||||
state.routers = constantRouterMap.concat(routers);
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
GenerateRoutes({ commit }, data) {
|
||||
return new Promise(resolve => {
|
||||
const { roles } = data;
|
||||
const accessedRouters = asyncRouterMap.filter(v => {
|
||||
if (roles.indexOf('admin') >= 0) return true;
|
||||
if (hasPermission(roles, v)) {
|
||||
if (v.children && v.children.length > 0) {
|
||||
v.children = v.children.filter(child => {
|
||||
if (hasPermission(roles, child)) {
|
||||
return child
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return v
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
const { roles } = data
|
||||
let accessedRouters
|
||||
if (roles.indexOf('admin') >= 0) {
|
||||
accessedRouters = asyncRouterMap
|
||||
} else {
|
||||
accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
|
||||
}
|
||||
commit('SET_ROUTERS', accessedRouters);
|
||||
resolve();
|
||||
})
|
||||
@@ -49,5 +59,4 @@ const permission = {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export default permission;
|
||||
|
@@ -24,27 +24,34 @@ service.interceptors.request.use(config => {
|
||||
|
||||
// respone拦截器
|
||||
service.interceptors.response.use(
|
||||
response => response
|
||||
response => response,
|
||||
/**
|
||||
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
|
||||
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
|
||||
*/
|
||||
// const code = response.data.code;
|
||||
// // 50014:Token 过期了 50012:其他客户端登录了 50008:非法的token
|
||||
// if (code === 50008 || code === 50014 || code === 50012) {
|
||||
// Message({
|
||||
// message: res.message,
|
||||
// type: 'error',
|
||||
// duration: 5 * 1000
|
||||
// });
|
||||
// // 登出
|
||||
// store.dispatch('FedLogOut').then(() => {
|
||||
// router.push({ path: '/login' })
|
||||
// });
|
||||
// } else {
|
||||
// return response
|
||||
// }
|
||||
,
|
||||
// const res = response.data;
|
||||
// if (res.code !== 20000) {
|
||||
// Message({
|
||||
// message: res.message,
|
||||
// type: 'error',
|
||||
// duration: 5 * 1000
|
||||
// });
|
||||
// // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
|
||||
// if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
|
||||
// MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
|
||||
// confirmButtonText: '重新登录',
|
||||
// cancelButtonText: '取消',
|
||||
// type: 'warning'
|
||||
// }).then(() => {
|
||||
// store.dispatch('FedLogOut').then(() => {
|
||||
// location.reload();// 为了重新实例化vue-router对象 避免bug
|
||||
// });
|
||||
// })
|
||||
// }
|
||||
// return Promise.reject(error);
|
||||
// } else {
|
||||
// return response.data;
|
||||
// }
|
||||
error => {
|
||||
console.log('err' + error);// for debug
|
||||
Message({
|
||||
|
@@ -40,8 +40,8 @@
|
||||
<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 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 tiffany-btn" to="/example/form1">form</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/form/edit">Form</router-link>
|
||||
</div>
|
||||
|
||||
<div class="clearfix main-dashboard-container">
|
||||
|
@@ -1,38 +1,19 @@
|
||||
<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="名称" 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 style='margin:0 0 5px 20px'>固定表头 按照表头顺序排序</div>
|
||||
<fixed-thead/>
|
||||
|
||||
<div style='margin:30px 0 5px 20px'>不固定表头 按照点击顺序排序</div>
|
||||
<unfixed-thead/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import fixedThead from './dynamictable/fixedThead'
|
||||
import unfixedThead from './dynamictable/unfixedThead'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
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']
|
||||
}
|
||||
}
|
||||
components: { fixedThead, unfixedThead }
|
||||
};
|
||||
</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">
|
||||
<hamburger class="hamburger-container" :toggleClick="toggleSideBar" :isActive="sidebar.opened"></hamburger>
|
||||
<levelbar></levelbar>
|
||||
<tabs-view></tabs-view>
|
||||
<error-log v-if="log.length>0" class="errLog-container" :logsList="log"></error-log>
|
||||
<screenfull class='screenfull'></screenfull>
|
||||
<el-dropdown class="avatar-container" trigger="click">
|
||||
<div class="avatar-wrapper">
|
||||
<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>
|
||||
<el-dropdown-menu class="user-dropdown" slot="dropdown">
|
||||
<router-link class='inlineBlock' to="/">
|
||||
@@ -29,6 +30,7 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import Levelbar from './Levelbar';
|
||||
import TabsView from './TabsView';
|
||||
import Hamburger from 'components/Hamburger';
|
||||
import Screenfull from 'components/Screenfull';
|
||||
import ErrorLog from 'components/ErrLog';
|
||||
@@ -37,6 +39,7 @@
|
||||
export default {
|
||||
components: {
|
||||
Levelbar,
|
||||
TabsView,
|
||||
Hamburger,
|
||||
ErrorLog,
|
||||
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