|
|
@@ -2,10 +2,10 @@
|
|
|
* 权限管理
|
|
|
*/
|
|
|
import React from 'react'
|
|
|
-import { Tabs, Layout, Input, Menu, Table, Checkbox, message } from 'antd'
|
|
|
+import { Tabs, Layout, Row, Col, Input, Menu, Table, Checkbox, message, Button, Icon } from 'antd'
|
|
|
import { connect } from 'dva'
|
|
|
import './index.less'
|
|
|
-const { Sider, Content } = Layout
|
|
|
+const { Sider, Header, Content } = Layout
|
|
|
const { Search } = Input
|
|
|
const { TabPane } = Tabs
|
|
|
|
|
|
@@ -20,19 +20,27 @@ class Authority extends React.Component {
|
|
|
|
|
|
checkIndeterminate = (treeList) => {
|
|
|
const { authority } = this.props;
|
|
|
- const { dashboardList } = authority;
|
|
|
+ const { dashboardList, dashboardFilterLabel } = authority;
|
|
|
let arr = treeList && treeList.length > 0 ? [ ...treeList ] : null;
|
|
|
- for(let i = 0;arr && i < arr.length; i++) {
|
|
|
+ for(let i = (arr ? (arr.length - 1) : 0); arr && i >= 0; i--) {
|
|
|
let l = arr[i];
|
|
|
if(l.type === 'menu') {
|
|
|
l.children = this.checkIndeterminate(l.children);
|
|
|
let checkedCount = l.children ? l.children.filter(c => c.type === 'dashboard').map(c => c.checked).filter(c => !!c).length : 0;
|
|
|
l.indeterminate = l.children ? (checkedCount > 0 && checkedCount < l.children.filter(c => c.type === 'dashboard').length) : false;
|
|
|
l.checked = l.children ? checkedCount !== 0 && checkedCount === l.children.filter(c => c.type === 'dashboard').length : false;
|
|
|
+
|
|
|
+ if((!l.children || l.children.length === 0) && !!dashboardFilterLabel && l.name.toLowerCase().indexOf(dashboardFilterLabel.toLowerCase()) === -1) {
|
|
|
+ arr.splice(i, 1);
|
|
|
+ }
|
|
|
}else {
|
|
|
l.children = null;
|
|
|
l.indeterminate = false;
|
|
|
l.checked = dashboardList.findIndex(d => d === l.code) > -1;
|
|
|
+
|
|
|
+ if(!!dashboardFilterLabel && l.name.toLowerCase().indexOf(dashboardFilterLabel.toLowerCase()) === -1) {
|
|
|
+ arr.splice(i, 1);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
return arr;
|
|
|
@@ -49,8 +57,9 @@ class Authority extends React.Component {
|
|
|
|
|
|
render() {
|
|
|
const { dashboard, authority, userGroup, user, dispatch } = this.props;
|
|
|
- const { menuSelectedKeys, tabActiveKey, groupFilterLabel, userFilterLabel, groupLimit, userLimit } = authority;
|
|
|
- const dashboardTreeList = this.checkIndeterminate(dashboard.menuTree);
|
|
|
+ const { menuSelectedKeys, tabActiveKey, groupFilterLabel, userFilterLabel, dashboardFilterLabel, groupLimit, userLimit } = authority;
|
|
|
+
|
|
|
+ const dashboardTreeList = this.checkIndeterminate(JSON.parse(JSON.stringify(dashboard.menuTree)));
|
|
|
return <Layout className='layout-authority'>
|
|
|
<Sider>
|
|
|
<Tabs
|
|
|
@@ -126,7 +135,30 @@ class Authority extends React.Component {
|
|
|
</Tabs>
|
|
|
</Sider>
|
|
|
<Content>
|
|
|
- <DashBoardTree dataSource={dashboardTreeList} onRowCheckChange={(record, checked) => {
|
|
|
+ <Header>
|
|
|
+ <Row className='search-bar' type='flex' justify='end'>
|
|
|
+ <Col className='search'>
|
|
|
+ <Button className='btn-refresh' onClick={() => {
|
|
|
+ dispatch({ type: 'userGroup/fetchList', mandatory: true });
|
|
|
+ dispatch({ type: 'user/fetchList', mandatory: true });
|
|
|
+ dispatch({ type: 'dashboard/remoteMenuTree', mandatory: true });
|
|
|
+ }}>
|
|
|
+ <Icon type='sync'/>
|
|
|
+ </Button>
|
|
|
+ <Search
|
|
|
+ placehodler='请输入关键字'
|
|
|
+ value={dashboardFilterLabel}
|
|
|
+ onChange={e => {
|
|
|
+ let value = e.target.value;
|
|
|
+ dispatch({ type: 'authority/setFields', fields: [
|
|
|
+ { name: 'dashboardFilterLabel', value },
|
|
|
+ ] })
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ </Header>
|
|
|
+ <DashBoardTree filterLabel={dashboardFilterLabel} dataSource={dashboardTreeList} onRowCheckChange={(record, checked) => {
|
|
|
if(!!menuSelectedKeys[0]) {
|
|
|
if(record.type === 'menu') {
|
|
|
let dashboardCodes = record.children.filter(c => c.type === 'dashboard').map(c => c.code)
|
|
|
@@ -217,7 +249,8 @@ class DashBoardTree extends React.Component {
|
|
|
super(props);
|
|
|
this.state = {
|
|
|
tableScrollHeight: 0,
|
|
|
- pageSize: 0,
|
|
|
+ allExpanded: false,
|
|
|
+ expandedRowKeys: [],
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -235,24 +268,70 @@ class DashBoardTree extends React.Component {
|
|
|
const content = tableWrapper.getElementsByClassName('ant-spin-nested-loading')[0];
|
|
|
const tableHeader = content.querySelector('thead');
|
|
|
const padding = content.getBoundingClientRect().top - tableWrapper.getBoundingClientRect().top;
|
|
|
- // 容器高度 - padding * 2 - 分页器高度 - 表头高度
|
|
|
- let tableScrollHeight = tableWrapper.offsetHeight - padding * 2 - 42 - tableHeader.offsetHeight;
|
|
|
+ // 容器高度 - padding * 2 - 表头高度 - 边框线
|
|
|
+ let tableScrollHeight = tableWrapper.offsetHeight - padding * 2 - tableHeader.offsetHeight - 2;
|
|
|
this.setState({
|
|
|
tableScrollHeight,
|
|
|
- pageSize: Math.ceil((tableScrollHeight) / 38)
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- render() {
|
|
|
- const { dataSource, onRowCheckChange } = this.props;
|
|
|
- const { tableScrollHeight, pageSize } = this.state;
|
|
|
+ onExpandedRowsChange = (expandedRowKeys) => {
|
|
|
+ this.setState({
|
|
|
+ expandedRowKeys
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ onExpandAll = () => {
|
|
|
+ const { dataSource } = this.props;
|
|
|
+ let expandedRowKeys = this.getAllKeys(dataSource);
|
|
|
+ this.setState({
|
|
|
+ allExpanded: true,
|
|
|
+ expandedRowKeys
|
|
|
+ });
|
|
|
+ }
|
|
|
|
|
|
+ collapseAll = () => {
|
|
|
+ this.setState({
|
|
|
+ allExpanded: false,
|
|
|
+ expandedRowKeys: []
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ getAllKeys = (list) => {
|
|
|
+ let keyArr = [];
|
|
|
+ for(let i = 0;!!list && i < list.length; i++) {
|
|
|
+ if(!!list[i].children) {
|
|
|
+ keyArr.push(list[i].key);
|
|
|
+ keyArr = keyArr.concat(this.getAllKeys(list[i].children, keyArr));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return keyArr
|
|
|
+ }
|
|
|
+
|
|
|
+ render() {
|
|
|
+ const { dataSource, onRowCheckChange, filterLabel } = this.props;
|
|
|
+ const { tableScrollHeight, expandedRowKeys, allExpanded } = this.state;
|
|
|
+ const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
|
|
|
const columns = [{
|
|
|
- title: '报表目录',
|
|
|
+ title: <span><Icon type='menu' title='展开/折叠全部' style={{ marginRight: '4px' }} onClick={allExpanded ? this.collapseAll : this.onExpandAll}/>报表目录</span>,
|
|
|
dataIndex: 'name',
|
|
|
key: 'name',
|
|
|
width: '80%',
|
|
|
- render: (text, record, index) => <span style={{ fontWeight: record.type === 'dashboard' ? 'bold' : 'normal' }}>{text}</span>
|
|
|
+ render: (text, record) => {
|
|
|
+ return <span style={{ fontWeight: record.type === 'dashboard' ? 'bold' : 'normal' }}>
|
|
|
+ {
|
|
|
+ filterLabel ?
|
|
|
+ ((text || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
|
|
|
+ return (
|
|
|
+ fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
|
|
|
+ <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
|
|
|
+ fragment
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )) : text
|
|
|
+ }
|
|
|
+ </span>
|
|
|
+ }
|
|
|
}, {
|
|
|
title: '查看',
|
|
|
dataIndex: 'view',
|
|
|
@@ -267,10 +346,10 @@ class DashBoardTree extends React.Component {
|
|
|
}];
|
|
|
|
|
|
return <Table columns={columns} dataSource={dataSource} scroll={{x: false, y: tableScrollHeight}}
|
|
|
- size='small'
|
|
|
- pagination={{
|
|
|
- pageSize: pageSize
|
|
|
- }}
|
|
|
+ size='small'
|
|
|
+ pagination={false}
|
|
|
+ expandedRowKeys={expandedRowKeys}
|
|
|
+ onExpandedRowsChange={this.onExpandedRowsChange}
|
|
|
/>
|
|
|
}
|
|
|
}
|