Compare commits

...

15 Commits

Author SHA1 Message Date
Pan
5cd245ac15 split tabs-view to separate files 2017-06-23 17:56:45 +08:00
Pan
0c3063f46c Release 1.0.3 2017-06-23 17:38:30 +08:00
Pan
91cb0ac5ca add view tabs 2017-06-23 17:36:13 +08:00
Pan
7549eb8044 fix eslint && refine code 2017-06-23 15:39:13 +08:00
孙晨光
1072572ac6 update: 递归过滤异步路由表 2017-06-23 15:25:58 +08:00
Pan
046d1369d2 not use Lazy Loading In dev 2017-06-21 16:59:02 +08:00
Pan
657937c7a5 Revert "refine css"
This reverts commit 6de521d671.
2017-06-21 09:46:47 +08:00
Pan
6de521d671 refine css 2017-06-20 23:14:50 +08:00
Pan
dbf9638922 refine dynamictable example 2017-06-20 23:02:36 +08:00
轩辕Rowboat
aaa64a8ccf update format code
没用编辑器,所以代码没格式化/(ㄒoㄒ)/~~
2017-06-20 15:44:14 +08:00
轩辕Rowboat
ff8d7ada73 千分符考虑小数点 2017-06-20 15:44:14 +08:00
Pan
bf480ca6b4 fix router path bug 2017-06-19 18:14:31 +08:00
Pan
803201af3a fix error link 2017-06-19 18:02:19 +08:00
Pan
e97dbf6115 use babel-preset-env 2017-06-19 17:59:56 +08:00
Pan
cf1fb6cd4d refine demo code 2017-06-15 15:35:14 +08:00
20 changed files with 415 additions and 247 deletions

View File

@@ -1,5 +1,8 @@
{ {
"presets": ["es2015", "stage-2"], "presets": [
["env", { "modules": false }],
"stage-2"
],
"plugins": ["transform-runtime"], "plugins": ["transform-runtime"],
"comments": false "comments": false
} }

View File

@@ -55,6 +55,7 @@ Join the group on QQ 591724180.
- cache tabs example - cache tabs example
- screenfull - screenfull
- markdown2html - markdown2html
- views-tab
## Development ## Development

View File

@@ -57,6 +57,7 @@
- cache tabs example - cache tabs example
- screenfull - screenfull
- markdown2html - markdown2html
- views-tab
## 开发 ## 开发

View File

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

View File

@@ -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 stickyCurrently Safari, Firefox and Chrome Canary // if the browser support css stickyCurrently 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)
}
}());

View File

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

View File

@@ -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, ','));
} }

View File

@@ -0,0 +1 @@
module.exports = file => require('../views/' + file + '.vue')

View File

@@ -0,0 +1 @@
module.exports = file => () => import('../views/' + file + '.vue')

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

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