Compare commits
23 Commits
3.5.0
...
perf/keep-
Author | SHA1 | Date | |
---|---|---|---|
|
d431de0589 | ||
|
6f2a7ce804 | ||
|
2e0d3fd0e4 | ||
|
bc01171466 | ||
|
4e65890b6a | ||
|
79c5cb4fcd | ||
|
0d47e3454e | ||
|
3253a91a7e | ||
|
fea6e5feee | ||
|
1610945813 | ||
|
840eda6e27 | ||
|
700e08b795 | ||
|
3c0696d1a9 | ||
|
76a6eb12e7 | ||
|
2c147649ba | ||
|
de3b29b5f3 | ||
|
54acf1e0d5 | ||
|
de08e49f19 | ||
|
2472107768 | ||
|
d18902dfee | ||
|
9ba2648689 | ||
|
1d0b26cec8 | ||
|
ea7e139696 |
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"plugins": {
|
"plugins": {
|
||||||
// to edit target browsers: use "browserslist" field in package.json
|
|
||||||
"postcss-import": {},
|
"postcss-import": {},
|
||||||
|
"postcss-url": {},
|
||||||
|
// to edit target browsers: use "browserslist" field in package.json
|
||||||
"autoprefixer": {}
|
"autoprefixer": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -78,6 +78,7 @@ You need to install [node](http://nodejs.org/) and [git](https://git-scm.com/) l
|
|||||||
- Export excel
|
- Export excel
|
||||||
- Export zip
|
- Export zip
|
||||||
- Front-end visualization excel
|
- Front-end visualization excel
|
||||||
|
- Tree Table
|
||||||
- Table example
|
- Table example
|
||||||
- Dynamictable example
|
- Dynamictable example
|
||||||
- Drag and drop table example
|
- Drag and drop table example
|
||||||
|
@@ -91,6 +91,7 @@
|
|||||||
- 导出excel
|
- 导出excel
|
||||||
- 导出zip
|
- 导出zip
|
||||||
- 前端可视化excel
|
- 前端可视化excel
|
||||||
|
- 树形table
|
||||||
- Table example
|
- Table example
|
||||||
- 动态table example
|
- 动态table example
|
||||||
- 拖拽table example
|
- 拖拽table example
|
||||||
|
@@ -33,7 +33,7 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// https://webpack.js.org/configuration/devtool/#development
|
// https://webpack.js.org/configuration/devtool/#development
|
||||||
devtool: 'eval-source-map',
|
devtool: '#cheap-source-map',
|
||||||
|
|
||||||
// If you have problems debugging vue-files in devtools,
|
// If you have problems debugging vue-files in devtools,
|
||||||
// set this to false - it *may* help
|
// set this to false - it *may* help
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vue-element-admin",
|
"name": "vue-element-admin",
|
||||||
"version": "3.5.0",
|
"version": "3.6.1",
|
||||||
"description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features",
|
"description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features",
|
||||||
"author": "Pan <panfree23@gmail.com>",
|
"author": "Pan <panfree23@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"vue-splitpane": "1.0.2",
|
"vue-splitpane": "1.0.2",
|
||||||
"vuedraggable": "2.15.0",
|
"vuedraggable": "2.15.0",
|
||||||
"vuex": "3.0.1",
|
"vuex": "3.0.1",
|
||||||
"xlsx": "^0.11.7"
|
"xlsx": "^0.11.16"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "7.2.3",
|
"autoprefixer": "7.2.3",
|
||||||
@@ -71,6 +71,7 @@
|
|||||||
"portfinder": "1.0.13",
|
"portfinder": "1.0.13",
|
||||||
"postcss-import": "11.0.0",
|
"postcss-import": "11.0.0",
|
||||||
"postcss-loader": "2.0.9",
|
"postcss-loader": "2.0.9",
|
||||||
|
"postcss-url": "7.3.0",
|
||||||
"pushstate-server": "3.0.1",
|
"pushstate-server": "3.0.1",
|
||||||
"rimraf": "2.6.2",
|
"rimraf": "2.6.2",
|
||||||
"sass-loader": "6.0.6",
|
"sass-loader": "6.0.6",
|
||||||
|
@@ -53,11 +53,19 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style scoped>
|
||||||
.CodeMirror {
|
.json-editor{
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.json-editor .cm-s-rubyblue span.cm-string {
|
.json-editor >>> .CodeMirror {
|
||||||
|
height: auto;
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
.json-editor >>> .CodeMirror-scroll{
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
.json-editor >>> .cm-s-rubyblue span.cm-string {
|
||||||
color: #F08047;
|
color: #F08047;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -34,7 +34,7 @@ export default {
|
|||||||
.international-icon {
|
.international-icon {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
vertical-align: -5px;
|
vertical-align: -5px!important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
29
src/components/TreeTable/eval.js
Normal file
29
src/components/TreeTable/eval.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* @Author: jianglei
|
||||||
|
* @Date: 2017-10-12 12:06:49
|
||||||
|
*/
|
||||||
|
'use strict'
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default function treeToArray(data, expandedAll, parent = null, level = null) {
|
||||||
|
let tmp = []
|
||||||
|
Array.from(data).forEach(function(record) {
|
||||||
|
if (record._expanded === undefined) {
|
||||||
|
Vue.set(record, '_expanded', expandedAll)
|
||||||
|
}
|
||||||
|
let _level = 1
|
||||||
|
if (level !== undefined && level !== null) {
|
||||||
|
_level = level + 1
|
||||||
|
}
|
||||||
|
Vue.set(record, '_level', _level)
|
||||||
|
// 如果有父元素
|
||||||
|
if (parent) {
|
||||||
|
Vue.set(record, 'parent', parent)
|
||||||
|
}
|
||||||
|
tmp.push(record)
|
||||||
|
if (record.children && record.children.length > 0) {
|
||||||
|
const children = treeToArray(record.children, expandedAll, record, _level)
|
||||||
|
tmp = tmp.concat(children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return tmp
|
||||||
|
}
|
114
src/components/TreeTable/index.vue
Normal file
114
src/components/TreeTable/index.vue
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<template>
|
||||||
|
<el-table :data="formatData" :row-style="showRow" v-bind="$attrs">
|
||||||
|
<el-table-column v-if="columns.length===0" width="150">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span v-for="space in scope.row._level" class="ms-tree-space" :key="space"></span>
|
||||||
|
<span class="tree-ctrl" v-if="iconShow(0,scope.row)" @click="toggleExpanded(scope.$index)">
|
||||||
|
<i v-if="!scope.row._expanded" class="el-icon-plus"></i>
|
||||||
|
<i v-else class="el-icon-minus"></i>
|
||||||
|
</span>
|
||||||
|
{{scope.$index}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-else v-for="(column, index) in columns" :key="column.value" :label="column.text" :width="column.width">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span v-if="index === 0" v-for="space in scope.row._level" class="ms-tree-space" :key="space"></span>
|
||||||
|
<span class="tree-ctrl" v-if="iconShow(index,scope.row)" @click="toggleExpanded(scope.$index)">
|
||||||
|
<i v-if="!scope.row._expanded" class="el-icon-plus"></i>
|
||||||
|
<i v-else class="el-icon-minus"></i>
|
||||||
|
</span>
|
||||||
|
{{scope.row[column.value]}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<slot></slot>
|
||||||
|
</el-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
Auth: Lei.j1ang
|
||||||
|
Created: 2018/1/19-13:59
|
||||||
|
*/
|
||||||
|
import treeToArray from './eval'
|
||||||
|
export default {
|
||||||
|
name: 'treeTable',
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: [Array, Object],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
evalFunc: Function,
|
||||||
|
evalArgs: Array,
|
||||||
|
expandAll: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 格式化数据源
|
||||||
|
formatData: function() {
|
||||||
|
let tmp
|
||||||
|
if (!Array.isArray(this.data)) {
|
||||||
|
tmp = [this.data]
|
||||||
|
} else {
|
||||||
|
tmp = this.data
|
||||||
|
}
|
||||||
|
const func = this.evalFunc || treeToArray
|
||||||
|
const args = this.evalArgs ? Array.concat([tmp], this.evalArgs) : [tmp, this.expandAll]
|
||||||
|
return func.apply(null, args)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showRow: function(row) {
|
||||||
|
const show = (row.row.parent ? (row.row.parent._expanded && row.row.parent._show) : true)
|
||||||
|
row.row._show = show
|
||||||
|
return show ? '' : 'display:none;'
|
||||||
|
},
|
||||||
|
// 切换下级是否展开
|
||||||
|
toggleExpanded: function(trIndex) {
|
||||||
|
const record = this.formatData[trIndex]
|
||||||
|
record._expanded = !record._expanded
|
||||||
|
},
|
||||||
|
// 图标显示
|
||||||
|
iconShow(index, record) {
|
||||||
|
return (index === 0 && record.children && record.children.length > 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
|
$color-blue: #2196F3;
|
||||||
|
$space-width: 18px;
|
||||||
|
.ms-tree-space {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
display: inline-block;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
width: $space-width;
|
||||||
|
height: 14px;
|
||||||
|
&::before {
|
||||||
|
content: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.processContainer{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
table td {
|
||||||
|
line-height: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-ctrl{
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
color: $color-blue;
|
||||||
|
margin-left: -$space-width;
|
||||||
|
}
|
||||||
|
</style>
|
89
src/components/TreeTable/readme.md
Normal file
89
src/components/TreeTable/readme.md
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
## 写在前面
|
||||||
|
此组件仅提供一个创建TreeTable的解决思路
|
||||||
|
|
||||||
|
## prop说明
|
||||||
|
#### *data*
|
||||||
|
**必填**
|
||||||
|
|
||||||
|
原始数据,要求是一个数组或者对象
|
||||||
|
```javascript
|
||||||
|
[{
|
||||||
|
key1: value1,
|
||||||
|
key2: value2,
|
||||||
|
children: [{
|
||||||
|
key1: value1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key1: value1
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key1: value1
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
或者
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
key1: value1,
|
||||||
|
key2: value2,
|
||||||
|
children: [{
|
||||||
|
key1: value1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key1: value1
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### columns
|
||||||
|
列属性,要求是一个数组
|
||||||
|
|
||||||
|
1. text: 显示在表头的文字
|
||||||
|
2. value: 对应data的key。treeTable将显示相应的value
|
||||||
|
3. width: 每列的宽度,为一个数字(可选)
|
||||||
|
|
||||||
|
如果你想要每个字段都有自定义的样式或者嵌套其他组件,columns可不提供,直接像在el-table一样写即可,如果没有自定义内容,提供columns将更加的便捷方便
|
||||||
|
|
||||||
|
如果你有几个字段是需要自定义的,几个不需要,那么可以将不需要自定义的字段放入columns,将需要自定义的内容放入到slot中,详情见后文
|
||||||
|
```javascript
|
||||||
|
[{
|
||||||
|
value:string,
|
||||||
|
text:string,
|
||||||
|
width:number
|
||||||
|
},{
|
||||||
|
value:string,
|
||||||
|
text:string,
|
||||||
|
width:number
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### expandAll
|
||||||
|
是否默认全部展开,boolean值,默认为false
|
||||||
|
|
||||||
|
#### evalFunc
|
||||||
|
解析函数,function,非必须
|
||||||
|
|
||||||
|
如果不提供,将使用默认的[evalFunc](./eval.js)
|
||||||
|
|
||||||
|
如果提供了evalFunc,那么会用提供的evalFunc去解析data,并返回treeTable渲染所需要的值。如何编写一个evalFunc,请参考[*eval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/components/TreeTable/eval.js)或[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/example/table/treeTable/customEval.js)
|
||||||
|
|
||||||
|
#### evalArgs
|
||||||
|
解析函数的参数,是一个数组
|
||||||
|
|
||||||
|
**请注意,自定义的解析函数参数第一个为this.data,你不需要在evalArgs填写。** *this.data为需要解析的数据*
|
||||||
|
|
||||||
|
如你的解析函数需要的参数为`(this.data,1,2,3,4)`,那么你只需要将`[1,2,3,4]`赋值给`evalArgs`就可以了
|
||||||
|
|
||||||
|
如果你的解析函数参数只有一个`(this.data)`,那么就可以不用填写evalArgs了
|
||||||
|
|
||||||
|
具体可参考[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/example/table/treeTable/customEval.js)的函数参数和[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/example/table/treeTable/customTreeTable.vue)的`evalArgs`属性值
|
||||||
|
|
||||||
|
## slot
|
||||||
|
这是一个自定义列的插槽。
|
||||||
|
|
||||||
|
默认情况下,treeTable只有一行行展示数据的功能。但是一般情况下,我们会要给行加上一个操作按钮或者根据当行数据展示不同的样式,这时我们就需要自定义列了。请参考[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/example/table/treeTable/customTreeTable.vue),[实例效果](http://panjiachen.github.io/vue-element-admin/#/example/table/custom-tree-table)
|
||||||
|
|
||||||
|
`slot`和`columns属性`可同时存在,columns里面的数据列会在slot自定义列的左边展示
|
||||||
|
|
||||||
|
## 其他
|
||||||
|
如果有其他的需求,请参考[el-table](http://element-cn.eleme.io/#/en-US/component/table)的api自行修改index.vue
|
@@ -1,7 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-button :loading="loading" type="primary" @click="handleUpload">select excel file</el-button>
|
|
||||||
<input id="excel-upload-input" type="file" accept=".xlsx, .xls" class="c-hide" @change="handkeFileChange">
|
<input id="excel-upload-input" type="file" accept=".xlsx, .xls" class="c-hide" @change="handkeFileChange">
|
||||||
|
<div id="drop" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover">
|
||||||
|
Drop excel file here or
|
||||||
|
<el-button style="margin-left:16px;" size="mini" type="primary" @click="handleUpload">browse</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -22,16 +25,35 @@ export default {
|
|||||||
generateDate({ header, results }) {
|
generateDate({ header, results }) {
|
||||||
this.excelData.header = header
|
this.excelData.header = header
|
||||||
this.excelData.results = results
|
this.excelData.results = results
|
||||||
this.loading = false
|
|
||||||
this.$emit('on-selected-file', this.excelData)
|
this.$emit('on-selected-file', this.excelData)
|
||||||
},
|
},
|
||||||
|
handleDrop(e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
const files = e.dataTransfer.files
|
||||||
|
if (files.length !== 1) {
|
||||||
|
this.$message.error('Only support uploading one file!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const itemFile = files[0] // only use files[0]
|
||||||
|
this.readerData(itemFile)
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
},
|
||||||
|
handleDragover(e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
e.dataTransfer.dropEffect = 'copy'
|
||||||
|
},
|
||||||
handleUpload() {
|
handleUpload() {
|
||||||
document.getElementById('excel-upload-input').click()
|
document.getElementById('excel-upload-input').click()
|
||||||
},
|
},
|
||||||
handkeFileChange(e) {
|
handkeFileChange(e) {
|
||||||
this.loading = true
|
|
||||||
const files = e.target.files
|
const files = e.target.files
|
||||||
const itemFile = files[0] // only use files[0]
|
const itemFile = files[0] // only use files[0]
|
||||||
|
this.readerData(itemFile)
|
||||||
|
},
|
||||||
|
readerData(itemFile) {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.onload = e => {
|
reader.onload = e => {
|
||||||
const data = e.target.result
|
const data = e.target.result
|
||||||
@@ -75,4 +97,16 @@ export default {
|
|||||||
display: none;
|
display: none;
|
||||||
z-index: -9999;
|
z-index: -9999;
|
||||||
}
|
}
|
||||||
|
#drop{
|
||||||
|
border: 2px dashed #bbb;
|
||||||
|
width: 600px;
|
||||||
|
height: 160px;
|
||||||
|
line-height: 160px;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-size: 24px;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
color: #bbb;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -28,6 +28,8 @@ export default {
|
|||||||
dragTable: 'Drag Table',
|
dragTable: 'Drag Table',
|
||||||
inlineEditTable: 'Inline Edit',
|
inlineEditTable: 'Inline Edit',
|
||||||
complexTable: 'Complex Table',
|
complexTable: 'Complex Table',
|
||||||
|
treeTable: 'treeTable',
|
||||||
|
customTreeTable: 'Custom TreeTable',
|
||||||
tab: 'Tab',
|
tab: 'Tab',
|
||||||
form: 'Form',
|
form: 'Form',
|
||||||
createForm: 'Create Form',
|
createForm: 'Create Form',
|
||||||
@@ -40,7 +42,8 @@ export default {
|
|||||||
exportExcel: 'Export Excel',
|
exportExcel: 'Export Excel',
|
||||||
selectExcel: 'Export Selected',
|
selectExcel: 'Export Selected',
|
||||||
uploadExcel: 'Upload Excel',
|
uploadExcel: 'Upload Excel',
|
||||||
exportZip: 'Zip',
|
zip: 'Zip',
|
||||||
|
exportZip: 'Export Zip',
|
||||||
theme: 'Theme',
|
theme: 'Theme',
|
||||||
clipboardDemo: 'Clipboard',
|
clipboardDemo: 'Clipboard',
|
||||||
i18n: 'I18n'
|
i18n: 'I18n'
|
||||||
|
@@ -24,10 +24,12 @@ export default {
|
|||||||
mixChart: '混合图表',
|
mixChart: '混合图表',
|
||||||
example: '综合实例',
|
example: '综合实例',
|
||||||
Table: 'Table',
|
Table: 'Table',
|
||||||
dynamicTable: '动态table',
|
dynamicTable: '动态Table',
|
||||||
dragTable: '拖拽table',
|
dragTable: '拖拽Table',
|
||||||
inlineEditTable: 'table内编辑',
|
inlineEditTable: 'Table内编辑',
|
||||||
complexTable: '综合table',
|
complexTable: '综合Table',
|
||||||
|
treeTable: '树形表格',
|
||||||
|
customTreeTable: '自定义树表',
|
||||||
tab: 'Tab',
|
tab: 'Tab',
|
||||||
form: '表单',
|
form: '表单',
|
||||||
createForm: '创建表单',
|
createForm: '创建表单',
|
||||||
@@ -36,13 +38,14 @@ export default {
|
|||||||
page401: '401',
|
page401: '401',
|
||||||
page404: '404',
|
page404: '404',
|
||||||
errorLog: '错误日志',
|
errorLog: '错误日志',
|
||||||
excel: 'excel',
|
excel: 'Excel',
|
||||||
exportExcel: 'export excel',
|
exportExcel: 'Export Excel',
|
||||||
selectExcel: 'export selected',
|
selectExcel: 'Export Selected',
|
||||||
uploadExcel: 'upload excel',
|
uploadExcel: 'Upload Excel',
|
||||||
exportZip: 'zip',
|
zip: 'Zip',
|
||||||
|
exportZip: 'Export Zip',
|
||||||
theme: '换肤',
|
theme: '换肤',
|
||||||
clipboardDemo: 'clipboard',
|
clipboardDemo: 'Clipboard',
|
||||||
i18n: '国际化'
|
i18n: '国际化'
|
||||||
},
|
},
|
||||||
navbar: {
|
navbar: {
|
||||||
|
@@ -2,14 +2,14 @@ import { param2Obj } from '@/utils'
|
|||||||
|
|
||||||
const userMap = {
|
const userMap = {
|
||||||
admin: {
|
admin: {
|
||||||
role: ['admin'],
|
roles: ['admin'],
|
||||||
token: 'admin',
|
token: 'admin',
|
||||||
introduction: '我是超级管理员',
|
introduction: '我是超级管理员',
|
||||||
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
|
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
|
||||||
name: 'Super Admin'
|
name: 'Super Admin'
|
||||||
},
|
},
|
||||||
editor: {
|
editor: {
|
||||||
role: ['editor'],
|
roles: ['editor'],
|
||||||
token: 'editor',
|
token: 'editor',
|
||||||
introduction: '我是编辑',
|
introduction: '我是编辑',
|
||||||
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
|
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
|
||||||
|
@@ -1,11 +1,13 @@
|
|||||||
import router from './router'
|
import router from './router'
|
||||||
import store from './store'
|
import store from './store'
|
||||||
|
import { Message } from 'element-ui'
|
||||||
import NProgress from 'nprogress' // progress bar
|
import NProgress from 'nprogress' // progress bar
|
||||||
import 'nprogress/nprogress.css'// progress bar style
|
import 'nprogress/nprogress.css'// progress bar style
|
||||||
import { getToken } from '@/utils/auth' // getToken from cookie
|
import { getToken } from '@/utils/auth' // getToken from cookie
|
||||||
import { Message } from 'element-ui'
|
|
||||||
|
|
||||||
// permissiom judge
|
NProgress.configure({ showSpinner: false })// NProgress Configuration
|
||||||
|
|
||||||
|
// permissiom judge function
|
||||||
function hasPermission(roles, permissionRoles) {
|
function hasPermission(roles, permissionRoles) {
|
||||||
if (roles.indexOf('admin') >= 0) return true // admin permission passed directly
|
if (roles.indexOf('admin') >= 0) return true // admin permission passed directly
|
||||||
if (!permissionRoles) return true
|
if (!permissionRoles) return true
|
||||||
@@ -16,15 +18,16 @@ const whiteList = ['/login', '/authredirect']// no redirect whitelist
|
|||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
NProgress.start() // start progress bar
|
NProgress.start() // start progress bar
|
||||||
if (getToken()) { // 判断是否有token
|
if (getToken()) { // determine if there has token
|
||||||
|
/* has token*/
|
||||||
if (to.path === '/login') {
|
if (to.path === '/login') {
|
||||||
next({ path: '/' })
|
next({ path: '/' })
|
||||||
NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
|
NProgress.done() // if current page is dashboard will not trigger afterEach hook, so manually handle it
|
||||||
} else {
|
} else {
|
||||||
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
|
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
|
||||||
store.dispatch('GetUserInfo').then(res => { // 拉取user_info
|
store.dispatch('GetUserInfo').then(res => { // 拉取user_info
|
||||||
const roles = res.data.role
|
const roles = res.data.roles // note: roles must be a array! such as: ['editor','develop']
|
||||||
store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
|
store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表
|
||||||
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
|
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
|
||||||
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
|
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
|
||||||
})
|
})
|
||||||
@@ -36,21 +39,21 @@ router.beforeEach((to, from, next) => {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
|
// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
|
||||||
if (hasPermission(store.getters.roles, to.meta.role)) {
|
if (hasPermission(store.getters.roles, to.meta.roles)) {
|
||||||
next()//
|
next()//
|
||||||
} else {
|
} else {
|
||||||
next({ path: '/401', query: { noGoBack: true }})
|
next({ path: '/401', replace: true, query: { noGoBack: true }})
|
||||||
NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
|
|
||||||
}
|
}
|
||||||
// 可删 ↑
|
// 可删 ↑
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* has no token*/
|
||||||
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
|
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
|
||||||
next()
|
next()
|
||||||
} else {
|
} else {
|
||||||
next('/login') // 否则全部重定向到登录页
|
next('/login') // 否则全部重定向到登录页
|
||||||
NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
|
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@@ -15,10 +15,13 @@ import Layout from '../views/layout/Layout'
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* hidden: true if `hidden:true` will not show in the sidebar(default is false)
|
* hidden: true if `hidden:true` will not show in the sidebar(default is false)
|
||||||
|
* alwaysShow: true if set true, will always show the root menu, whatever its child routes length
|
||||||
|
* if not set alwaysShow, only more than one route under the children
|
||||||
|
* it will becomes nested mode, otherwise not show the root menu
|
||||||
* redirect: noredirect if `redirect:noredirect` will no redirct in the breadcrumb
|
* redirect: noredirect if `redirect:noredirect` will no redirct in the breadcrumb
|
||||||
* name:'router-name' the name is used by <keep-alive> (must set!!!)
|
* name:'router-name' the name is used by <keep-alive> (must set!!!)
|
||||||
* meta : {
|
* meta : {
|
||||||
role: ['admin','editor'] will control the page role (you can set multiple roles)
|
roles: ['admin','editor'] will control the page roles (you can set multiple roles)
|
||||||
title: 'title' the name show in submenu and breadcrumb (recommend set)
|
title: 'title' the name show in submenu and breadcrumb (recommend set)
|
||||||
icon: 'svg-name' the icon show in the sidebar,
|
icon: 'svg-name' the icon show in the sidebar,
|
||||||
noCache: true if fasle ,the page will no be cached(default is false)
|
noCache: true if fasle ,the page will no be cached(default is false)
|
||||||
@@ -54,7 +57,7 @@ export const constantRouterMap = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export default new Router({
|
export default new Router({
|
||||||
// mode: 'history', //后端支持可开
|
// mode: 'history', // require service support
|
||||||
scrollBehavior: () => ({ y: 0 }),
|
scrollBehavior: () => ({ y: 0 }),
|
||||||
routes: constantRouterMap
|
routes: constantRouterMap
|
||||||
})
|
})
|
||||||
@@ -64,7 +67,7 @@ export const asyncRouterMap = [
|
|||||||
path: '/permission',
|
path: '/permission',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/permission/index',
|
redirect: '/permission/index',
|
||||||
meta: { role: ['admin'] },
|
meta: { roles: ['admin'] }, // you can set roles in root nav
|
||||||
children: [{
|
children: [{
|
||||||
path: 'index',
|
path: 'index',
|
||||||
component: _import('permission/index'),
|
component: _import('permission/index'),
|
||||||
@@ -72,7 +75,7 @@ export const asyncRouterMap = [
|
|||||||
meta: {
|
meta: {
|
||||||
title: 'permission',
|
title: 'permission',
|
||||||
icon: 'lock',
|
icon: 'lock',
|
||||||
role: ['admin']
|
roles: ['admin'] // or you can only set roles in sub nav
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
@@ -151,6 +154,8 @@ export const asyncRouterMap = [
|
|||||||
{ path: 'dynamic-table', component: _import('example/table/dynamicTable/index'), name: 'dynamicTable', meta: { title: 'dynamicTable' }},
|
{ path: 'dynamic-table', component: _import('example/table/dynamicTable/index'), name: 'dynamicTable', meta: { title: 'dynamicTable' }},
|
||||||
{ path: 'drag-table', component: _import('example/table/dragTable'), name: 'dragTable', meta: { title: 'dragTable' }},
|
{ path: 'drag-table', component: _import('example/table/dragTable'), name: 'dragTable', meta: { title: 'dragTable' }},
|
||||||
{ path: 'inline-edit-table', component: _import('example/table/inlineEditTable'), name: 'inlineEditTable', meta: { title: 'inlineEditTable' }},
|
{ path: 'inline-edit-table', component: _import('example/table/inlineEditTable'), name: 'inlineEditTable', meta: { title: 'inlineEditTable' }},
|
||||||
|
{ path: 'tree-table', component: _import('example/table/treeTable/treeTable'), name: 'treeTable', meta: { title: 'treeTable' }},
|
||||||
|
{ path: 'custom-tree-table', component: _import('example/table/treeTable/customTreeTable'), name: 'customTreeTable', meta: { title: 'customTreeTable' }},
|
||||||
{ path: 'complex-table', component: _import('example/table/complexTable'), name: 'complexTable', meta: { title: 'complexTable' }}
|
{ path: 'complex-table', component: _import('example/table/complexTable'), name: 'complexTable', meta: { title: 'complexTable' }}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -215,7 +220,9 @@ export const asyncRouterMap = [
|
|||||||
path: '/zip',
|
path: '/zip',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/zip/download',
|
redirect: '/zip/download',
|
||||||
children: [{ path: 'download', component: _import('zip/index'), name: 'exportZip', meta: { title: 'exportZip', icon: 'zip' }}]
|
alwaysShow: true,
|
||||||
|
meta: { title: 'zip', icon: 'zip' },
|
||||||
|
children: [{ path: 'download', component: _import('zip/index'), name: 'exportZip', meta: { title: 'exportZip' }}]
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@@ -5,7 +5,7 @@ const app = {
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
opened: !+Cookies.get('sidebarStatus')
|
opened: !+Cookies.get('sidebarStatus')
|
||||||
},
|
},
|
||||||
language: Cookies.get('language') || 'zh'
|
language: Cookies.get('language') || 'en'
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
TOGGLE_SIDEBAR: state => {
|
TOGGLE_SIDEBAR: state => {
|
||||||
|
@@ -6,8 +6,8 @@ import { asyncRouterMap, constantRouterMap } from '@/router'
|
|||||||
* @param route
|
* @param route
|
||||||
*/
|
*/
|
||||||
function hasPermission(roles, route) {
|
function hasPermission(roles, route) {
|
||||||
if (route.meta && route.meta.role) {
|
if (route.meta && route.meta.roles) {
|
||||||
return roles.some(role => route.meta.role.indexOf(role) >= 0)
|
return roles.some(role => route.meta.roles.indexOf(role) >= 0)
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@@ -6,14 +6,21 @@ const tagsView = {
|
|||||||
mutations: {
|
mutations: {
|
||||||
ADD_VISITED_VIEWS: (state, view) => {
|
ADD_VISITED_VIEWS: (state, view) => {
|
||||||
if (state.visitedViews.some(v => v.path === view.path)) return
|
if (state.visitedViews.some(v => v.path === view.path)) return
|
||||||
state.visitedViews.push({
|
|
||||||
name: view.name,
|
if (view.showInVisitedViews) {
|
||||||
path: view.path,
|
state.visitedViews.push({
|
||||||
title: view.meta.title || 'no-name'
|
name: view.name,
|
||||||
})
|
path: view.path,
|
||||||
if (!view.meta.noCache) {
|
title: view.meta.title || 'no-name'
|
||||||
state.cachedViews.push(view.name)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!view.meta.noCache) {
|
||||||
|
const cachedViews = [...state.cachedViews]
|
||||||
|
cachedViews.push(view.name)
|
||||||
|
state.cachedViews = Array.from(new Set([...cachedViews]))
|
||||||
|
}
|
||||||
|
console.log(state.cachedViews)
|
||||||
},
|
},
|
||||||
DEL_VISITED_VIEWS: (state, view) => {
|
DEL_VISITED_VIEWS: (state, view) => {
|
||||||
for (const [i, v] of state.visitedViews.entries()) {
|
for (const [i, v] of state.visitedViews.entries()) {
|
||||||
@@ -25,7 +32,7 @@ const tagsView = {
|
|||||||
for (const i of state.cachedViews) {
|
for (const i of state.cachedViews) {
|
||||||
if (i === view.name) {
|
if (i === view.name) {
|
||||||
const index = state.cachedViews.indexOf(i)
|
const index = state.cachedViews.indexOf(i)
|
||||||
state.cachedViews.splice(index, index + 1)
|
state.cachedViews.splice(index, 1)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -67,7 +67,7 @@ const user = {
|
|||||||
reject('error')
|
reject('error')
|
||||||
}
|
}
|
||||||
const data = response.data
|
const data = response.data
|
||||||
commit('SET_ROLES', data.role)
|
commit('SET_ROLES', data.roles)
|
||||||
commit('SET_NAME', data.name)
|
commit('SET_NAME', data.name)
|
||||||
commit('SET_AVATAR', data.avatar)
|
commit('SET_AVATAR', data.avatar)
|
||||||
commit('SET_INTRODUCTION', data.introduction)
|
commit('SET_INTRODUCTION', data.introduction)
|
||||||
@@ -116,13 +116,13 @@ const user = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 动态修改权限
|
// 动态修改权限
|
||||||
ChangeRole({ commit }, role) {
|
ChangeRoles({ commit }, role) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
commit('SET_TOKEN', role)
|
commit('SET_TOKEN', role)
|
||||||
setToken(role)
|
setToken(role)
|
||||||
getUserInfo(role).then(response => {
|
getUserInfo(role).then(response => {
|
||||||
const data = response.data
|
const data = response.data
|
||||||
commit('SET_ROLES', data.role)
|
commit('SET_ROLES', data.roles)
|
||||||
commit('SET_NAME', data.name)
|
commit('SET_NAME', data.name)
|
||||||
commit('SET_AVATAR', data.avatar)
|
commit('SET_AVATAR', data.avatar)
|
||||||
commit('SET_INTRODUCTION', data.introduction)
|
commit('SET_INTRODUCTION', data.introduction)
|
||||||
|
@@ -140,10 +140,6 @@ code {
|
|||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-container .CodeMirror {
|
|
||||||
height: 100%!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
text-align: center
|
text-align: center
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,10 @@
|
|||||||
// translate router.meta.title, be used in breadcrumb sidebar tagsview
|
// translate router.meta.title, be used in breadcrumb sidebar tagsview
|
||||||
export function generateTitle(title) {
|
export function generateTitle(title) {
|
||||||
return this.$t('route.' + title) // $t :this method from vue-i18n, inject in @/lang/index.js
|
const hasKey = this.$te('route.' + title)
|
||||||
|
const translatedTitle = this.$t('route.' + title) // $t :this method from vue-i18n, inject in @/lang/index.js
|
||||||
|
|
||||||
|
if (hasKey) {
|
||||||
|
return translatedTitle
|
||||||
|
}
|
||||||
|
return title
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="components-container" style="height:100vh">
|
<div class="components-container">
|
||||||
<code>JsonEditor is base on <a href="https://github.com/codemirror/CodeMirror" target="_blank">CodeMirrorr</a> , lint base on json-lint </code>
|
<code>JsonEditor is base on <a href="https://github.com/codemirror/CodeMirror" target="_blank">CodeMirrorr</a> , lint base on json-lint </code>
|
||||||
<div class="editor-container">
|
<div class="editor-container">
|
||||||
<json-editor ref="jsonEditor" v-model="value"></json-editor>
|
<json-editor ref="jsonEditor" v-model="value"></json-editor>
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'TableMain',
|
name: 'Table',
|
||||||
computed: {
|
computed: {
|
||||||
cachedViews() {
|
cachedViews() {
|
||||||
return this.$store.state.tagsView.cachedViews
|
return this.$store.state.tagsView.cachedViews
|
||||||
|
48
src/views/example/table/treeTable/customEval.js
Normal file
48
src/views/example/table/treeTable/customEval.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* @Author: jianglei
|
||||||
|
* @Date: 2017-10-12 12:06:49
|
||||||
|
*/
|
||||||
|
'use strict'
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default function treeToArray(data, parent, level, expandedAll, item) {
|
||||||
|
const marLTemp = []
|
||||||
|
let tmp = []
|
||||||
|
Array.from(data).forEach(function(record) {
|
||||||
|
if (record._expanded === undefined) {
|
||||||
|
Vue.set(record, '_expanded', expandedAll)
|
||||||
|
}
|
||||||
|
let _level = 1
|
||||||
|
if (level !== undefined && level !== null) {
|
||||||
|
_level = level + 1
|
||||||
|
}
|
||||||
|
Vue.set(record, '_level', _level)
|
||||||
|
// 如果有父元素
|
||||||
|
if (parent) {
|
||||||
|
Vue.set(record, 'parent', parent)
|
||||||
|
// 如果父元素有偏移量,需要计算在this的偏移量中
|
||||||
|
// 偏移量还与前面同级元素有关,需要加上前面所有元素的长度和
|
||||||
|
if (!marLTemp[_level]) {
|
||||||
|
marLTemp[_level] = 0
|
||||||
|
}
|
||||||
|
Vue.set(record, '_marginLeft', marLTemp[_level] + parent._marginLeft)
|
||||||
|
Vue.set(record, '_width', record[item] / parent[item] * parent._width)
|
||||||
|
// 在本次计算过偏移量后加上自己长度,以供下一个元素使用
|
||||||
|
marLTemp[_level] += record._width
|
||||||
|
} else {
|
||||||
|
// 如果为根
|
||||||
|
// 初始化偏移量存储map
|
||||||
|
marLTemp[record.id] = []
|
||||||
|
// map中是一个数组,存储的是每级的长度和
|
||||||
|
// 初始情况下为0
|
||||||
|
marLTemp[record.id][_level] = 0
|
||||||
|
Vue.set(record, '_marginLeft', 0)
|
||||||
|
Vue.set(record, '_width', 1)
|
||||||
|
}
|
||||||
|
tmp.push(record)
|
||||||
|
if (record.children && record.children.length > 0) {
|
||||||
|
const children = treeToArray(record.children, record, _level, expandedAll, item)
|
||||||
|
tmp = tmp.concat(children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return tmp
|
||||||
|
}
|
135
src/views/example/table/treeTable/customTreeTable.vue
Normal file
135
src/views/example/table/treeTable/customTreeTable.vue
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
|
||||||
|
<el-tag style="margin-bottom:20px;">
|
||||||
|
<a href="https://github.com/PanJiaChen/vue-element-admin/tree/master/src/components/TreeTable" target="_blank">Documentation</a>
|
||||||
|
</el-tag>
|
||||||
|
|
||||||
|
<tree-table :data="data" :evalFunc="func" :evalArgs="args" border>
|
||||||
|
<el-table-column label="事件">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span style="color:sandybrown">{{scope.row.event}}</span>
|
||||||
|
<el-tag>{{scope.row.timeLine+'ms'}}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="时间线">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tooltip effect="dark" :content="scope.row.timeLine+'ms'" placement="left">
|
||||||
|
<div class="processContainer">
|
||||||
|
<div class="process" :style="{ width:scope.row._width * 500+'px',
|
||||||
|
background:scope.row._width>0.5?'rgba(233,0,0,.5)':'rgba(0,0,233,0.5)',
|
||||||
|
marginLeft:scope.row._marginLeft * 500+'px' }">
|
||||||
|
<span style="display:inline-block"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="200">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="text" @click="message(scope.row)">点击</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</tree-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
Auth: Lei.j1ang
|
||||||
|
Created: 2018/1/19-14:54
|
||||||
|
*/
|
||||||
|
import treeTable from '@/components/TreeTable'
|
||||||
|
import treeToArray from './customEval'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'tree',
|
||||||
|
components: { treeTable },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
func: treeToArray,
|
||||||
|
data:
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
event: '事件1',
|
||||||
|
timeLine: 100,
|
||||||
|
comment: '无',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
event: '事件2',
|
||||||
|
timeLine: 10,
|
||||||
|
comment: '无'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
event: '事件3',
|
||||||
|
timeLine: 90,
|
||||||
|
comment: '无',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
event: '事件4',
|
||||||
|
timeLine: 5,
|
||||||
|
comment: '无'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
event: '事件5',
|
||||||
|
timeLine: 10,
|
||||||
|
comment: '无'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
event: '事件6',
|
||||||
|
timeLine: 75,
|
||||||
|
comment: '无',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
event: '事件7',
|
||||||
|
timeLine: 50,
|
||||||
|
comment: '无',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 71,
|
||||||
|
event: '事件71',
|
||||||
|
timeLine: 25,
|
||||||
|
comment: 'xx'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 72,
|
||||||
|
event: '事件72',
|
||||||
|
timeLine: 5,
|
||||||
|
comment: 'xx'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 73,
|
||||||
|
event: '事件73',
|
||||||
|
timeLine: 20,
|
||||||
|
comment: 'xx'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
event: '事件8',
|
||||||
|
timeLine: 25,
|
||||||
|
comment: '无'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
args: [null, null, true, 'timeLine']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
message(row) {
|
||||||
|
this.$message.info(row.event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
129
src/views/example/table/treeTable/treeTable.vue
Normal file
129
src/views/example/table/treeTable/treeTable.vue
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
|
||||||
|
<el-tag style="margin-bottom:20px;">
|
||||||
|
<a href="https://github.com/PanJiaChen/vue-element-admin/tree/master/src/components/TreeTable" target="_blank">Documentation</a>
|
||||||
|
</el-tag>
|
||||||
|
|
||||||
|
<tree-table :data="data" :columns="columns" border></tree-table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
Auth: Lei.j1ang
|
||||||
|
Created: 2018/1/19-14:54
|
||||||
|
*/
|
||||||
|
import treeTable from '@/components/TreeTable'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'tree',
|
||||||
|
components: { treeTable },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
text: '事件',
|
||||||
|
value: 'event',
|
||||||
|
width: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'ID',
|
||||||
|
value: 'id'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '时间线',
|
||||||
|
value: 'timeLine'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '备注',
|
||||||
|
value: 'comment'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
event: '事件1',
|
||||||
|
timeLine: 50,
|
||||||
|
comment: '无'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
event: '事件1',
|
||||||
|
timeLine: 100,
|
||||||
|
comment: '无',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
event: '事件2',
|
||||||
|
timeLine: 10,
|
||||||
|
comment: '无'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
event: '事件3',
|
||||||
|
timeLine: 90,
|
||||||
|
comment: '无',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
event: '事件4',
|
||||||
|
timeLine: 5,
|
||||||
|
comment: '无'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
event: '事件5',
|
||||||
|
timeLine: 10,
|
||||||
|
comment: '无'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
event: '事件6',
|
||||||
|
timeLine: 75,
|
||||||
|
comment: '无',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
event: '事件7',
|
||||||
|
timeLine: 50,
|
||||||
|
comment: '无',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 71,
|
||||||
|
event: '事件71',
|
||||||
|
timeLine: 25,
|
||||||
|
comment: 'xx'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 72,
|
||||||
|
event: '事件72',
|
||||||
|
timeLine: 5,
|
||||||
|
comment: 'xx'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 73,
|
||||||
|
event: '事件73',
|
||||||
|
timeLine: 20,
|
||||||
|
comment: 'xx'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
event: '事件8',
|
||||||
|
timeLine: 25,
|
||||||
|
comment: '无'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@@ -2,8 +2,8 @@
|
|||||||
<div class="menu-wrapper">
|
<div class="menu-wrapper">
|
||||||
<template v-for="item in routes" v-if="!item.hidden&&item.children">
|
<template v-for="item in routes" v-if="!item.hidden&&item.children">
|
||||||
|
|
||||||
<router-link v-if="item.children.length===1 && !item.children[0].children" :to="item.path+'/'+item.children[0].path" :key="item.children[0].name">
|
<router-link v-if="item.children.length===1 && !item.children[0].children&&!item.alwaysShow" :to="item.path+'/'+item.children[0].path" :key="item.children[0].name">
|
||||||
<el-menu-item :index="item.path+'/'+item.children[0].path" class='submenu-title-noDropdown'>
|
<el-menu-item :index="item.path+'/'+item.children[0].path" :class="{'submenu-title-noDropdown':!isNest}">
|
||||||
<svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon>
|
<svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon>
|
||||||
<span v-if="item.children[0].meta&&item.children[0].meta.title">{{generateTitle(item.children[0].meta.title)}}</span>
|
<span v-if="item.children[0].meta&&item.children[0].meta.title">{{generateTitle(item.children[0].meta.title)}}</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-for="child in item.children" v-if="!child.hidden">
|
<template v-for="child in item.children" v-if="!child.hidden">
|
||||||
<sidebar-item class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :key="child.path"></sidebar-item>
|
<sidebar-item :is-nest="true" class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :key="child.path"></sidebar-item>
|
||||||
|
|
||||||
<router-link v-else :to="item.path+'/'+child.path" :key="child.name">
|
<router-link v-else :to="item.path+'/'+child.path" :key="child.name">
|
||||||
<el-menu-item :index="item.path+'/'+child.path">
|
<el-menu-item :index="item.path+'/'+child.path">
|
||||||
@@ -39,6 +39,10 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
routes: {
|
routes: {
|
||||||
type: Array
|
type: Array
|
||||||
|
},
|
||||||
|
isNest: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<scroll-bar>
|
<scroll-bar>
|
||||||
<el-menu mode="vertical" :default-active="$route.path" :collapse="isCollapse" background-color="#304156" text-color="#fff" active-text-color="#409EFF">
|
<el-menu mode="vertical" :default-active="$route.path" :collapse="isCollapse" background-color="#304156" text-color="#bfcbd9" active-text-color="#409EFF">
|
||||||
<sidebar-item :routes="permission_routers"></sidebar-item>
|
<sidebar-item :routes="permission_routers"></sidebar-item>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</scroll-bar>
|
</scroll-bar>
|
||||||
|
@@ -52,8 +52,11 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
generateTitle, // generateTitle by vue-i18n
|
generateTitle, // generateTitle by vue-i18n
|
||||||
generateRoute() {
|
generateRoute() {
|
||||||
if (this.$route.name) {
|
let matched = [...this.$route.matched]
|
||||||
return this.$route
|
matched.splice(0, 1)
|
||||||
|
matched = matched.filter(item => item.name)
|
||||||
|
if (matched) {
|
||||||
|
return matched
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
@@ -61,11 +64,17 @@ export default {
|
|||||||
return route.path === this.$route.path || route.name === this.$route.name
|
return route.path === this.$route.path || route.name === this.$route.name
|
||||||
},
|
},
|
||||||
addViewTags() {
|
addViewTags() {
|
||||||
const route = this.generateRoute()
|
const routes = this.generateRoute()
|
||||||
if (!route) {
|
if (!routes) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
this.$store.dispatch('addVisitedViews', route)
|
const length = routes.length
|
||||||
|
routes.forEach((item, index) => {
|
||||||
|
if (index === length - 1) {
|
||||||
|
item.showInVisitedViews = true
|
||||||
|
}
|
||||||
|
this.$store.dispatch('addVisitedViews', item)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
moveToCurrentTag() {
|
moveToCurrentTag() {
|
||||||
const tags = this.$refs.tag
|
const tags = this.$refs.tag
|
||||||
|
@@ -36,7 +36,7 @@
|
|||||||
<el-button class="thirdparty-button" type="primary" @click="showDialog=true">{{$t('login.thirdparty')}}</el-button>
|
<el-button class="thirdparty-button" type="primary" @click="showDialog=true">{{$t('login.thirdparty')}}</el-button>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<el-dialog :title="$t('login.thirdparty')" :visible.sync="showDialog">
|
<el-dialog :title="$t('login.thirdparty')" :visible.sync="showDialog" append-to-body>
|
||||||
{{$t('login.thirdpartyTips')}}
|
{{$t('login.thirdpartyTips')}}
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -170,14 +170,14 @@ $light_gray:#eee;
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
@import "src/styles/mixin.scss";
|
|
||||||
$bg:#2d3a4b;
|
$bg:#2d3a4b;
|
||||||
$dark_gray:#889aa4;
|
$dark_gray:#889aa4;
|
||||||
$light_gray:#eee;
|
$light_gray:#eee;
|
||||||
|
|
||||||
.login-container {
|
.login-container {
|
||||||
@include relative;
|
position: fixed;
|
||||||
height: 100vh;
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
background-color: $bg;
|
background-color: $bg;
|
||||||
.login-form {
|
.login-form {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<div style="margin-bottom:15px;">{{$t('permission.roles')}}: {{roles}}</div>
|
<div style="margin-bottom:15px;">{{$t('permission.roles')}}: {{roles}}</div>
|
||||||
{{$t('permission.switchRoles')}}:
|
{{$t('permission.switchRoles')}}:
|
||||||
<el-radio-group v-model="role">
|
<el-radio-group v-model="switchRoles">
|
||||||
<el-radio-button label="editor"></el-radio-button>
|
<el-radio-button label="editor"></el-radio-button>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</div>
|
</div>
|
||||||
@@ -15,7 +15,7 @@ export default{
|
|||||||
name: 'permission',
|
name: 'permission',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
role: ''
|
switchRoles: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -24,8 +24,8 @@ export default{
|
|||||||
])
|
])
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
role(val) {
|
switchRoles(val) {
|
||||||
this.$store.dispatch('ChangeRole', val).then(() => {
|
this.$store.dispatch('ChangeRoles', val).then(() => {
|
||||||
this.$router.push({ path: '/permission/index?' + +new Date() })
|
this.$router.push({ path: '/permission/index?' + +new Date() })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user