update .gitignore
This commit is contained in:
@@ -1,192 +1,192 @@
|
||||
/**
|
||||
* auth: 允许的权限
|
||||
* authExclude: 排除的权限
|
||||
*
|
||||
* auth的几种传值方式
|
||||
* 1.String
|
||||
* 例: auth="sysApp:page"
|
||||
* 直接传入字符串,对单项权限进行验证
|
||||
*
|
||||
* 2.Array
|
||||
* 2.1.单项权限
|
||||
* 例: :auth="['sysApp:page']"
|
||||
* 2.2.并且关系多项权限
|
||||
* 例: :auth="['sysApp:page', 'sysApp:add']"
|
||||
* 数组中传入多个字符串
|
||||
* 此时验证的是同时拥有"sysApp:page"和"sysApp:add"两项权限才会渲染
|
||||
* 2.3.或者关系多项权限
|
||||
* 例: :auth="[['sysApp:page', 'sysApp:add'], ['sysApp:edit']]"
|
||||
* 二维数组结构,内部数组之间为并且关系
|
||||
* 此时验证的是"sysApp:page"&"sysApp:add"||"sysApp:edit"
|
||||
* 注意:或者的条件必须包括在数组中,暴露在外则判定为并且
|
||||
* 2.4.可直接传入布尔值
|
||||
* 例: :auth="['sysApp:page', 1 === 1]"
|
||||
* :auth="[['sysApp:page', 'sysApp:add'], [1 === 1]]"
|
||||
*
|
||||
* 3.Json
|
||||
* 如果觉得多项权限时每次都要写应用编号比较繁琐,可对Array形式进行简化
|
||||
* 3.1.单项权限
|
||||
* 例: :auth="{ sysApp: 'page' }"
|
||||
* 3.2.并且关系多项权限
|
||||
* 例: :auth="{ sysApp: ['page', 'add'] }"
|
||||
* 3.3.或者关系多项权限
|
||||
* 例: :auth="{ sysApp: [['page', 'add'], ['edit']]}"
|
||||
* 3.4.可直接传入布尔值
|
||||
* 例: :auth="{ sysApp: ['page', 1 === 1] }"
|
||||
* :auth="{ sysApp: [['page', 'add'], [1 === 1]] }"
|
||||
*
|
||||
*/
|
||||
|
||||
import app from '@/main'
|
||||
|
||||
const authByArray = (auth, permissions) => {
|
||||
|
||||
const flags = []
|
||||
|
||||
auth.forEach(p => {
|
||||
switch (p.constructor) {
|
||||
case String:
|
||||
flags.push([permissions.indexOf(p) > -1, '&&'])
|
||||
break
|
||||
case Array:
|
||||
flags.push([authByArray(p, permissions), '||'])
|
||||
break
|
||||
case Boolean:
|
||||
flags.push([p, '&&'])
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
let result
|
||||
|
||||
flags.forEach((p, i) => {
|
||||
if (p[1] === '&&') {
|
||||
if (i === 0) {
|
||||
result = true
|
||||
}
|
||||
if (result) {
|
||||
result = p[0]
|
||||
}
|
||||
} else {
|
||||
if (i === 0) {
|
||||
result = false
|
||||
}
|
||||
if (!result) {
|
||||
result = p[0]
|
||||
}
|
||||
}
|
||||
//result = p[1] === '&&' ? result && p[0] : result || p[0]
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
const authByJson = (auth, permissions) => {
|
||||
|
||||
let result = true
|
||||
|
||||
const flags = []
|
||||
|
||||
const deepName = (arr, key) => {
|
||||
arr.forEach((p, i) => {
|
||||
switch (p.constructor) {
|
||||
case String:
|
||||
arr[i] = `${key}:${p}`
|
||||
break
|
||||
case Array:
|
||||
p = deepName(p, key)
|
||||
break
|
||||
default:
|
||||
p = p
|
||||
break
|
||||
}
|
||||
})
|
||||
return arr
|
||||
}
|
||||
|
||||
for (let key in auth) {
|
||||
const app = auth[key]
|
||||
switch (app.constructor) {
|
||||
case String:
|
||||
flags.push(permissions.indexOf(`${key}:${p}`) > -1)
|
||||
break
|
||||
case Array:
|
||||
flags.push(authByArray(deepName(app, key), permissions))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
flags.forEach(p => {
|
||||
result = result && p
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
export const auth = (auth) => {
|
||||
|
||||
const { info } = app.global
|
||||
|
||||
if (!info) {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 超级管理员
|
||||
*/
|
||||
if (info.adminType === 1) {
|
||||
return true
|
||||
}
|
||||
|
||||
const permissions = info.permissions
|
||||
|
||||
let flag = false
|
||||
|
||||
if (auth) {
|
||||
switch (auth.constructor) {
|
||||
case String:
|
||||
flag = permissions.indexOf(auth) > -1
|
||||
break
|
||||
case Array:
|
||||
flag = authByArray(auth, permissions)
|
||||
break
|
||||
case Object:
|
||||
flag = authByJson(auth, permissions)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return flag
|
||||
}
|
||||
|
||||
export default {
|
||||
functional: true,
|
||||
props: {
|
||||
auth: {
|
||||
default() {
|
||||
return new Array()
|
||||
},
|
||||
type: [Array, Object, String],
|
||||
},
|
||||
authExclude: {
|
||||
default() {
|
||||
return new Array()
|
||||
},
|
||||
type: Array,
|
||||
},
|
||||
},
|
||||
|
||||
render(h, context) {
|
||||
const { props, scopedSlots } = context
|
||||
const authExclude = props.authExclude
|
||||
|
||||
let flag = auth(props.auth)
|
||||
|
||||
if (flag) {
|
||||
return scopedSlots.default && scopedSlots.default()
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
/**
|
||||
* auth: 允许的权限
|
||||
* authExclude: 排除的权限
|
||||
*
|
||||
* auth的几种传值方式
|
||||
* 1.String
|
||||
* 例: auth="sysApp:page"
|
||||
* 直接传入字符串,对单项权限进行验证
|
||||
*
|
||||
* 2.Array
|
||||
* 2.1.单项权限
|
||||
* 例: :auth="['sysApp:page']"
|
||||
* 2.2.并且关系多项权限
|
||||
* 例: :auth="['sysApp:page', 'sysApp:add']"
|
||||
* 数组中传入多个字符串
|
||||
* 此时验证的是同时拥有"sysApp:page"和"sysApp:add"两项权限才会渲染
|
||||
* 2.3.或者关系多项权限
|
||||
* 例: :auth="[['sysApp:page', 'sysApp:add'], ['sysApp:edit']]"
|
||||
* 二维数组结构,内部数组之间为并且关系
|
||||
* 此时验证的是"sysApp:page"&"sysApp:add"||"sysApp:edit"
|
||||
* 注意:或者的条件必须包括在数组中,暴露在外则判定为并且
|
||||
* 2.4.可直接传入布尔值
|
||||
* 例: :auth="['sysApp:page', 1 === 1]"
|
||||
* :auth="[['sysApp:page', 'sysApp:add'], [1 === 1]]"
|
||||
*
|
||||
* 3.Json
|
||||
* 如果觉得多项权限时每次都要写应用编号比较繁琐,可对Array形式进行简化
|
||||
* 3.1.单项权限
|
||||
* 例: :auth="{ sysApp: 'page' }"
|
||||
* 3.2.并且关系多项权限
|
||||
* 例: :auth="{ sysApp: ['page', 'add'] }"
|
||||
* 3.3.或者关系多项权限
|
||||
* 例: :auth="{ sysApp: [['page', 'add'], ['edit']]}"
|
||||
* 3.4.可直接传入布尔值
|
||||
* 例: :auth="{ sysApp: ['page', 1 === 1] }"
|
||||
* :auth="{ sysApp: [['page', 'add'], [1 === 1]] }"
|
||||
*
|
||||
*/
|
||||
|
||||
import app from '@/main'
|
||||
|
||||
const authByArray = (auth, permissions) => {
|
||||
|
||||
const flags = []
|
||||
|
||||
auth.forEach(p => {
|
||||
switch (p.constructor) {
|
||||
case String:
|
||||
flags.push([permissions.indexOf(p) > -1, '&&'])
|
||||
break
|
||||
case Array:
|
||||
flags.push([authByArray(p, permissions), '||'])
|
||||
break
|
||||
case Boolean:
|
||||
flags.push([p, '&&'])
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
let result
|
||||
|
||||
flags.forEach((p, i) => {
|
||||
if (p[1] === '&&') {
|
||||
if (i === 0) {
|
||||
result = true
|
||||
}
|
||||
if (result) {
|
||||
result = p[0]
|
||||
}
|
||||
} else {
|
||||
if (i === 0) {
|
||||
result = false
|
||||
}
|
||||
if (!result) {
|
||||
result = p[0]
|
||||
}
|
||||
}
|
||||
//result = p[1] === '&&' ? result && p[0] : result || p[0]
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
const authByJson = (auth, permissions) => {
|
||||
|
||||
let result = true
|
||||
|
||||
const flags = []
|
||||
|
||||
const deepName = (arr, key) => {
|
||||
arr.forEach((p, i) => {
|
||||
switch (p.constructor) {
|
||||
case String:
|
||||
arr[i] = `${key}:${p}`
|
||||
break
|
||||
case Array:
|
||||
p = deepName(p, key)
|
||||
break
|
||||
default:
|
||||
p = p
|
||||
break
|
||||
}
|
||||
})
|
||||
return arr
|
||||
}
|
||||
|
||||
for (let key in auth) {
|
||||
const app = auth[key]
|
||||
switch (app.constructor) {
|
||||
case String:
|
||||
flags.push(permissions.indexOf(`${key}:${p}`) > -1)
|
||||
break
|
||||
case Array:
|
||||
flags.push(authByArray(deepName(app, key), permissions))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
flags.forEach(p => {
|
||||
result = result && p
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
export const auth = (auth) => {
|
||||
|
||||
const { info } = app.global
|
||||
|
||||
if (!info) {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 超级管理员
|
||||
*/
|
||||
if (info.adminType === 1) {
|
||||
return true
|
||||
}
|
||||
|
||||
const permissions = info.permissions
|
||||
|
||||
let flag = false
|
||||
|
||||
if (auth) {
|
||||
switch (auth.constructor) {
|
||||
case String:
|
||||
flag = permissions.indexOf(auth) > -1
|
||||
break
|
||||
case Array:
|
||||
flag = authByArray(auth, permissions)
|
||||
break
|
||||
case Object:
|
||||
flag = authByJson(auth, permissions)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return flag
|
||||
}
|
||||
|
||||
export default {
|
||||
functional: true,
|
||||
props: {
|
||||
auth: {
|
||||
default() {
|
||||
return new Array()
|
||||
},
|
||||
type: [Array, Object, String],
|
||||
},
|
||||
authExclude: {
|
||||
default() {
|
||||
return new Array()
|
||||
},
|
||||
type: Array,
|
||||
},
|
||||
},
|
||||
|
||||
render(h, context) {
|
||||
const { props, scopedSlots } = context
|
||||
const authExclude = props.authExclude
|
||||
|
||||
let flag = auth(props.auth)
|
||||
|
||||
if (flag) {
|
||||
return scopedSlots.default && scopedSlots.default()
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<section :class="mode || $root.global.settings.container || 'container-fluid'">
|
||||
<slot />
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
};
|
||||
<template>
|
||||
<section :class="mode || $root.global.settings.container || 'container-fluid'">
|
||||
<slot />
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,254 +1,254 @@
|
||||
export default {
|
||||
props: {
|
||||
loadData: {
|
||||
type: Function,
|
||||
require: true,
|
||||
},
|
||||
|
||||
autoLoad: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
|
||||
defaultSelectedKeys: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
|
||||
data: [],
|
||||
list: []
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.autoLoad) {
|
||||
this.onLoadData()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
renderDescriptions(data) {
|
||||
return data.map(p => {
|
||||
return p.children && p.children.length ? this.renderItem(p) : this.renderCheckbox(p)
|
||||
})
|
||||
},
|
||||
|
||||
renderItem(data) {
|
||||
return (
|
||||
<a-descriptions bordered column={1}>
|
||||
<a-descriptions-item>
|
||||
<a-checkbox
|
||||
slot="label"
|
||||
value={data.id}
|
||||
checked={data.checked}
|
||||
indeterminate={data.indeterminate}
|
||||
onChange={(e) => this.onChange(e, data)}
|
||||
>{data.title}</a-checkbox>
|
||||
{this.renderDescriptions(data.children)}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
)
|
||||
},
|
||||
|
||||
renderCheckbox(data) {
|
||||
return (
|
||||
<div class="yo-authority-view--checkbox">
|
||||
{data.visibleParent && data.type == 2 &&
|
||||
<a-tooltip placement="top" title="选中此项才会显示父节点">
|
||||
<a-icon type="eye" style={{ color: '#1890ff' }} class="mr-xxs" />
|
||||
</a-tooltip>
|
||||
}
|
||||
<a-checkbox
|
||||
value={data.id}
|
||||
checked={data.checked}
|
||||
onChange={(e) => this.onChange(e, data)}
|
||||
>
|
||||
{data.title}
|
||||
</a-checkbox>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
onLoadData() {
|
||||
this.loading = true
|
||||
|
||||
this.loadData().then((res) => {
|
||||
this.data = this.generateCheck(res)
|
||||
|
||||
this.list = []
|
||||
this.generateList(this.data)
|
||||
|
||||
if (this.defaultSelectedKeys.length) {
|
||||
this.list.map(p => {
|
||||
if (this.defaultSelectedKeys.indexOf(p.id) > -1 && (!p.children || !p.children.length)) {
|
||||
this.onSelect(true, p)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
onReloadData() {
|
||||
|
||||
this.data = []
|
||||
this.onLoadData()
|
||||
|
||||
},
|
||||
|
||||
onChange(e, item) {
|
||||
|
||||
this.onSelect(e.target.checked, item)
|
||||
|
||||
const visible = this.getVisible()
|
||||
|
||||
this.$emit('select',
|
||||
// 返回所有选中
|
||||
this.list.filter(p => p.checked).map(p => p.id),
|
||||
// 返回所有选中和半选
|
||||
this.list.filter(p => p.checked || p.indeterminate).map(p => p.id),
|
||||
// 返回所有选中和半选,但是不返回没有子级选中visibleParent的半选
|
||||
visible
|
||||
)
|
||||
},
|
||||
|
||||
onSelect(check, item) {
|
||||
item.checked = check
|
||||
item.indeterminate = false
|
||||
if (item.children && item.children.length) {
|
||||
this.onChangeChildren(item.checked, item.children)
|
||||
}
|
||||
if (item.parentId) {
|
||||
this.onChangeParent(item.checked, item.parentId)
|
||||
}
|
||||
},
|
||||
|
||||
onChangeParent(checked, parentId) {
|
||||
const parent = this.list.find(p => p.id === parentId)
|
||||
if (parent) {
|
||||
const checkedCount = parent.children.filter(p => p.checked).length
|
||||
const indeterminateCount = parent.children.filter(p => p.indeterminate).length
|
||||
if (checkedCount === parent.children.length) {
|
||||
// 全选
|
||||
parent.checked = true
|
||||
parent.indeterminate = false
|
||||
} else if (!checkedCount && !indeterminateCount) {
|
||||
// 全不选
|
||||
parent.checked = false
|
||||
parent.indeterminate = false
|
||||
} else {
|
||||
// 半选
|
||||
parent.checked = false
|
||||
parent.indeterminate = true
|
||||
}
|
||||
this.onChangeParent(checked, parent.parentId)
|
||||
}
|
||||
},
|
||||
|
||||
onChangeChildren(checked, children) {
|
||||
children.forEach(p => {
|
||||
p.checked = checked
|
||||
p.indeterminate = false
|
||||
if (p.children && p.children.length) {
|
||||
this.onChangeChildren(checked, p.children)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
generateCheck(data) {
|
||||
data.forEach(p => {
|
||||
if (p.children && p.children.length) {
|
||||
p.children = this.generateCheck(p.children)
|
||||
}
|
||||
p.checked = false
|
||||
p.indeterminate = false
|
||||
})
|
||||
|
||||
return data
|
||||
},
|
||||
|
||||
generateList(data) {
|
||||
data.forEach(p => {
|
||||
if (p.children && p.children.length) {
|
||||
this.generateList(p.children)
|
||||
}
|
||||
this.list.push(p)
|
||||
})
|
||||
},
|
||||
|
||||
getVisible() {
|
||||
const checked = this.list.filter(p => p.checked)
|
||||
const caseChildren = checked.filter(p => p.visibleParent || p.type != 2)
|
||||
const visibleParents = []
|
||||
// 递归寻找父级
|
||||
const findVisibleParents = (children) => {
|
||||
const parents = []
|
||||
children.forEach(item => {
|
||||
if (item.parentId) {
|
||||
const parent = this.list.find(p => p.id === item.parentId)
|
||||
if (parent) {
|
||||
parents.push(parent)
|
||||
visibleParents.push(parent)
|
||||
}
|
||||
}
|
||||
})
|
||||
if (parents.length) {
|
||||
findVisibleParents(parents)
|
||||
}
|
||||
}
|
||||
|
||||
findVisibleParents(caseChildren)
|
||||
|
||||
const checkedIds = checked.map(p => p.id)
|
||||
const visibleParentsIds = visibleParents.map(p => p.id)
|
||||
|
||||
const result = checkedIds
|
||||
visibleParentsIds.forEach(p => {
|
||||
if (result.indexOf(p) === -1) {
|
||||
result.push(p)
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div class="yo-authority-view">
|
||||
<a-spin style={{ width: '100%' }} spinning={this.loading}>
|
||||
<a-icon slot="indicator" type="loading" spin />
|
||||
{
|
||||
!this.loading &&
|
||||
<a-descriptions bordered column={1}>
|
||||
{
|
||||
this.data.map(p => {
|
||||
return (
|
||||
<a-descriptions-item>
|
||||
<a-checkbox
|
||||
slot="label"
|
||||
value={p.id}
|
||||
checked={p.checked}
|
||||
indeterminate={p.indeterminate}
|
||||
onChange={(e) => this.onChange(e, p)}
|
||||
>{p.title}</a-checkbox>
|
||||
{this.renderDescriptions(p.children)}
|
||||
</a-descriptions-item>
|
||||
)
|
||||
})
|
||||
}
|
||||
</a-descriptions>
|
||||
}
|
||||
</a-spin>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
loadData: {
|
||||
type: Function,
|
||||
require: true,
|
||||
},
|
||||
|
||||
autoLoad: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
|
||||
defaultSelectedKeys: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
|
||||
data: [],
|
||||
list: []
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.autoLoad) {
|
||||
this.onLoadData()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
renderDescriptions(data) {
|
||||
return data.map(p => {
|
||||
return p.children && p.children.length ? this.renderItem(p) : this.renderCheckbox(p)
|
||||
})
|
||||
},
|
||||
|
||||
renderItem(data) {
|
||||
return (
|
||||
<a-descriptions bordered column={1}>
|
||||
<a-descriptions-item>
|
||||
<a-checkbox
|
||||
slot="label"
|
||||
value={data.id}
|
||||
checked={data.checked}
|
||||
indeterminate={data.indeterminate}
|
||||
onChange={(e) => this.onChange(e, data)}
|
||||
>{data.title}</a-checkbox>
|
||||
{this.renderDescriptions(data.children)}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
)
|
||||
},
|
||||
|
||||
renderCheckbox(data) {
|
||||
return (
|
||||
<div class="yo-authority-view--checkbox">
|
||||
{data.visibleParent && data.type == 2 &&
|
||||
<a-tooltip placement="top" title="选中此项才会显示父节点">
|
||||
<a-icon type="eye" style={{ color: '#1890ff' }} class="mr-xxs" />
|
||||
</a-tooltip>
|
||||
}
|
||||
<a-checkbox
|
||||
value={data.id}
|
||||
checked={data.checked}
|
||||
onChange={(e) => this.onChange(e, data)}
|
||||
>
|
||||
{data.title}
|
||||
</a-checkbox>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
onLoadData() {
|
||||
this.loading = true
|
||||
|
||||
this.loadData().then((res) => {
|
||||
this.data = this.generateCheck(res)
|
||||
|
||||
this.list = []
|
||||
this.generateList(this.data)
|
||||
|
||||
if (this.defaultSelectedKeys.length) {
|
||||
this.list.map(p => {
|
||||
if (this.defaultSelectedKeys.indexOf(p.id) > -1 && (!p.children || !p.children.length)) {
|
||||
this.onSelect(true, p)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
onReloadData() {
|
||||
|
||||
this.data = []
|
||||
this.onLoadData()
|
||||
|
||||
},
|
||||
|
||||
onChange(e, item) {
|
||||
|
||||
this.onSelect(e.target.checked, item)
|
||||
|
||||
const visible = this.getVisible()
|
||||
|
||||
this.$emit('select',
|
||||
// 返回所有选中
|
||||
this.list.filter(p => p.checked).map(p => p.id),
|
||||
// 返回所有选中和半选
|
||||
this.list.filter(p => p.checked || p.indeterminate).map(p => p.id),
|
||||
// 返回所有选中和半选,但是不返回没有子级选中visibleParent的半选
|
||||
visible
|
||||
)
|
||||
},
|
||||
|
||||
onSelect(check, item) {
|
||||
item.checked = check
|
||||
item.indeterminate = false
|
||||
if (item.children && item.children.length) {
|
||||
this.onChangeChildren(item.checked, item.children)
|
||||
}
|
||||
if (item.parentId) {
|
||||
this.onChangeParent(item.checked, item.parentId)
|
||||
}
|
||||
},
|
||||
|
||||
onChangeParent(checked, parentId) {
|
||||
const parent = this.list.find(p => p.id === parentId)
|
||||
if (parent) {
|
||||
const checkedCount = parent.children.filter(p => p.checked).length
|
||||
const indeterminateCount = parent.children.filter(p => p.indeterminate).length
|
||||
if (checkedCount === parent.children.length) {
|
||||
// 全选
|
||||
parent.checked = true
|
||||
parent.indeterminate = false
|
||||
} else if (!checkedCount && !indeterminateCount) {
|
||||
// 全不选
|
||||
parent.checked = false
|
||||
parent.indeterminate = false
|
||||
} else {
|
||||
// 半选
|
||||
parent.checked = false
|
||||
parent.indeterminate = true
|
||||
}
|
||||
this.onChangeParent(checked, parent.parentId)
|
||||
}
|
||||
},
|
||||
|
||||
onChangeChildren(checked, children) {
|
||||
children.forEach(p => {
|
||||
p.checked = checked
|
||||
p.indeterminate = false
|
||||
if (p.children && p.children.length) {
|
||||
this.onChangeChildren(checked, p.children)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
generateCheck(data) {
|
||||
data.forEach(p => {
|
||||
if (p.children && p.children.length) {
|
||||
p.children = this.generateCheck(p.children)
|
||||
}
|
||||
p.checked = false
|
||||
p.indeterminate = false
|
||||
})
|
||||
|
||||
return data
|
||||
},
|
||||
|
||||
generateList(data) {
|
||||
data.forEach(p => {
|
||||
if (p.children && p.children.length) {
|
||||
this.generateList(p.children)
|
||||
}
|
||||
this.list.push(p)
|
||||
})
|
||||
},
|
||||
|
||||
getVisible() {
|
||||
const checked = this.list.filter(p => p.checked)
|
||||
const caseChildren = checked.filter(p => p.visibleParent || p.type != 2)
|
||||
const visibleParents = []
|
||||
// 递归寻找父级
|
||||
const findVisibleParents = (children) => {
|
||||
const parents = []
|
||||
children.forEach(item => {
|
||||
if (item.parentId) {
|
||||
const parent = this.list.find(p => p.id === item.parentId)
|
||||
if (parent) {
|
||||
parents.push(parent)
|
||||
visibleParents.push(parent)
|
||||
}
|
||||
}
|
||||
})
|
||||
if (parents.length) {
|
||||
findVisibleParents(parents)
|
||||
}
|
||||
}
|
||||
|
||||
findVisibleParents(caseChildren)
|
||||
|
||||
const checkedIds = checked.map(p => p.id)
|
||||
const visibleParentsIds = visibleParents.map(p => p.id)
|
||||
|
||||
const result = checkedIds
|
||||
visibleParentsIds.forEach(p => {
|
||||
if (result.indexOf(p) === -1) {
|
||||
result.push(p)
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div class="yo-authority-view">
|
||||
<a-spin style={{ width: '100%' }} spinning={this.loading}>
|
||||
<a-icon slot="indicator" type="loading" spin />
|
||||
{
|
||||
!this.loading &&
|
||||
<a-descriptions bordered column={1}>
|
||||
{
|
||||
this.data.map(p => {
|
||||
return (
|
||||
<a-descriptions-item>
|
||||
<a-checkbox
|
||||
slot="label"
|
||||
value={p.id}
|
||||
checked={p.checked}
|
||||
indeterminate={p.indeterminate}
|
||||
onChange={(e) => this.onChange(e, p)}
|
||||
>{p.title}</a-checkbox>
|
||||
{this.renderDescriptions(p.children)}
|
||||
</a-descriptions-item>
|
||||
)
|
||||
})
|
||||
}
|
||||
</a-descriptions>
|
||||
}
|
||||
</a-spin>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,107 +1,107 @@
|
||||
export default {
|
||||
props: {
|
||||
pageNo: {
|
||||
default: 1,
|
||||
type: Number,
|
||||
},
|
||||
pageSize: {
|
||||
default: 10,
|
||||
type: Number,
|
||||
},
|
||||
loadData: {
|
||||
type: Function,
|
||||
require: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
|
||||
data: [],
|
||||
|
||||
pagination: {
|
||||
current: this.pageNo,
|
||||
pageSize: this.pageSize,
|
||||
total: 0,
|
||||
size: 'small',
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `总共${total}条数据`
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
onLoading() {
|
||||
this.loading = {
|
||||
indicator: <a-icon type="loading" spin />
|
||||
}
|
||||
},
|
||||
|
||||
onLoaded() {
|
||||
this.loading = false
|
||||
},
|
||||
|
||||
onLoadData() {
|
||||
this.onLoading()
|
||||
|
||||
this.loadData({
|
||||
pageNo: this.pagination.current,
|
||||
pageSize: this.pagination.pageSize,
|
||||
...this.sorter
|
||||
}).then((res) => {
|
||||
this.data = res.rows
|
||||
this.pagination.total = res.totalRows
|
||||
this.onLoaded()
|
||||
})
|
||||
},
|
||||
|
||||
onReloadData(refresh = false) {
|
||||
if (refresh && refresh.constructor === Boolean && this.pagination.constructor === Object) {
|
||||
this.pagination.current = this.pageNo
|
||||
this.pagination.pageSize = this.pageSize
|
||||
}
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
render() {
|
||||
const props = {
|
||||
loading: this.loading,
|
||||
pagination: this.pagination,
|
||||
dataSource: this.data,
|
||||
rowKey: record => record.id,
|
||||
...this.$attrs
|
||||
}
|
||||
|
||||
const on = {
|
||||
//change: this.onTableChange
|
||||
}
|
||||
return (
|
||||
<section>
|
||||
<div class="yo-action-bar">
|
||||
<div class="yo-action-bar--actions">
|
||||
{this.$scopedSlots.operator && this.$scopedSlots.operator()}
|
||||
</div>
|
||||
<div class="yo-action-bar--actions">
|
||||
<a-button-group>
|
||||
<a-button onClick={this.onReloadData}>刷新</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
<a-list {...{ props, on, scopedSlots: { ...this.$scopedSlots } }}>
|
||||
{Object.keys(this.$slots).map((name) => (
|
||||
<template slot={name}>{this.$slots[name]}</template>
|
||||
))}
|
||||
</a-list>
|
||||
</section>
|
||||
)
|
||||
},
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
pageNo: {
|
||||
default: 1,
|
||||
type: Number,
|
||||
},
|
||||
pageSize: {
|
||||
default: 10,
|
||||
type: Number,
|
||||
},
|
||||
loadData: {
|
||||
type: Function,
|
||||
require: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
|
||||
data: [],
|
||||
|
||||
pagination: {
|
||||
current: this.pageNo,
|
||||
pageSize: this.pageSize,
|
||||
total: 0,
|
||||
size: 'small',
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `总共${total}条数据`
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
onLoading() {
|
||||
this.loading = {
|
||||
indicator: <a-icon type="loading" spin />
|
||||
}
|
||||
},
|
||||
|
||||
onLoaded() {
|
||||
this.loading = false
|
||||
},
|
||||
|
||||
onLoadData() {
|
||||
this.onLoading()
|
||||
|
||||
this.loadData({
|
||||
pageNo: this.pagination.current,
|
||||
pageSize: this.pagination.pageSize,
|
||||
...this.sorter
|
||||
}).then((res) => {
|
||||
this.data = res.rows
|
||||
this.pagination.total = res.totalRows
|
||||
this.onLoaded()
|
||||
})
|
||||
},
|
||||
|
||||
onReloadData(refresh = false) {
|
||||
if (refresh && refresh.constructor === Boolean && this.pagination.constructor === Object) {
|
||||
this.pagination.current = this.pageNo
|
||||
this.pagination.pageSize = this.pageSize
|
||||
}
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
render() {
|
||||
const props = {
|
||||
loading: this.loading,
|
||||
pagination: this.pagination,
|
||||
dataSource: this.data,
|
||||
rowKey: record => record.id,
|
||||
...this.$attrs
|
||||
}
|
||||
|
||||
const on = {
|
||||
//change: this.onTableChange
|
||||
}
|
||||
return (
|
||||
<section>
|
||||
<div class="yo-action-bar">
|
||||
<div class="yo-action-bar--actions">
|
||||
{this.$scopedSlots.operator && this.$scopedSlots.operator()}
|
||||
</div>
|
||||
<div class="yo-action-bar--actions">
|
||||
<a-button-group>
|
||||
<a-button onClick={this.onReloadData}>刷新</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
<a-list {...{ props, on, scopedSlots: { ...this.$scopedSlots } }}>
|
||||
{Object.keys(this.$slots).map((name) => (
|
||||
<template slot={name}>{this.$slots[name]}</template>
|
||||
))}
|
||||
</a-list>
|
||||
</section>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
<template>
|
||||
<a-dropdown :trigger="['click']" placement="bottomRight" v-model="visible">
|
||||
<a-button>显示列</a-button>
|
||||
<a-menu @click="() => { return false; }" class="yo-table--column-setting" slot="overlay">
|
||||
<a-menu-item>
|
||||
<a-checkbox :checked="checkedAll" :indeterminate="halfChecked" @change="onCheckAll">全选</a-checkbox>
|
||||
</a-menu-item>
|
||||
<a-menu-divider />
|
||||
<a-menu-item :key="column.dataIndex || column.key" v-for="column in columns">
|
||||
<a-checkbox :checked="!column.hidden" @change="(e) => onCheck(column, e)">{{column.title}}</a-checkbox>
|
||||
<a-icon
|
||||
:class="{ 'yo-table--fixed': column.fixed }"
|
||||
@click="onFixed(column)"
|
||||
type="pushpin"
|
||||
/>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
columns: {
|
||||
type: Array,
|
||||
require: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
|
||||
checkedAll: true,
|
||||
halfChecked: false,
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.onHalfCheck();
|
||||
},
|
||||
|
||||
methods: {
|
||||
onHalfCheck() {
|
||||
this.halfChecked = this.columns.filter((p) => p.hidden).length > 0;
|
||||
},
|
||||
|
||||
onCheck(column, e) {
|
||||
this.$set(column, 'hidden', !e.target.checked);
|
||||
this.onHalfCheck();
|
||||
},
|
||||
|
||||
onCheckAll(e) {
|
||||
this.columns.forEach((column) => {
|
||||
this.$set(column, 'hidden', !e.target.checked);
|
||||
});
|
||||
this.checkedAll = e.target.checked;
|
||||
},
|
||||
|
||||
onFixed(column) {
|
||||
this.$set(column, 'fixed', !column.fixed);
|
||||
},
|
||||
},
|
||||
};
|
||||
<template>
|
||||
<a-dropdown :trigger="['click']" placement="bottomRight" v-model="visible">
|
||||
<a-button>显示列</a-button>
|
||||
<a-menu @click="() => { return false; }" class="yo-table--column-setting" slot="overlay">
|
||||
<a-menu-item>
|
||||
<a-checkbox :checked="checkedAll" :indeterminate="halfChecked" @change="onCheckAll">全选</a-checkbox>
|
||||
</a-menu-item>
|
||||
<a-menu-divider />
|
||||
<a-menu-item :key="column.dataIndex || column.key" v-for="column in columns">
|
||||
<a-checkbox :checked="!column.hidden" @change="(e) => onCheck(column, e)">{{column.title}}</a-checkbox>
|
||||
<a-icon
|
||||
:class="{ 'yo-table--fixed': column.fixed }"
|
||||
@click="onFixed(column)"
|
||||
type="pushpin"
|
||||
/>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
columns: {
|
||||
type: Array,
|
||||
require: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
|
||||
checkedAll: true,
|
||||
halfChecked: false,
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.onHalfCheck();
|
||||
},
|
||||
|
||||
methods: {
|
||||
onHalfCheck() {
|
||||
this.halfChecked = this.columns.filter((p) => p.hidden).length > 0;
|
||||
},
|
||||
|
||||
onCheck(column, e) {
|
||||
this.$set(column, 'hidden', !e.target.checked);
|
||||
this.onHalfCheck();
|
||||
},
|
||||
|
||||
onCheckAll(e) {
|
||||
this.columns.forEach((column) => {
|
||||
this.$set(column, 'hidden', !e.target.checked);
|
||||
});
|
||||
this.checkedAll = e.target.checked;
|
||||
},
|
||||
|
||||
onFixed(column) {
|
||||
this.$set(column, 'fixed', !column.fixed);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,229 +1,229 @@
|
||||
// 列设置用jsx实现起来较为困难
|
||||
import ColumnSetting from './column'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
pageNo: {
|
||||
default: 1,
|
||||
type: Number,
|
||||
},
|
||||
pageSize: {
|
||||
default: 10,
|
||||
type: Number,
|
||||
},
|
||||
loadData: {
|
||||
type: Function,
|
||||
require: true,
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
require: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
|
||||
type: '',
|
||||
|
||||
data: [],
|
||||
|
||||
pagination: {
|
||||
current: this.pageNo,
|
||||
pageSize: this.pageSize,
|
||||
total: 0,
|
||||
size: 'small',
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `总共${total}条数据`
|
||||
},
|
||||
|
||||
sorter: {
|
||||
sortField: '',
|
||||
sortOrder: '',
|
||||
},
|
||||
|
||||
columnSettingVisible: false
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
renderColumnSetting() {
|
||||
|
||||
const props = {
|
||||
visible: this.columnSettingVisible,
|
||||
placement: 'bottomRight'
|
||||
}
|
||||
|
||||
const on = {
|
||||
visibleChange: (visible) => {
|
||||
this.columnSettingVisible = visible
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<a-dropdown {...{ props, on }}>
|
||||
<a-button onClick={() => this.columnSettingVisible = true}>设置列</a-button>
|
||||
<a-menu slot="overlay" onClick={() => { return false }}>
|
||||
{
|
||||
this.columns.map(column => {
|
||||
return (
|
||||
<a-menu-item key={column.dataIndex || column.key}>
|
||||
<a-checkbox checked={column.hidden} onChange={() => { column.hidden = !column.hidden }}>{column.title}</a-checkbox>
|
||||
</a-menu-item>
|
||||
)
|
||||
})
|
||||
}
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
)
|
||||
},
|
||||
|
||||
onLoading() {
|
||||
this.loading = {
|
||||
indicator: <a-icon type="loading" spin />
|
||||
}
|
||||
},
|
||||
|
||||
onLoaded() {
|
||||
this.loading = false
|
||||
},
|
||||
|
||||
onLoadData() {
|
||||
this.onLoading()
|
||||
|
||||
this.loadData({
|
||||
pageNo: this.pagination.current,
|
||||
pageSize: this.pagination.pageSize,
|
||||
...this.sorter
|
||||
}).then((res) => {
|
||||
if (res.rows) {
|
||||
// 普通表格
|
||||
this.type = 'table'
|
||||
this.data = res.rows
|
||||
this.pagination.total = res.totalRows
|
||||
} else if (res) {
|
||||
// 树形表格
|
||||
this.type = 'tree'
|
||||
this.data = this.onClearChildren(res)
|
||||
this.pagination = false
|
||||
}
|
||||
}).finally(() => {
|
||||
this.onLoaded()
|
||||
})
|
||||
},
|
||||
|
||||
onReloadData(refresh = false) {
|
||||
if (refresh && refresh.constructor === Boolean && this.pagination.constructor === Object) {
|
||||
this.pagination.current = this.pageNo
|
||||
this.pagination.pageSize = this.pageSize
|
||||
}
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
onTableChange(pagination, filters, sorter) {
|
||||
this.pagination = pagination
|
||||
this.sorter = {
|
||||
sortField: sorter.field,
|
||||
sortOrder: sorter.order,
|
||||
}
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
/**
|
||||
* 清除没有子节点内容的子节点位置
|
||||
*/
|
||||
onClearChildren(data) {
|
||||
data.forEach(p => {
|
||||
if (p.children) {
|
||||
if (p.children.length) {
|
||||
p.children = this.onClearChildren(p.children)
|
||||
} else {
|
||||
delete p.children
|
||||
}
|
||||
}
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
onQuery() {
|
||||
this.$emit('query')
|
||||
},
|
||||
|
||||
onResetQuery() {
|
||||
this.$emit('resetQuery')
|
||||
this.$emit('reset-query')
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
const props = {
|
||||
loading: this.loading,
|
||||
pagination: this.pagination,
|
||||
dataSource: this.data,
|
||||
columns: this.columns.filter(p => !p.hidden),
|
||||
bordered: true,
|
||||
size: 'middle',
|
||||
rowKey: record => record.id || Math.random().toString(16).slice(2),
|
||||
scroll: { x: 'max-content' }
|
||||
}
|
||||
|
||||
const on = {
|
||||
change: this.onTableChange,
|
||||
...this.$listeners
|
||||
}
|
||||
|
||||
const queryOn = {
|
||||
'submit.native.prevent': () => { }
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<a-alert type="warning" closable>
|
||||
<template slot="message">
|
||||
字段固定应该遵循左侧固定到最左,右侧固定到最右(此逻辑难以实现)
|
||||
</template>
|
||||
</a-alert>
|
||||
<br />
|
||||
{
|
||||
this.$scopedSlots.query &&
|
||||
<div class="yo-query-bar">
|
||||
<a-form-model layout="inline" {...{ on: queryOn }}>
|
||||
{this.$scopedSlots.query()}
|
||||
<a-form-model-item>
|
||||
<a-button-group>
|
||||
<a-button onClick={this.onQuery} html-type="submit" type="primary">查询</a-button>
|
||||
<a-button onClick={this.onResetQuery}>重置</a-button>
|
||||
</a-button-group>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
}
|
||||
<div class="yo-action-bar">
|
||||
<div class="yo-action-bar--actions">
|
||||
{this.$scopedSlots.operator && this.$scopedSlots.operator()}
|
||||
</div>
|
||||
<div class="yo-action-bar--actions">
|
||||
<a-button-group>
|
||||
<a-button onClick={this.onReloadData}>刷新</a-button>
|
||||
{
|
||||
this.type === 'table' && <ColumnSetting {...{ props: { columns: this.columns } }} />
|
||||
}
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
<a-table class="yo-table" {...{ props, on, scopedSlots: { ...this.$scopedSlots } }}>
|
||||
{Object.keys(this.$slots).map((name) => (
|
||||
<template slot={name}>{this.$slots[name]}</template>
|
||||
))}
|
||||
</a-table>
|
||||
</section>
|
||||
)
|
||||
},
|
||||
// 列设置用jsx实现起来较为困难
|
||||
import ColumnSetting from './column'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
pageNo: {
|
||||
default: 1,
|
||||
type: Number,
|
||||
},
|
||||
pageSize: {
|
||||
default: 10,
|
||||
type: Number,
|
||||
},
|
||||
loadData: {
|
||||
type: Function,
|
||||
require: true,
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
require: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
|
||||
type: '',
|
||||
|
||||
data: [],
|
||||
|
||||
pagination: {
|
||||
current: this.pageNo,
|
||||
pageSize: this.pageSize,
|
||||
total: 0,
|
||||
size: 'small',
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `总共${total}条数据`
|
||||
},
|
||||
|
||||
sorter: {
|
||||
sortField: '',
|
||||
sortOrder: '',
|
||||
},
|
||||
|
||||
columnSettingVisible: false
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
renderColumnSetting() {
|
||||
|
||||
const props = {
|
||||
visible: this.columnSettingVisible,
|
||||
placement: 'bottomRight'
|
||||
}
|
||||
|
||||
const on = {
|
||||
visibleChange: (visible) => {
|
||||
this.columnSettingVisible = visible
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<a-dropdown {...{ props, on }}>
|
||||
<a-button onClick={() => this.columnSettingVisible = true}>设置列</a-button>
|
||||
<a-menu slot="overlay" onClick={() => { return false }}>
|
||||
{
|
||||
this.columns.map(column => {
|
||||
return (
|
||||
<a-menu-item key={column.dataIndex || column.key}>
|
||||
<a-checkbox checked={column.hidden} onChange={() => { column.hidden = !column.hidden }}>{column.title}</a-checkbox>
|
||||
</a-menu-item>
|
||||
)
|
||||
})
|
||||
}
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
)
|
||||
},
|
||||
|
||||
onLoading() {
|
||||
this.loading = {
|
||||
indicator: <a-icon type="loading" spin />
|
||||
}
|
||||
},
|
||||
|
||||
onLoaded() {
|
||||
this.loading = false
|
||||
},
|
||||
|
||||
onLoadData() {
|
||||
this.onLoading()
|
||||
|
||||
this.loadData({
|
||||
pageNo: this.pagination.current,
|
||||
pageSize: this.pagination.pageSize,
|
||||
...this.sorter
|
||||
}).then((res) => {
|
||||
if (res.rows) {
|
||||
// 普通表格
|
||||
this.type = 'table'
|
||||
this.data = res.rows
|
||||
this.pagination.total = res.totalRows
|
||||
} else if (res) {
|
||||
// 树形表格
|
||||
this.type = 'tree'
|
||||
this.data = this.onClearChildren(res)
|
||||
this.pagination = false
|
||||
}
|
||||
}).finally(() => {
|
||||
this.onLoaded()
|
||||
})
|
||||
},
|
||||
|
||||
onReloadData(refresh = false) {
|
||||
if (refresh && refresh.constructor === Boolean && this.pagination.constructor === Object) {
|
||||
this.pagination.current = this.pageNo
|
||||
this.pagination.pageSize = this.pageSize
|
||||
}
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
onTableChange(pagination, filters, sorter) {
|
||||
this.pagination = pagination
|
||||
this.sorter = {
|
||||
sortField: sorter.field,
|
||||
sortOrder: sorter.order,
|
||||
}
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
/**
|
||||
* 清除没有子节点内容的子节点位置
|
||||
*/
|
||||
onClearChildren(data) {
|
||||
data.forEach(p => {
|
||||
if (p.children) {
|
||||
if (p.children.length) {
|
||||
p.children = this.onClearChildren(p.children)
|
||||
} else {
|
||||
delete p.children
|
||||
}
|
||||
}
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
onQuery() {
|
||||
this.$emit('query')
|
||||
},
|
||||
|
||||
onResetQuery() {
|
||||
this.$emit('resetQuery')
|
||||
this.$emit('reset-query')
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
const props = {
|
||||
loading: this.loading,
|
||||
pagination: this.pagination,
|
||||
dataSource: this.data,
|
||||
columns: this.columns.filter(p => !p.hidden),
|
||||
bordered: true,
|
||||
size: 'middle',
|
||||
rowKey: record => record.id || Math.random().toString(16).slice(2),
|
||||
scroll: { x: 'max-content' }
|
||||
}
|
||||
|
||||
const on = {
|
||||
change: this.onTableChange,
|
||||
...this.$listeners
|
||||
}
|
||||
|
||||
const queryOn = {
|
||||
'submit.native.prevent': () => { }
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<a-alert type="warning" closable>
|
||||
<template slot="message">
|
||||
字段固定应该遵循左侧固定到最左,右侧固定到最右(此逻辑难以实现)
|
||||
</template>
|
||||
</a-alert>
|
||||
<br />
|
||||
{
|
||||
this.$scopedSlots.query &&
|
||||
<div class="yo-query-bar">
|
||||
<a-form-model layout="inline" {...{ on: queryOn }}>
|
||||
{this.$scopedSlots.query()}
|
||||
<a-form-model-item>
|
||||
<a-button-group>
|
||||
<a-button onClick={this.onQuery} html-type="submit" type="primary">查询</a-button>
|
||||
<a-button onClick={this.onResetQuery}>重置</a-button>
|
||||
</a-button-group>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
}
|
||||
<div class="yo-action-bar">
|
||||
<div class="yo-action-bar--actions">
|
||||
{this.$scopedSlots.operator && this.$scopedSlots.operator()}
|
||||
</div>
|
||||
<div class="yo-action-bar--actions">
|
||||
<a-button-group>
|
||||
<a-button onClick={this.onReloadData}>刷新</a-button>
|
||||
{
|
||||
this.type === 'table' && <ColumnSetting {...{ props: { columns: this.columns } }} />
|
||||
}
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
<a-table class="yo-table" {...{ props, on, scopedSlots: { ...this.$scopedSlots } }}>
|
||||
{Object.keys(this.$slots).map((name) => (
|
||||
<template slot={name}>{this.$slots[name]}</template>
|
||||
))}
|
||||
</a-table>
|
||||
</section>
|
||||
)
|
||||
},
|
||||
}
|
||||
@@ -1,23 +1,23 @@
|
||||
export default {
|
||||
render() {
|
||||
|
||||
const components = []
|
||||
|
||||
const slots = this.$slots.default.filter(p => p.tag)
|
||||
|
||||
slots.forEach((p, i) => {
|
||||
components.push(p)
|
||||
if (i < slots.length - 1) {
|
||||
components.push(<a-divider type="vertical" />)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<div class="yo-table-actions">
|
||||
<div class="yo-table-actions--inner">
|
||||
{components}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default {
|
||||
render() {
|
||||
|
||||
const components = []
|
||||
|
||||
const slots = this.$slots.default.filter(p => p.tag)
|
||||
|
||||
slots.forEach((p, i) => {
|
||||
components.push(p)
|
||||
if (i < slots.length - 1) {
|
||||
components.push(<a-divider type="vertical" />)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<div class="yo-table-actions">
|
||||
<div class="yo-table-actions--inner">
|
||||
{components}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,303 +1,303 @@
|
||||
import Swiper from 'swiper'
|
||||
|
||||
let timer, swiper
|
||||
|
||||
export default {
|
||||
props: {
|
||||
loadData: {
|
||||
type: Function,
|
||||
require: true,
|
||||
},
|
||||
|
||||
defaultExpandedKeys: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
|
||||
replaceFields: {
|
||||
default() {
|
||||
return {
|
||||
value: 'id',
|
||||
title: 'title',
|
||||
children: 'children'
|
||||
}
|
||||
},
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
|
||||
data: [],
|
||||
list: [],
|
||||
|
||||
searchValue: '',
|
||||
|
||||
selectedKeys: [],
|
||||
expandedKeys: [],
|
||||
autoExpandParent: true
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const container = this.$refs.swiper,
|
||||
scrollBar = container.querySelector('.swiper-scrollbar')
|
||||
|
||||
const swiperOptions = {
|
||||
direction: 'vertical',
|
||||
slidesPerView: 'auto',
|
||||
freeMode: true,
|
||||
scrollbar: {
|
||||
el: scrollBar,
|
||||
},
|
||||
mousewheel: true,
|
||||
}
|
||||
|
||||
swiper = new Swiper(container, swiperOptions)
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
this.onUpdateSwiper()
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
renderBreadcrumbItem() {
|
||||
|
||||
const path = ['顶级']
|
||||
|
||||
const findPath = (data, level) => {
|
||||
level = level || 1
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const item = data[i]
|
||||
|
||||
path[level] = item[this.replaceFields.title]
|
||||
|
||||
if (item[this.replaceFields.value] === this.selectedKeys[0]) {
|
||||
path.length = level + 1
|
||||
return true
|
||||
}
|
||||
|
||||
if (item[this.replaceFields.children] && item[this.replaceFields.children].length) {
|
||||
const found = findPath(item[this.replaceFields.children], level + 1)
|
||||
if (found) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.selectedKeys.length) {
|
||||
findPath(this.data)
|
||||
}
|
||||
|
||||
return path.map(p => (
|
||||
<a-breadcrumb-item>{p}</a-breadcrumb-item>
|
||||
))
|
||||
},
|
||||
|
||||
onLoadData() {
|
||||
this.loading = true
|
||||
|
||||
this.loadData().then((res) => {
|
||||
const data = this.generateKey(res)
|
||||
this.list = []
|
||||
this.generateList(data)
|
||||
if (this.defaultExpandedKeys) {
|
||||
this.expandedKeys = this.list.map(p => p.key)
|
||||
}
|
||||
this.data = data
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.onUpdateSwiper()
|
||||
})
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
onReloadData() {
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
onExpand(expandedKeys) {
|
||||
this.expandedKeys = expandedKeys
|
||||
this.autoExpandParent = false
|
||||
this.onUpdateSwiper()
|
||||
},
|
||||
|
||||
onUnexpandAll() {
|
||||
this.expandedKeys = []
|
||||
},
|
||||
|
||||
onSearch(value) {
|
||||
const expandedKeys = this.list
|
||||
.map(p => {
|
||||
if (p[this.replaceFields.title].indexOf(value) > -1) {
|
||||
return this.getParentKey(p.key, this.data)
|
||||
}
|
||||
return null
|
||||
})
|
||||
.filter((p, i, self) => p && self.indexOf(p) === i)
|
||||
|
||||
this.searchValue = value
|
||||
this.expandedKeys = expandedKeys
|
||||
this.autoExpandParent = true
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.onUpdateSwiper()
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
onSelect(selectedKeys) {
|
||||
const selectedIds = []
|
||||
selectedKeys.forEach(p => {
|
||||
const data = this.list.find(m => m.key === p)
|
||||
selectedIds.push(data[this.replaceFields.value])
|
||||
})
|
||||
this.selectedKeys = selectedIds
|
||||
this.$emit('select', selectedIds)
|
||||
},
|
||||
|
||||
onUpdateSwiper() {
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
swiper.update()
|
||||
swiper.update()
|
||||
}, 300)
|
||||
},
|
||||
|
||||
generateKey(data, level) {
|
||||
const n = level || [0]
|
||||
n.push(0)
|
||||
data.forEach((p, i) => {
|
||||
n[n.length - 1] = i
|
||||
p.key = n.join('-')
|
||||
p.scopedSlots = { title: 'title' }
|
||||
if (p[this.replaceFields.children]) {
|
||||
this.generateKey(p[this.replaceFields.children], Object.assign([], n))
|
||||
}
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
generateList(data) {
|
||||
// 这里获取不到Key
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const { key } = data[i]
|
||||
this.list.push({
|
||||
key,
|
||||
[this.replaceFields.value]: data[i][this.replaceFields.value],
|
||||
[this.replaceFields.title]: data[i][this.replaceFields.title]
|
||||
})
|
||||
if (data[i][this.replaceFields.children]) {
|
||||
this.generateList(data[i][this.replaceFields.children])
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getParentKey(key, tree) {
|
||||
let parentKey;
|
||||
for (let i = 0; i < tree.length; i++) {
|
||||
const node = tree[i]
|
||||
if (node[this.replaceFields.children]) {
|
||||
if (node[this.replaceFields.children].some(item => item.key === key)) {
|
||||
parentKey = node.key
|
||||
} else if (this.getParentKey(key, node[this.replaceFields.children])) {
|
||||
parentKey = this.getParentKey(key, node[this.replaceFields.children])
|
||||
}
|
||||
}
|
||||
}
|
||||
return parentKey;
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
|
||||
const props = {
|
||||
treeData: this.data,
|
||||
expandedKeys: this.expandedKeys,
|
||||
autoExpandParent: this.autoExpandParent,
|
||||
}
|
||||
|
||||
const on = {
|
||||
expand: this.onExpand,
|
||||
select: this.onSelect
|
||||
}
|
||||
|
||||
const scopedSlots = {
|
||||
title: (props) => {
|
||||
const title = props[this.replaceFields.title]
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
title.indexOf(this.searchValue) > -1 ?
|
||||
<span>
|
||||
{title.substr(0, title.indexOf(this.searchValue))}
|
||||
<span style="color: #f50">{this.searchValue}</span>
|
||||
{title.substr(title.indexOf(this.searchValue) + this.searchValue.length)}
|
||||
</span>
|
||||
:
|
||||
<span>{title}</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<a-layout class="yo-tree-layout">
|
||||
<a-layout-sider width="240px">
|
||||
<a-layout-header>
|
||||
<div class="header-actions">
|
||||
<a-input-search allowClear={true} placeholder="请输入检索关键字" onSearch={this.onSearch} />
|
||||
</div>
|
||||
</a-layout-header>
|
||||
<div class="yo-tree-layout--bar">
|
||||
<a-tooltip placement="bottom" title="折叠全部">
|
||||
<a-icon type="switcher" onClick={this.onUnexpandAll} />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<div class="swiper-container" ref="swiper">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide">
|
||||
<a-spin style={{ height: '100%' }} spinning={this.loading}>
|
||||
<a-icon slot="indicator" type="loading" spin />
|
||||
{
|
||||
!this.loading && !this.list.length ?
|
||||
<a-empty description={false} class="ant-list-empty-text">
|
||||
<template slot="image">
|
||||
<a-icon class="h3 mt-xl mb-md" type="smile" />
|
||||
<p>暂无数据</p>
|
||||
</template>
|
||||
</a-empty>
|
||||
:
|
||||
<a-tree {...{ props, on, scopedSlots }} />
|
||||
}
|
||||
</a-spin>
|
||||
</div>
|
||||
</div>
|
||||
<div class="swiper-scrollbar" />
|
||||
</div>
|
||||
</a-layout-sider>
|
||||
<a-layout-content>
|
||||
<container>
|
||||
<a-breadcrumb class="mt-md mb-md">
|
||||
{this.renderBreadcrumbItem()}
|
||||
</a-breadcrumb>
|
||||
</container>
|
||||
{this.$scopedSlots.default ? this.$scopedSlots.default() : null}
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
)
|
||||
}
|
||||
import Swiper from 'swiper'
|
||||
|
||||
let timer, swiper
|
||||
|
||||
export default {
|
||||
props: {
|
||||
loadData: {
|
||||
type: Function,
|
||||
require: true,
|
||||
},
|
||||
|
||||
defaultExpandedKeys: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
|
||||
replaceFields: {
|
||||
default() {
|
||||
return {
|
||||
value: 'id',
|
||||
title: 'title',
|
||||
children: 'children'
|
||||
}
|
||||
},
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
|
||||
data: [],
|
||||
list: [],
|
||||
|
||||
searchValue: '',
|
||||
|
||||
selectedKeys: [],
|
||||
expandedKeys: [],
|
||||
autoExpandParent: true
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const container = this.$refs.swiper,
|
||||
scrollBar = container.querySelector('.swiper-scrollbar')
|
||||
|
||||
const swiperOptions = {
|
||||
direction: 'vertical',
|
||||
slidesPerView: 'auto',
|
||||
freeMode: true,
|
||||
scrollbar: {
|
||||
el: scrollBar,
|
||||
},
|
||||
mousewheel: true,
|
||||
}
|
||||
|
||||
swiper = new Swiper(container, swiperOptions)
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
this.onUpdateSwiper()
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
renderBreadcrumbItem() {
|
||||
|
||||
const path = ['顶级']
|
||||
|
||||
const findPath = (data, level) => {
|
||||
level = level || 1
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const item = data[i]
|
||||
|
||||
path[level] = item[this.replaceFields.title]
|
||||
|
||||
if (item[this.replaceFields.value] === this.selectedKeys[0]) {
|
||||
path.length = level + 1
|
||||
return true
|
||||
}
|
||||
|
||||
if (item[this.replaceFields.children] && item[this.replaceFields.children].length) {
|
||||
const found = findPath(item[this.replaceFields.children], level + 1)
|
||||
if (found) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.selectedKeys.length) {
|
||||
findPath(this.data)
|
||||
}
|
||||
|
||||
return path.map(p => (
|
||||
<a-breadcrumb-item>{p}</a-breadcrumb-item>
|
||||
))
|
||||
},
|
||||
|
||||
onLoadData() {
|
||||
this.loading = true
|
||||
|
||||
this.loadData().then((res) => {
|
||||
const data = this.generateKey(res)
|
||||
this.list = []
|
||||
this.generateList(data)
|
||||
if (this.defaultExpandedKeys) {
|
||||
this.expandedKeys = this.list.map(p => p.key)
|
||||
}
|
||||
this.data = data
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.onUpdateSwiper()
|
||||
})
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
onReloadData() {
|
||||
this.onLoadData()
|
||||
},
|
||||
|
||||
onExpand(expandedKeys) {
|
||||
this.expandedKeys = expandedKeys
|
||||
this.autoExpandParent = false
|
||||
this.onUpdateSwiper()
|
||||
},
|
||||
|
||||
onUnexpandAll() {
|
||||
this.expandedKeys = []
|
||||
},
|
||||
|
||||
onSearch(value) {
|
||||
const expandedKeys = this.list
|
||||
.map(p => {
|
||||
if (p[this.replaceFields.title].indexOf(value) > -1) {
|
||||
return this.getParentKey(p.key, this.data)
|
||||
}
|
||||
return null
|
||||
})
|
||||
.filter((p, i, self) => p && self.indexOf(p) === i)
|
||||
|
||||
this.searchValue = value
|
||||
this.expandedKeys = expandedKeys
|
||||
this.autoExpandParent = true
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.onUpdateSwiper()
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
onSelect(selectedKeys) {
|
||||
const selectedIds = []
|
||||
selectedKeys.forEach(p => {
|
||||
const data = this.list.find(m => m.key === p)
|
||||
selectedIds.push(data[this.replaceFields.value])
|
||||
})
|
||||
this.selectedKeys = selectedIds
|
||||
this.$emit('select', selectedIds)
|
||||
},
|
||||
|
||||
onUpdateSwiper() {
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
swiper.update()
|
||||
swiper.update()
|
||||
}, 300)
|
||||
},
|
||||
|
||||
generateKey(data, level) {
|
||||
const n = level || [0]
|
||||
n.push(0)
|
||||
data.forEach((p, i) => {
|
||||
n[n.length - 1] = i
|
||||
p.key = n.join('-')
|
||||
p.scopedSlots = { title: 'title' }
|
||||
if (p[this.replaceFields.children]) {
|
||||
this.generateKey(p[this.replaceFields.children], Object.assign([], n))
|
||||
}
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
generateList(data) {
|
||||
// 这里获取不到Key
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const { key } = data[i]
|
||||
this.list.push({
|
||||
key,
|
||||
[this.replaceFields.value]: data[i][this.replaceFields.value],
|
||||
[this.replaceFields.title]: data[i][this.replaceFields.title]
|
||||
})
|
||||
if (data[i][this.replaceFields.children]) {
|
||||
this.generateList(data[i][this.replaceFields.children])
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getParentKey(key, tree) {
|
||||
let parentKey;
|
||||
for (let i = 0; i < tree.length; i++) {
|
||||
const node = tree[i]
|
||||
if (node[this.replaceFields.children]) {
|
||||
if (node[this.replaceFields.children].some(item => item.key === key)) {
|
||||
parentKey = node.key
|
||||
} else if (this.getParentKey(key, node[this.replaceFields.children])) {
|
||||
parentKey = this.getParentKey(key, node[this.replaceFields.children])
|
||||
}
|
||||
}
|
||||
}
|
||||
return parentKey;
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
|
||||
const props = {
|
||||
treeData: this.data,
|
||||
expandedKeys: this.expandedKeys,
|
||||
autoExpandParent: this.autoExpandParent,
|
||||
}
|
||||
|
||||
const on = {
|
||||
expand: this.onExpand,
|
||||
select: this.onSelect
|
||||
}
|
||||
|
||||
const scopedSlots = {
|
||||
title: (props) => {
|
||||
const title = props[this.replaceFields.title]
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
title.indexOf(this.searchValue) > -1 ?
|
||||
<span>
|
||||
{title.substr(0, title.indexOf(this.searchValue))}
|
||||
<span style="color: #f50">{this.searchValue}</span>
|
||||
{title.substr(title.indexOf(this.searchValue) + this.searchValue.length)}
|
||||
</span>
|
||||
:
|
||||
<span>{title}</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<a-layout class="yo-tree-layout">
|
||||
<a-layout-sider width="240px">
|
||||
<a-layout-header>
|
||||
<div class="header-actions">
|
||||
<a-input-search allowClear={true} placeholder="请输入检索关键字" onSearch={this.onSearch} />
|
||||
</div>
|
||||
</a-layout-header>
|
||||
<div class="yo-tree-layout--bar">
|
||||
<a-tooltip placement="bottom" title="折叠全部">
|
||||
<a-icon type="switcher" onClick={this.onUnexpandAll} />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<div class="swiper-container" ref="swiper">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide">
|
||||
<a-spin style={{ height: '100%' }} spinning={this.loading}>
|
||||
<a-icon slot="indicator" type="loading" spin />
|
||||
{
|
||||
!this.loading && !this.list.length ?
|
||||
<a-empty description={false} class="ant-list-empty-text">
|
||||
<template slot="image">
|
||||
<a-icon class="h3 mt-xl mb-md" type="smile" />
|
||||
<p>暂无数据</p>
|
||||
</template>
|
||||
</a-empty>
|
||||
:
|
||||
<a-tree {...{ props, on, scopedSlots }} />
|
||||
}
|
||||
</a-spin>
|
||||
</div>
|
||||
</div>
|
||||
<div class="swiper-scrollbar" />
|
||||
</div>
|
||||
</a-layout-sider>
|
||||
<a-layout-content>
|
||||
<container>
|
||||
<a-breadcrumb class="mt-md mb-md">
|
||||
{this.renderBreadcrumbItem()}
|
||||
</a-breadcrumb>
|
||||
</container>
|
||||
{this.$scopedSlots.default ? this.$scopedSlots.default() : null}
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user