260 lines
8.1 KiB
JavaScript
260 lines
8.1 KiB
JavaScript
import React, { Component } from 'react'
|
|
import { Card, Checkbox, Descriptions, Empty, Popover, Spin, Tooltip } from 'antd'
|
|
import { AntIcon } from 'components'
|
|
import { EMPTY_ID } from 'util/global'
|
|
|
|
function generateList(data) {
|
|
data.forEach(item => {
|
|
if (item.children && item.children.length) {
|
|
generateList.call(this, item.children)
|
|
}
|
|
this.list.push(item)
|
|
})
|
|
}
|
|
|
|
function getVisible() {
|
|
const checked = this.list.filter(item => item.checked)
|
|
const caseChildren = checked.filter(item => item.visibleParent || item.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(item => item.id)
|
|
const visibleParentsIds = visibleParents.map(item => item.id)
|
|
|
|
const result = checkedIds
|
|
visibleParentsIds.forEach(item => {
|
|
if (!result.includes(item)) {
|
|
result.push(item)
|
|
}
|
|
})
|
|
|
|
return result
|
|
}
|
|
|
|
function renderDescriptions(data) {
|
|
return data.map(item => {
|
|
return item.children && item.children.length
|
|
? renderItem.call(this, item)
|
|
: renderCheckbox.call(this, item)
|
|
})
|
|
}
|
|
|
|
function renderItem(data) {
|
|
return (
|
|
<Descriptions bordered column={1} contentStyle={{ padding: 0 }}>
|
|
<Descriptions.Item
|
|
label={
|
|
<Checkbox
|
|
value={data.id}
|
|
checked={data.checked}
|
|
indeterminate={data.indeterminate}
|
|
onChange={e => this.onChange(e, data)}
|
|
>
|
|
{data.title}
|
|
</Checkbox>
|
|
}
|
|
>
|
|
<Card bordered={false}>{renderDescriptions.call(this, data.children)}</Card>
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
)
|
|
}
|
|
|
|
function renderCheckbox(data) {
|
|
return (
|
|
<label className="ant-card-grid ant-card-grid-hoverable">
|
|
<Popover
|
|
placement="topLeft"
|
|
content={data.remark || <span className="text-normal">没有说明</span>}
|
|
>
|
|
<Checkbox
|
|
value={data.id}
|
|
checked={data.checked}
|
|
onChange={e => this.onChange(e, data)}
|
|
>
|
|
{data.title}
|
|
</Checkbox>
|
|
{data.visibleParent && data.type == 2 && (
|
|
<Tooltip placement="bottom" title="选中此项才会显示菜单">
|
|
<AntIcon type="eye" style={{ color: '#1890ff' }} className="mr-xxs" />
|
|
</Tooltip>
|
|
)}
|
|
<div className="text-gray">{data.permission}</div>
|
|
</Popover>
|
|
</label>
|
|
)
|
|
}
|
|
|
|
export default class AuthorityView extends Component {
|
|
state = {
|
|
loading: false,
|
|
dataSource: [],
|
|
}
|
|
|
|
list = []
|
|
|
|
constructor(props) {
|
|
super(props)
|
|
|
|
this.autoLoad = typeof this.props.autoLoad === 'boolean' ? this.props.autoLoad : true
|
|
this.loadData =
|
|
typeof this.props.loadData === 'function' ? this.props.loadData : async () => {}
|
|
}
|
|
|
|
/**
|
|
* 自动加载数据
|
|
*/
|
|
componentDidMount() {
|
|
if (this.autoLoad) {
|
|
this.onLoadData()
|
|
}
|
|
}
|
|
|
|
onLoadData = async () => {
|
|
this.setState({ loading: true })
|
|
|
|
const res = await this.loadData()
|
|
|
|
this.list = []
|
|
generateList.call(this, res)
|
|
|
|
if (this.props.defaultSelectedKeys) {
|
|
this.list.map(item => {
|
|
if (
|
|
this.props.defaultSelectedKeys.includes(item.id) &&
|
|
(!item.children || !item.children.length)
|
|
) {
|
|
this.onSelect(true, item)
|
|
}
|
|
})
|
|
}
|
|
|
|
this.setState({
|
|
dataSource: res,
|
|
loading: false,
|
|
})
|
|
|
|
this.onChange()
|
|
}
|
|
|
|
onReloadData = () => {
|
|
this.onLoadData()
|
|
}
|
|
|
|
onChange = (e, item) => {
|
|
if (e && item) {
|
|
this.onSelect(e.target.checked, item)
|
|
}
|
|
|
|
const visible = getVisible.call(this)
|
|
|
|
if (this.props.onSelect) {
|
|
this.props.onSelect(
|
|
// 返回所有选中
|
|
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)
|
|
}
|
|
|
|
this.setState({
|
|
dataSource: this.list.filter(p => p.parentId === EMPTY_ID),
|
|
})
|
|
}
|
|
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<div className="yo-authority-view">
|
|
<Spin spinning={this.state.loading} indicator={<AntIcon type="loading" />}>
|
|
{!this.state.loading ? (
|
|
<Descriptions bordered column={1} className="yo-authority-view--container">
|
|
{this.state.dataSource.map(item => {
|
|
return (
|
|
<Descriptions.Item
|
|
label={
|
|
<Checkbox
|
|
value={item.id}
|
|
checked={item.checked}
|
|
indeterminate={item.indeterminate}
|
|
onChange={e => this.onChange(e, item)}
|
|
>
|
|
{item.title}
|
|
</Checkbox>
|
|
}
|
|
>
|
|
{renderDescriptions.call(this, item.children)}
|
|
</Descriptions.Item>
|
|
)
|
|
})}
|
|
</Descriptions>
|
|
) : (
|
|
<Empty className="mt-lg mb-lg" />
|
|
)}
|
|
</Spin>
|
|
</div>
|
|
)
|
|
}
|
|
}
|